Skip to content

Commit

Permalink
Add Mac support for library loading
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonleenaylor committed Feb 10, 2021
1 parent c1406a5 commit 252c19b
Showing 1 changed file with 43 additions and 4 deletions.
47 changes: 43 additions & 4 deletions source/icu.net/NativeMethods/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ static NativeMethods()

#region Dynamic method loading

#region Native methods for Linux
#region Native methods for Unix

private const int RTLD_NOW = 2;

Expand All @@ -81,7 +81,26 @@ private static string dlerror()
var ptr = _dlerror();
return Marshal.PtrToStringAnsi(ptr);
}
private const string MAC_LIBDL_NAME = "libdl.dylib";

[DllImport(MAC_LIBDL_NAME, SetLastError = true)]
private static extern IntPtr mac_dlopen(string file, int mode);

[DllImport(MAC_LIBDL_NAME, SetLastError = true)]
private static extern int mac_dlclose(IntPtr handle);

[DllImport(MAC_LIBDL_NAME, SetLastError = true)]
private static extern IntPtr mac_dlsym(IntPtr handle, string name);

[DllImport(MAC_LIBDL_NAME, EntryPoint = "dlerror")]
private static extern IntPtr _mac_dlerror();

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

#region Native methods for Windows
Expand Down Expand Up @@ -120,6 +139,7 @@ private enum LoadLibraryFlags : uint
private static IntPtr _IcuI18NLibHandle;

private static bool IsWindows => Platform.OperatingSystem == OperatingSystemType.Windows;
private static bool IsMac = Platform.OperatingSystem == OperatingSystemType.MacOSX;

private static IntPtr IcuCommonLibHandle
{
Expand Down Expand Up @@ -295,6 +315,17 @@ private static IntPtr GetIcuLibHandle(string basename, int icuVersion)
Trace.WriteLineIf(handle == IntPtr.Zero && lastError != 0,
$"Unable to load [{libPath}]. Error: {new Win32Exception(lastError).Message}");
}
if (IsMac)
{
var libName = $"lib{basename}.{icuVersion}.dylib";
libPath = string.IsNullOrEmpty(_IcuPath) ? libName : Path.Combine(_IcuPath, libName);

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

Trace.WriteLineIf(handle == IntPtr.Zero && lastError != 0,
$"Unable to load [{libPath}]. Error: {lastError} ({dlerror()})");
}
else
{
var libName = $"lib{basename}.so.{icuVersion}";
Expand All @@ -306,10 +337,11 @@ private static IntPtr GetIcuLibHandle(string basename, int icuVersion)
Trace.WriteLineIf(handle == IntPtr.Zero && lastError != 0,
$"Unable to load [{libPath}]. Error: {lastError} ({dlerror()})");
}

if (handle == IntPtr.Zero)
{
Trace.TraceWarning("{0} of {1} failed with error {2}",
IsWindows ? "LoadLibraryEx" : "dlopen",
IsWindows ? "LoadLibraryEx" : IsMac ? "mac_dlopen" : "dlopen",
libPath, lastError);
return GetIcuLibHandle(basename, icuVersion - 1);
}
Expand Down Expand Up @@ -339,6 +371,13 @@ public static void Cleanup()
if (_IcuI18NLibHandle != IntPtr.Zero)
FreeLibrary(_IcuI18NLibHandle);
}
else if (IsMac)
{
if (_IcuCommonLibHandle != IntPtr.Zero)
mac_dlclose(_IcuCommonLibHandle);
if (_IcuI18NLibHandle != IntPtr.Zero)
mac_dlclose(_IcuI18NLibHandle);
}
else
{
if (_IcuCommonLibHandle != IntPtr.Zero)
Expand Down Expand Up @@ -389,14 +428,14 @@ private static T GetMethod<T>(IntPtr handle, string methodName, bool missingInMi
var versionedMethodName = $"{methodName}_{IcuVersion}";
var methodPointer = IsWindows ?
GetProcAddress(handle, versionedMethodName) :
dlsym(handle, versionedMethodName);
IsMac ? mac_dlsym(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) :
dlsym(handle, methodName);
IsMac ? mac_dlsym(handle, methodName) : dlsym(handle, methodName);
}
if (methodPointer != IntPtr.Zero)
{
Expand Down

0 comments on commit 252c19b

Please sign in to comment.