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 #6

Closed
wants to merge 3 commits into
base: master
from

Conversation

Projects
None yet
1 participant
@Daniel15
Copy link
Member

Daniel15 commented Feb 1, 2019

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.
@Daniel15

This comment has been minimized.

Copy link
Member Author

Daniel15 commented Feb 3, 2019

I need to reopen this off a branch rather than master... GitHub doesn't let me change the source branch

@Daniel15

This comment has been minimized.

Copy link
Member Author

Daniel15 commented Feb 3, 2019

Resubmitted as #7

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