Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 60 additions & 30 deletions FoundationDB.Client/Native/FdbNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ internal static unsafe class FdbNative
private const string FDB_C_DLL = "libfdb_c.so";
#else
/// <summary>Name of the C API dll used for P/Invoking</summary>
private const string FDB_C_DLL = "fdb_c.dll";
private const string FDB_C_DLL = "fdb_c";
#endif

/// <summary>Handle on the native FDB C API library</summary>
Expand Down Expand Up @@ -235,42 +235,72 @@ public static extern void fdb_transaction_clear_range(

static FdbNative()
{
// Impact of NativeLibPath:
// - If null, don't preload the library, and let the CLR find the file using the default P/Invoke behavior
// - If String.Empty, call win32 LoadLibrary("fdb_c.dll") and let the os find the file (using the standard OS behavior)
// - Else, combine the path with "fdb_c.dll" and call LoadLibrary with the resulting (relative or absolute) path
var libraryPath = GetPreloadPath();

var libraryPath = Fdb.Options.NativeLibPath;
if (libraryPath != null)
if (libraryPath == null)
{ // PInvoke will load
return;
}

try
{
try
FdbCLib = UnmanagedLibrary.Load(libraryPath);
}
catch (Exception e)
{
if (FdbCLib != null) FdbCLib.Dispose();
FdbCLib = null;
if (e is BadImageFormatException && IntPtr.Size == 4)
{
if (libraryPath.Length == 0)
{ // CLR will handle the search
libraryPath = FDB_C_DLL;
}
else if (!libraryPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
{ // add the file name
libraryPath = Path.Combine(Fdb.Options.NativeLibPath, FDB_C_DLL);
}

FdbCLib = UnmanagedLibrary.Load(libraryPath);
e = new InvalidOperationException("The native FDB client is 64-bit only, and cannot be loaded in a 32-bit process.", e);
}
catch (Exception e)
else
{
if (FdbCLib != null) FdbCLib.Dispose();
FdbCLib = null;
if (e is BadImageFormatException && IntPtr.Size == 4)
{
e = new InvalidOperationException("The native FDB client is 64-bit only, and cannot be loaded in a 32-bit process.", e);
}
else
{
e = new InvalidOperationException("An error occurred while loading the native FoundationDB library", e);
}
LibraryLoadError = ExceptionDispatchInfo.Capture(e);
e = new InvalidOperationException($"An error occurred while loading the native FoundationDB library: '{libraryPath}'.", e);
}
LibraryLoadError = ExceptionDispatchInfo.Capture(e);
}

}

private static string GetPreloadPath()
{
// we need to provide sensible defaults for loading the native library
// if this method returns null we'll let PInvoke deal
// otherwise - use explicit platform-specific dll loading
var libraryPath = Fdb.Options.NativeLibPath;

// on non-windows, library loading by convention just works.
// unless override is provided, just let PInvoke do the work
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (string.IsNullOrEmpty(libraryPath))
{
return null;
}
// otherwise just use the provided path
return libraryPath;
}

// Impact of NativeLibPath on windows:
// - If null, don't preload the library, and let the CLR find the file using the default P/Invoke behavior
// - If String.Empty, call win32 LoadLibrary(FDB_C_DLL + ".dll") and let the os find the file (using the standard OS behavior)
// - If path is folder, append the FDB_C_DLL
var winDllWithExtension = FDB_C_DLL + ".dll";
if (libraryPath == null)
{
return null;
}
if (libraryPath.Length == 0)
{
return winDllWithExtension;
}
var fileName = Path.GetFileName(libraryPath);
if (String.IsNullOrEmpty(fileName))
{
libraryPath = Path.Combine(libraryPath, winDllWithExtension);
}
return libraryPath;
}

private static void EnsureLibraryIsLoaded()
Expand Down
37 changes: 28 additions & 9 deletions FoundationDB.Client/Native/UnmanagedLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,24 @@ protected override bool ReleaseHandle()
[SuppressUnmanagedCodeSecurity]
private static class NativeMethods
{
#if __MonoCS__
const string KERNEL = "dl";
const string LIBDL = "dl";


[DllImport(KERNEL)]
[DllImport(LIBDL)]
public static extern SafeLibraryHandle dlopen(string fileName, int flags);

[DllImport(KERNEL, SetLastError = true)]

[DllImport(LIBDL, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern int dlclose(IntPtr hModule);

public static SafeLibraryHandle LoadLibrary(string fileName)
{
#if __MonoCS__

public static SafeLibraryHandle LoadPlatformLibrary(string fileName)
{
return dlopen(fileName, 1);

}
public static bool FreeLibrary(IntPtr hModule) { return dlclose(hModule) == 0; }
public static bool FreePlatformLibrary(IntPtr hModule) { return dlclose(hModule) == 0; }

#else
const string KERNEL = "kernel32";
Expand All @@ -100,6 +101,24 @@ public static SafeLibraryHandle LoadLibrary(string fileName)
[DllImport(KERNEL, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr hModule);

public static SafeLibraryHandle LoadPlatformLibrary(string fileName)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return LoadLibrary(fileName);
}
return dlopen(fileName, 1);
}

public static bool FreePlatformLibrary(IntPtr hModule)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return FreeLibrary(hModule);
}
return dlclose(hModule) == 0;
}
#endif
}

Expand All @@ -112,7 +131,7 @@ public static UnmanagedLibrary Load(string path)
{
if (path == null) throw new ArgumentNullException("path");

var handle = NativeMethods.LoadLibrary(path);
var handle = NativeMethods.LoadPlatformLibrary(path);
if (handle == null || handle.IsInvalid)
{
var ex = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
Expand Down