-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: support dotnet framework (#217)
- Loading branch information
Showing
4 changed files
with
256 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
using System.Reflection; | ||
using System.Runtime.InteropServices; | ||
|
||
internal static class NativeLibLoader | ||
{ | ||
internal static IntPtr LoadNativeLibrary() | ||
{ | ||
var libName = GetBinaryName(); | ||
var tempPath = Path.Combine(Path.GetTempPath(), libName); | ||
var assembly = Assembly.GetExecutingAssembly(); | ||
var assemblyName = assembly.GetName().Name; | ||
|
||
if (!File.Exists(tempPath)) | ||
{ | ||
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{assemblyName}.{libName}")) | ||
{ | ||
if (stream == null) | ||
throw new FileNotFoundException($"Embedded resource {libName} not found."); | ||
|
||
using (var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write)) | ||
{ | ||
stream.CopyTo(fileStream); | ||
} | ||
} | ||
} | ||
|
||
return LoadBinary(tempPath); | ||
} | ||
|
||
private static string GetBinaryName() | ||
{ | ||
string os, arch, libc = ""; | ||
|
||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||
os = "win"; | ||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) | ||
os = "linux"; | ||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | ||
os = "osx"; | ||
else | ||
throw new PlatformNotSupportedException("Unsupported OS"); | ||
|
||
if (RuntimeInformation.ProcessArchitecture == Architecture.X64) | ||
arch = "x86_64"; | ||
else if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) | ||
arch = "arm64"; | ||
else if (RuntimeInformation.ProcessArchitecture == Architecture.X86) | ||
arch = IntPtr.Size == 4 ? "i686" : "x86_64"; | ||
else | ||
throw new PlatformNotSupportedException("Unsupported CPU architecture"); | ||
|
||
if (os == "linux" && IsMusl()) | ||
libc = "-musl"; | ||
|
||
string filename = os == "win" | ||
? $"yggdrasilffi_{arch}.dll" | ||
: $"libyggdrasilffi_{arch}{libc}.{(os == "osx" ? "dylib" : "so")}"; | ||
|
||
return filename; | ||
} | ||
|
||
private static bool IsMusl() | ||
{ | ||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) | ||
return false; | ||
|
||
try | ||
{ | ||
string output = File.ReadAllText("/proc/self/maps"); | ||
return output.Contains("musl"); | ||
} | ||
catch | ||
{ | ||
try | ||
{ | ||
using (var process = new System.Diagnostics.Process()) | ||
{ | ||
process.StartInfo = new System.Diagnostics.ProcessStartInfo | ||
{ | ||
FileName = "ldd", | ||
Arguments = "--version", | ||
RedirectStandardOutput = true, | ||
UseShellExecute = false | ||
}; | ||
process.Start(); | ||
string lddOutput = process.StandardOutput.ReadToEnd(); | ||
process.WaitForExit(); | ||
|
||
return lddOutput.Contains("musl"); | ||
} | ||
} | ||
catch | ||
{ | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
internal static IntPtr LoadFunctionPointer(IntPtr libHandle, string functionName) | ||
{ | ||
Type nativeLibraryType = Type.GetType("System.Runtime.InteropServices.NativeLibrary, System.Runtime.InteropServices"); | ||
if (nativeLibraryType != null) | ||
{ | ||
var getExportMethod = nativeLibraryType.GetMethod("GetExport", new[] { typeof(IntPtr), typeof(string) }); | ||
if (getExportMethod != null) | ||
{ | ||
return (IntPtr)getExportMethod.Invoke(null, new object[] { libHandle, functionName }); | ||
} | ||
} | ||
|
||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||
return GetProcAddress(libHandle, functionName); | ||
else | ||
return dlsym(libHandle, functionName); | ||
} | ||
|
||
private static IntPtr LoadBinary(string libPath) | ||
{ | ||
IntPtr handle; | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||
handle = LoadWindowsLibrary(libPath); | ||
else | ||
handle = LoadUnixLibrary(libPath); | ||
|
||
if (handle == IntPtr.Zero) | ||
throw new DllNotFoundException($"Failed to load library from {libPath}"); | ||
|
||
return handle; | ||
} | ||
|
||
private static IntPtr LoadUnixLibrary(string libPath) | ||
{ | ||
// Try NativeLibrary.Load (works on .NET Core 3+) | ||
Type nativeLibraryType = Type.GetType("System.Runtime.InteropServices.NativeLibrary, System.Runtime.InteropServices"); | ||
if (nativeLibraryType != null) | ||
{ | ||
var loadMethod = nativeLibraryType.GetMethod("Load", new[] { typeof(string) }); | ||
if (loadMethod != null) | ||
return (IntPtr)loadMethod.Invoke(null, new object[] { libPath }); | ||
} | ||
return dlopen(libPath, RTLD_NOW); | ||
} | ||
|
||
private static IntPtr LoadWindowsLibrary(string libPath) | ||
{ | ||
// Try NativeLibrary.Load (works on .NET Core 3+) | ||
Type nativeLibraryType = Type.GetType("System.Runtime.InteropServices.NativeLibrary, System.Runtime.InteropServices"); | ||
if (nativeLibraryType != null) | ||
{ | ||
var loadMethod = nativeLibraryType.GetMethod("Load", new[] { typeof(string) }); | ||
if (loadMethod != null) | ||
return (IntPtr)loadMethod.Invoke(null, new object[] { libPath }); | ||
} | ||
|
||
return LoadLibrary(libPath); | ||
} | ||
|
||
#if NETSTANDARD | ||
[DllImport("kernel32.dll", SetLastError = true)] | ||
private static extern IntPtr LoadLibrary(string dllToLoad); | ||
|
||
[DllImport("kernel32.dll", SetLastError = true)] | ||
private static extern bool FreeLibrary(IntPtr hModule); | ||
|
||
[DllImport("libdl.so.2", EntryPoint = "dlopen")] | ||
private static extern IntPtr dlopen(string filename, int flags); | ||
|
||
[DllImport("libdl.so.2", EntryPoint = "dlclose")] | ||
private static extern int dlclose(IntPtr handle); | ||
|
||
private const int RTLD_NOW = 2; | ||
|
||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] | ||
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); | ||
|
||
[DllImport("libdl.so.2", SetLastError = true, CharSet = CharSet.Ansi)] | ||
private static extern IntPtr dlsym(IntPtr handle, string symbol); | ||
#endif | ||
} |
Oops, something went wrong.