-
Notifications
You must be signed in to change notification settings - Fork 10.5k
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
Fix C# native library loading in .NET 5 single-file apps #24744
Fix C# native library loading in .NET 5 single-file apps #24744
Conversation
Once this is approved, I'll also create a backport PR. |
Adhoc distribtests: https://g3c.corp.google.com/results/invocations/a25cde5a-bf1c-49cc-923e-315e96987e17 (including the newly added single file publish distribtest). |
{ | ||
var assembly = typeof(NativeExtension).GetTypeInfo().Assembly; | ||
#if NETSTANDARD | ||
// Assembly.EscapedCodeBase does not exist under CoreCLR, but assemblies imported from a nuget package | ||
// don't seem to be shadowed by DNX-based projects at all. | ||
return assembly.Location; | ||
var assemblyLocation = assembly.Location; | ||
if (assemblyLocation != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, assembly.Location might be returning an empty string according to the docs:
https://docs.microsoft.com/en-us/dotnet/core/deploying/single-file#api-incompatibility
I'll check which one is correct and update the code if needed.
Another adhoc distribtest run: https://g3c.corp.google.com/results/invocations/8872dc43-c7da-4533-b792-bc1c5eaff03b/targets |
Yet another adhoc distribtest: https://g3c.corp.google.com/results/invocations/700ebfdb-8e9a-43c8-9e43-2e58a4929037 |
https://github.com/grpc/grpc/blob/master/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs#L245 is another problem that needs to be fixed to make the single file scenario working. There is no libcoreclr.so on disk in the single file scenario. |
Ok, thanks for the tip. Do you have ideas on how to fix this problem? |
@jtattermusch please add a distribtest for the |
The best way to fix this problem is to use |
Thanks for the tip! Unfortunately Native.Load is only available on .NET Core 3+ (and at this point the newest we target is netstandard2.0) |
dce96e9
to
4e8de8d
Compare
The interop test failure is #24764. |
As @jkotas has pointed out, I'm now getting the
|
@yulin-liang I don't have a fully working fix at this point, so I think it's fine to cut the release branch without it. (If I come up with a fix, I can backport it) |
The fix for this should be to try to lookup these methods using reflection, and then use them instead of the hardcoded P/Invokes when these methods are available. Something like: delegate bool TryLoadDelegate(string libraryName, System.Reflection.Assembly assembly, System.Runtime.InteropServices.DllImportSearchPath? searchPath, out IntPtr handle);
delegate bool TryGetExportDelegate(IntPtr handle, string name, out IntPtr address);
static TryLoadDelegate s_tryLoad;
static TryGetExportDelegate s_tryGetExport;
...
Type nativeLibrary = Type.GetType("System.Runtime.InteropServices.NativeLibrary, System.Runtime.InteropServices, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
if (nativeLibrary == null)
return;
MethodInfo tryLoad = nativeLibrary.GetMethod("TryLoad", BindingFlags.Static | BindingFlags.Public, null,
new Type[] { typeof(string), typeof(Assembly), typeof(Nullable<DllImportSearchPath>), typeof(IntPtr).MakeByRefType() }, null);
s_tryLoad = (TryLoadDelegate)tryLoad?.CreateDelegate(typeof(TryLoadDelegate));
MethodInfo tryGetExport = nativeLibrary.GetMethod("TryLoad", BindingFlags.Static | BindingFlags.Public, null,
new Type[] { typeof(IntPtr), typeof(string), typeof(IntPtr).MakeByRefType() }, null);
s_tryGetExport = (TryGetExportDelegate)tryGetExport?.CreateDelegate(typeof(TryGetExportDelegate)); |
Alternative approach used by a library that faced a similar problem: gui-cs/Terminal.Gui@19955fa#diff-91d94d0e5b8dd01a182c51299d7e8093247fa636a9768574b7042bfd5df9a1deR261 |
77212fd
to
840590e
Compare
I refactored the native library loading logic to use the default The adhoc distribtest run is here: https://g3c.corp.google.com/results/invocations/4da3122d-8972-48ff-ac92-d01b22705b99/log |
Known failures: build_docker_go is also failing on master. |
Adhoc distribtests are passing: dotnet 5 distribtest is also green: |
{ | ||
// TODO: allow customizing path to native extension (possibly through exposing a GrpcEnvironment property). | ||
// See https://github.com/grpc/grpc/pull/7303 for one option. | ||
var assemblyDirectory = Path.GetDirectoryName(GetAssemblyPath()); | ||
var assemblyDirectory = GetAssemblyDirectory(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes in this method should not be needed with your new fix.
// The classes with the list of DllImport'd methods are code generated, | ||
// so having more than just one doesn't really bother us. | ||
|
||
// on Windows, the DllImport("grpc_csharp_ext.x64") doesn't work for some reason, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was bug dotnet/coreclr#17505 . It is fixed in .NET Core 3.1, but I assume you still want this to work on .NET Core 2.1.
Looks fine to me. |
@jtattermusch does your fix handle the |
I haven't tested that explicitly - would you mind trying it out and posting back the result? The nightly build of the nugets should appear here soon: Alternatively, here are nugets from my last manual build: I wanted to merge this PR ASAP because like this the fixes will still make it to Grpc.Core 2.34.0 release - we can address |
@jtattermusch I did a test with |
Fixes #24266.