Skip to content

Commit 7a257b0

Browse files
authored
Merge pull request #79 from bitgn/libdl-loader
loading: on non-windows use libdl to load libfdb_c
2 parents 69f0359 + 1cbc073 commit 7a257b0

File tree

2 files changed

+88
-39
lines changed

2 files changed

+88
-39
lines changed

FoundationDB.Client/Native/FdbNative.cs

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ internal static unsafe class FdbNative
4949
private const string FDB_C_DLL = "libfdb_c.so";
5050
#else
5151
/// <summary>Name of the C API dll used for P/Invoking</summary>
52-
private const string FDB_C_DLL = "fdb_c.dll";
52+
private const string FDB_C_DLL = "fdb_c";
5353
#endif
5454

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

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

243-
var libraryPath = Fdb.Options.NativeLibPath;
244-
if (libraryPath != null)
240+
if (libraryPath == null)
241+
{ // PInvoke will load
242+
return;
243+
}
244+
245+
try
245246
{
246-
try
247+
FdbCLib = UnmanagedLibrary.Load(libraryPath);
248+
}
249+
catch (Exception e)
250+
{
251+
if (FdbCLib != null) FdbCLib.Dispose();
252+
FdbCLib = null;
253+
if (e is BadImageFormatException && IntPtr.Size == 4)
247254
{
248-
if (libraryPath.Length == 0)
249-
{ // CLR will handle the search
250-
libraryPath = FDB_C_DLL;
251-
}
252-
else if (!libraryPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
253-
{ // add the file name
254-
libraryPath = Path.Combine(Fdb.Options.NativeLibPath, FDB_C_DLL);
255-
}
256-
257-
FdbCLib = UnmanagedLibrary.Load(libraryPath);
255+
e = new InvalidOperationException("The native FDB client is 64-bit only, and cannot be loaded in a 32-bit process.", e);
258256
}
259-
catch (Exception e)
257+
else
260258
{
261-
if (FdbCLib != null) FdbCLib.Dispose();
262-
FdbCLib = null;
263-
if (e is BadImageFormatException && IntPtr.Size == 4)
264-
{
265-
e = new InvalidOperationException("The native FDB client is 64-bit only, and cannot be loaded in a 32-bit process.", e);
266-
}
267-
else
268-
{
269-
e = new InvalidOperationException("An error occurred while loading the native FoundationDB library", e);
270-
}
271-
LibraryLoadError = ExceptionDispatchInfo.Capture(e);
259+
e = new InvalidOperationException($"An error occurred while loading the native FoundationDB library: '{libraryPath}'.", e);
260+
}
261+
LibraryLoadError = ExceptionDispatchInfo.Capture(e);
262+
}
263+
264+
}
265+
266+
private static string GetPreloadPath()
267+
{
268+
// we need to provide sensible defaults for loading the native library
269+
// if this method returns null we'll let PInvoke deal
270+
// otherwise - use explicit platform-specific dll loading
271+
var libraryPath = Fdb.Options.NativeLibPath;
272+
273+
// on non-windows, library loading by convention just works.
274+
// unless override is provided, just let PInvoke do the work
275+
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
276+
{
277+
if (string.IsNullOrEmpty(libraryPath))
278+
{
279+
return null;
272280
}
281+
// otherwise just use the provided path
282+
return libraryPath;
283+
}
284+
285+
// Impact of NativeLibPath on windows:
286+
// - If null, don't preload the library, and let the CLR find the file using the default P/Invoke behavior
287+
// - If String.Empty, call win32 LoadLibrary(FDB_C_DLL + ".dll") and let the os find the file (using the standard OS behavior)
288+
// - If path is folder, append the FDB_C_DLL
289+
var winDllWithExtension = FDB_C_DLL + ".dll";
290+
if (libraryPath == null)
291+
{
292+
return null;
293+
}
294+
if (libraryPath.Length == 0)
295+
{
296+
return winDllWithExtension;
297+
}
298+
var fileName = Path.GetFileName(libraryPath);
299+
if (String.IsNullOrEmpty(fileName))
300+
{
301+
libraryPath = Path.Combine(libraryPath, winDllWithExtension);
273302
}
303+
return libraryPath;
274304
}
275305

276306
private static void EnsureLibraryIsLoaded()

FoundationDB.Client/Native/UnmanagedLibrary.cs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,23 +72,24 @@ protected override bool ReleaseHandle()
7272
[SuppressUnmanagedCodeSecurity]
7373
private static class NativeMethods
7474
{
75-
#if __MonoCS__
76-
const string KERNEL = "dl";
75+
const string LIBDL = "dl";
76+
7777

78-
[DllImport(KERNEL)]
78+
[DllImport(LIBDL)]
7979
public static extern SafeLibraryHandle dlopen(string fileName, int flags);
8080

81-
[DllImport(KERNEL, SetLastError = true)]
81+
82+
[DllImport(LIBDL, SetLastError = true)]
8283
[return: MarshalAs(UnmanagedType.Bool)]
8384
public static extern int dlclose(IntPtr hModule);
8485

85-
public static SafeLibraryHandle LoadLibrary(string fileName)
86-
{
86+
#if __MonoCS__
8787

88+
public static SafeLibraryHandle LoadPlatformLibrary(string fileName)
89+
{
8890
return dlopen(fileName, 1);
89-
9091
}
91-
public static bool FreeLibrary(IntPtr hModule) { return dlclose(hModule) == 0; }
92+
public static bool FreePlatformLibrary(IntPtr hModule) { return dlclose(hModule) == 0; }
9293

9394
#else
9495
const string KERNEL = "kernel32";
@@ -100,6 +101,24 @@ public static SafeLibraryHandle LoadLibrary(string fileName)
100101
[DllImport(KERNEL, SetLastError = true)]
101102
[return: MarshalAs(UnmanagedType.Bool)]
102103
public static extern bool FreeLibrary(IntPtr hModule);
104+
105+
public static SafeLibraryHandle LoadPlatformLibrary(string fileName)
106+
{
107+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
108+
{
109+
return LoadLibrary(fileName);
110+
}
111+
return dlopen(fileName, 1);
112+
}
113+
114+
public static bool FreePlatformLibrary(IntPtr hModule)
115+
{
116+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
117+
{
118+
return FreeLibrary(hModule);
119+
}
120+
return dlclose(hModule) == 0;
121+
}
103122
#endif
104123
}
105124

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

115-
var handle = NativeMethods.LoadLibrary(path);
134+
var handle = NativeMethods.LoadPlatformLibrary(path);
116135
if (handle == null || handle.IsInvalid)
117136
{
118137
var ex = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());

0 commit comments

Comments
 (0)