New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for .NET Standard 2.0 #7

Merged
merged 2 commits into from Feb 4, 2019

Conversation

Projects
None yet
2 participants
@Daniel15
Copy link
Member

Daniel15 commented Feb 3, 2019

This is the same as #6 except it is based off the correct branch


This adds support for .NET Standard 2.0 / .NET Core 2.2. I have already published the updated version to NuGet: https://www.nuget.org/packages/gpgme-sharp/2.0.0

The trickiest part of this was the handling of the library file name. The file name differs on Windows (libgpgme-11.dll) vs on Linux (libgpgme.so.11). Mono has a feature called "dllmap" which makes this remapping quite easy to perform:

<dllmap dll="libgpgme-11.dll" target="libgpgme.so.11" />

However, this same functionality is not available in .NET Core. Work is currently underway to have some sort of native library loader functionality that would support this (see dotnet/corefx#32015), but as of now, it's not available.

This means I had to hack around it. My initial approach was going to be to have two classes (one for Windows, one for Linux) that implement a common interface:

interface INativeMethods {
    IntPtr gpgme_check_version(IntPtr req_version);
}

class LinuxNativeMethods : INativeMethods {
    [DllImport("libgpgme.so.11", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    internal extern IntPtr gpgme_check_version([In] IntPtr req_version);
}

class WindowsNativeMethods : INativeMethods {
    [DllImport("libgpgme-11.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    internal extern IntPtr gpgme_check_version([In] IntPtr req_version);
}

However, DllImport methods must be static, and C# doesn't allow static methods on an interface.

Because of this, my approach ended up being quite hacky: I have one class with the Linux methods, one class with the Windows methods, and a wrapper class that has properties for each of them (see NativeMethodsWrapper.cs).

There was another issue: I wanted to avoid copying-and-pasting the P/Invoke code, however .NET doesn't let you have the same file twice in the same assembly, with two different sets of preprocessor values. So, the Windows and Linux classes needed to be in two separate assemblies.

I updated the build to use ILRepack to merge all the assemblies together, so users shouldn't actually notice any of this hackiness. Ideally this will all be cleaned up once dotnet/corefx#32015 is completed.

Daniel15 added some commits Jan 31, 2019

Add support for .NET Standard 2.0 (#1)
This adds support for .NET Standard 2.0 / .NET Core 2.2.

The trickiest part of this was the handling of the library file name. The file name differs on Windows (`libgpgme-11.dll`) vs on Linux (`libgpgme.so.11`). Mono has a feature called "dllmap" which makes this remapping quite easy to perform:
```
<dllmap dll="libgpgme-11.dll" target="libgpgme.so.11" />
```

However, this same functionality is not available in .NET Core. Work is currently underway to have some sort of native library loader functionality that would support this (see dotnet/corefx#32015), but as of now, it's not available.

This means I had to hack around it. My initial approach was going to be to have two classes (one for Windows, one for Linux) that implement a common interface:
```
interface INativeMethods {
    IntPtr gpgme_check_version(IntPtr req_version);
}

class LinuxNativeMethods : INativeMethods {
    [DllImport("libgpgme.so.11", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    internal extern IntPtr gpgme_check_version([In] IntPtr req_version);
}

class WindowsNativeMethods : INativeMethods {
    [DllImport("libgpgme-11.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    internal extern IntPtr gpgme_check_version([In] IntPtr req_version);
}
```

However, `DllImport` methods **must** be static, and C# doesn't allow static methods on an interface.

Because of this, my approach ended up being quite hacky: I have one class with the Linux methods, one class with the Windows methods, and a wrapper class that has properties for each of them (see `NativeMethodsWrapper.cs`).

There was another issue: I wanted to avoid copying-and-pasting the P/Invoke code, however .NET doesn't let you have the same file twice in the same assembly, with two different sets of preprocessor values. So, the Windows and Linux classes needed to be in two separate assemblies.

I updated the build to use ILRepack to merge all the assemblies together, so users shouldn't actually notice any of this hackiness. Ideally this will all be cleaned up once dotnet/corefx#32015 is completed.

@wget wget merged commit 219c5a5 into gpgme-sharp:master Feb 4, 2019

@wget

This comment has been minimized.

Copy link
Collaborator

wget commented Feb 4, 2019

@Daniel15 Ok for the "hacky" solution. It's good to me. I would have done the same if I had to develop this myself.
Thanks for your patch. I have merged it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment