diff --git a/binding/Binding.Shared/LibraryLoader.cs b/binding/Binding.Shared/LibraryLoader.cs index 96daecd578..5923691259 100644 --- a/binding/Binding.Shared/LibraryLoader.cs +++ b/binding/Binding.Shared/LibraryLoader.cs @@ -47,57 +47,24 @@ static string GetLibraryPath (string libraryName) var path = typeof (T).Assembly.Location; if (!string.IsNullOrEmpty (path)) { path = Path.GetDirectoryName (path); - // 1.1 in platform sub dir - var lib = Path.Combine (path, arch, libWithExt); - if (File.Exists (lib)) - return lib; - // 1.2 in root - lib = Path.Combine (path, libWithExt); - if (File.Exists (lib)) - return lib; + if (CheckLibraryPath (path, arch, libWithExt, out var localLib)) + return localLib; } // 2. try current directory - path = Directory.GetCurrentDirectory (); - if (!string.IsNullOrEmpty (path)) { - // 2.1 in platform sub dir - var lib = Path.Combine (path, arch, libWithExt); - if (File.Exists (lib)) - return lib; - // 2.2 in root - lib = Path.Combine (lib, libWithExt); - if (File.Exists (lib)) - return lib; - } + if (CheckLibraryPath (Directory.GetCurrentDirectory (), arch, libWithExt, out var lib)) + return lib; // 3. try app domain try { if (AppDomain.CurrentDomain is AppDomain domain) { // 3.1 RelativeSearchPath - path = domain.RelativeSearchPath; - if (!string.IsNullOrEmpty (path)) { - // 3.1.1 in platform sub dir - var lib = Path.Combine (path, arch, libWithExt); - if (File.Exists (lib)) - return lib; - // 3.1.2 in root - lib = Path.Combine (lib, libWithExt); - if (File.Exists (lib)) - return lib; - } + if (CheckLibraryPath (domain.RelativeSearchPath, arch, libWithExt, out lib)) + return lib; // 3.2 BaseDirectory - path = domain.BaseDirectory; - if (!string.IsNullOrEmpty (path)) { - // 3.2.1 in platform sub dir - var lib = Path.Combine (path, arch, libWithExt); - if (File.Exists (lib)) - return lib; - // 3.2.2 in root - lib = Path.Combine (lib, libWithExt); - if (File.Exists (lib)) - return lib; - } + if (CheckLibraryPath (domain.BaseDirectory, arch, libWithExt, out lib)) + return lib; } } catch { // no-op as there may not be any domain or path @@ -106,6 +73,38 @@ static string GetLibraryPath (string libraryName) // 4. use PATH or default loading mechanism return libWithExt; } + + static bool CheckLibraryPath(string root, string arch, string libWithExt, out string foundPath) + { + if (!string.IsNullOrEmpty (root)) { + // a. in specific platform sub dir + if (!string.IsNullOrEmpty (PlatformConfiguration.LinuxFlavor)) { + var muslLib = Path.Combine (root, PlatformConfiguration.LinuxFlavor + "-" + arch, libWithExt); + if (File.Exists (muslLib)) { + foundPath = muslLib; + return true; + } + } + + // b. in generic platform sub dir + var searchLib = Path.Combine (root, arch, libWithExt); + if (File.Exists (searchLib)) { + foundPath = searchLib; + return true; + } + + // c. in root + searchLib = Path.Combine (root, libWithExt); + if (File.Exists (searchLib)) { + foundPath = searchLib; + return true; + } + } + + // d. nothing + foundPath = null; + return false; + } } public static T GetSymbolDelegate (IntPtr library, string name) @@ -192,7 +191,7 @@ private static class Mac private static class Linux { - private const string SystemLibrary = "libdl.so"; + private const string SystemLibrary = "dl"; private const int RTLD_LAZY = 1; private const int RTLD_NOW = 2; diff --git a/binding/Binding.Shared/PlatformConfiguration.cs b/binding/Binding.Shared/PlatformConfiguration.cs index 7b326c12dd..9e6c8eaeaa 100644 --- a/binding/Binding.Shared/PlatformConfiguration.cs +++ b/binding/Binding.Shared/PlatformConfiguration.cs @@ -37,7 +37,6 @@ static PlatformConfiguration () var arch = Package.Current.Id.Architecture; const ProcessorArchitecture arm64 = (ProcessorArchitecture)12; IsArm = arch == ProcessorArchitecture.Arm || arch == arm64; - #else IsMac = RuntimeInformation.IsOSPlatform (OSPlatform.OSX); IsLinux = RuntimeInformation.IsOSPlatform (OSPlatform.Linux); @@ -50,5 +49,50 @@ static PlatformConfiguration () Is64Bit = IntPtr.Size == 8; } + + private static string linuxFlavor; + + public static string LinuxFlavor + { + get + { + if (!IsLinux) + return null; + + if (!string.IsNullOrEmpty (linuxFlavor)) + return linuxFlavor; + + // we only check for musl/glibc right now + if (!IsGlibc) + return "musl"; + + return null; + } + set => linuxFlavor = value; + } + +#if WINDOWS_UWP + public static bool IsGlibc { get; } +#else + private static readonly Lazy isGlibcLazy = new Lazy (IsGlibcImplementation); + + public static bool IsGlibc => IsLinux && isGlibcLazy.Value; + + private static bool IsGlibcImplementation () + { + try + { + gnu_get_libc_version (); + return true; + } + catch (TypeLoadException) + { + return false; + } + } + + [DllImport ("c", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr gnu_get_libc_version (); +#endif } } diff --git a/binding/HarfBuzzSharp/nuget/build/net462/HarfBuzzSharp.targets b/binding/HarfBuzzSharp/nuget/build/net462/HarfBuzzSharp.targets index 3af672a23b..598652dbca 100644 --- a/binding/HarfBuzzSharp/nuget/build/net462/HarfBuzzSharp.targets +++ b/binding/HarfBuzzSharp/nuget/build/net462/HarfBuzzSharp.targets @@ -45,16 +45,16 @@ <_NativeHarfBuzzSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-x86\native\libHarfBuzzSharp*.so"> - x86\ + musl-x86\ <_NativeHarfBuzzSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-x64\native\libHarfBuzzSharp*.so"> - x64\ + musl-x64\ <_NativeHarfBuzzSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-arm\native\libHarfBuzzSharp*.so"> - arm\ + musl-arm\ <_NativeHarfBuzzSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-arm64\native\libHarfBuzzSharp*.so"> - arm64\ + musl-arm64\ diff --git a/binding/SkiaSharp/nuget/build/net462/SkiaSharp.targets b/binding/SkiaSharp/nuget/build/net462/SkiaSharp.targets index cd42e61e30..7ea7422f38 100644 --- a/binding/SkiaSharp/nuget/build/net462/SkiaSharp.targets +++ b/binding/SkiaSharp/nuget/build/net462/SkiaSharp.targets @@ -45,16 +45,16 @@ <_NativeSkiaSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-x86\native\libSkiaSharp*.so"> - x86\ + musl-x86\ <_NativeSkiaSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-x64\native\libSkiaSharp*.so"> - x64\ + musl-x64\ <_NativeSkiaSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-arm\native\libSkiaSharp*.so"> - arm\ + musl-arm\ <_NativeSkiaSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-arm64\native\libSkiaSharp*.so"> - arm64\ + musl-arm64\ diff --git a/tests/Tests/ApiTests.cs b/tests/Tests/ApiTests.cs index 4616eeacfd..3f6970c77b 100644 --- a/tests/Tests/ApiTests.cs +++ b/tests/Tests/ApiTests.cs @@ -247,5 +247,17 @@ public void TestVersionsString() { Assert.Equal(SkiaSharpVersion.Native.ToString(2), SkiaSharpVersion.NativeString); } + + [SkippableFact] + public void PlatformConfigurationIsMuslOverrideCanBeFoundViaReflection() + { + var assembly = typeof(SkiaSharpVersion).Assembly; + var config = assembly.DefinedTypes.FirstOrDefault(t => t.Name == "PlatformConfiguration"); + var overrideProp = config.GetProperty("LinuxFlavor"); + + Assert.Equal(typeof(string), overrideProp.PropertyType); + Assert.True(overrideProp.CanRead); + Assert.True(overrideProp.CanWrite); + } } }