Skip to content

Commit

Permalink
Try to get libdl functions from dlfcn.h on mac
Browse files Browse the repository at this point in the history
  • Loading branch information
imnasnainaec committed Mar 22, 2024
1 parent b990d03 commit 2fb5790
Showing 1 changed file with 49 additions and 3 deletions.
52 changes: 49 additions & 3 deletions source/icu.net/NativeMethods/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ static NativeMethods()

#region Dynamic method loading

#region Native methods for Unix

private const int RTLD_NOW = 2;

#region Native methods for Linux

private const string LIBDL_NAME = "libdl.so";

[DllImport(LIBDL_NAME, SetLastError = true)]
Expand All @@ -102,6 +102,31 @@ private static string dlerror()

#endregion

#region Native methods for Mac

private const string DLFCN_NAME = "dlfcn.h";

[DllImport(DLFCN_NAME, EntryPoint = "dlopen", SetLastError = true)]
private static extern IntPtr dlopen_mac(string file, int mode);

[DllImport(DLFCN_NAME, EntryPoint = "dlclose", SetLastError = true)]
private static extern int dlclose_mac(IntPtr handle);

[DllImport(DLFCN_NAME, EntryPoint = "dlsym", SetLastError = true)]
private static extern IntPtr dlsym_mac(IntPtr handle, string name);

[DllImport(DLFCN_NAME, EntryPoint = "dlerror")]
private static extern IntPtr _dlerror_mac();

private static string dlerror_mac()
{
// Don't free the string returned from _dlerror()!
var ptr = _dlerror_mac();
return Marshal.PtrToStringAnsi(ptr);
}

#endregion

#region Native methods for Windows

[DllImport("kernel32.dll", SetLastError = true)]
Expand Down Expand Up @@ -338,9 +363,19 @@ private static IntPtr GetIcuLibHandle(string basename, int icuVersion)

Trace.WriteLineIf(handle == IntPtr.Zero && lastError != 0, $"Unable to load [{libPath}]. Error: {new Win32Exception(lastError).Message}");
}
else if (IsMac)
{
var libName = $"lib{basename}.{icuVersion}.dylib";
libPath = string.IsNullOrEmpty(_IcuPath) ? libName : Path.Combine(_IcuPath, libName);

handle = dlopen_mac(libPath, RTLD_NOW);
lastError = Marshal.GetLastWin32Error();

Trace.WriteLineIf(handle == IntPtr.Zero && lastError != 0, $"Unable to load [{libPath}]. Error: {lastError} ({dlerror_mac()})");
}
else
{
var libName = IsMac ? $"lib{basename}.{icuVersion}.dylib" : $"lib{basename}.so.{icuVersion}";
var libName = $"lib{basename}.so.{icuVersion}";
libPath = string.IsNullOrEmpty(_IcuPath) ? libName : Path.Combine(_IcuPath, libName);

handle = dlopen(libPath, RTLD_NOW);
Expand Down Expand Up @@ -395,6 +430,13 @@ internal static void Cleanup()
if (_IcuI18NLibHandle != IntPtr.Zero)
FreeLibrary(_IcuI18NLibHandle);
}
else if (IsMac)
{
if (_IcuCommonLibHandle != IntPtr.Zero)
dlclose_mac(_IcuCommonLibHandle);
if (_IcuI18NLibHandle != IntPtr.Zero)
dlclose_mac(_IcuI18NLibHandle);
}
else
{
if (_IcuCommonLibHandle != IntPtr.Zero)
Expand Down Expand Up @@ -431,13 +473,17 @@ private static T GetMethod<T>(IntPtr handle, string methodName, bool missingInMi
var versionedMethodName = $"{methodName}_{IcuVersion}";
var methodPointer = IsWindows ?
GetProcAddress(handle, versionedMethodName) :
IsMac ?
dlsym_mac(handle, versionedMethodName):
dlsym(handle, versionedMethodName);

// Some systems (eg. Tizen) don't use methods with IcuVersion suffix
if (methodPointer == IntPtr.Zero)
{
methodPointer = IsWindows ?
GetProcAddress(handle, methodName) :
IsMac ?
dlsym_mac(handle, methodName):
dlsym(handle, methodName);
}
if (methodPointer != IntPtr.Zero)
Expand Down

0 comments on commit 2fb5790

Please sign in to comment.