Skip to content

Commit

Permalink
Properly Detect & Handle Musl Systems (#1657)
Browse files Browse the repository at this point in the history
Fixes #1637
  • Loading branch information
mattleibow committed May 20, 2021
1 parent 3a4adf7 commit 8b44e79
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 51 deletions.
83 changes: 41 additions & 42 deletions binding/Binding.Shared/LibraryLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<T> (IntPtr library, string name)
Expand Down Expand Up @@ -192,7 +191,7 @@ public static IntPtr dlopen (string path, bool lazy = true) =>

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;
Expand Down
46 changes: 45 additions & 1 deletion binding/Binding.Shared/PlatformConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<bool> isGlibcLazy = new Lazy<bool> (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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,16 @@

<!-- Linux: Musl -->
<_NativeHarfBuzzSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-x86\native\libHarfBuzzSharp*.so">
<Dir>x86\</Dir>
<Dir>musl-x86\</Dir>
</_NativeHarfBuzzSharpFile>
<_NativeHarfBuzzSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-x64\native\libHarfBuzzSharp*.so">
<Dir>x64\</Dir>
<Dir>musl-x64\</Dir>
</_NativeHarfBuzzSharpFile>
<_NativeHarfBuzzSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-arm\native\libHarfBuzzSharp*.so">
<Dir>arm\</Dir>
<Dir>musl-arm\</Dir>
</_NativeHarfBuzzSharpFile>
<_NativeHarfBuzzSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-arm64\native\libHarfBuzzSharp*.so">
<Dir>arm64\</Dir>
<Dir>musl-arm64\</Dir>
</_NativeHarfBuzzSharpFile>

<!-- macOS -->
Expand Down
8 changes: 4 additions & 4 deletions binding/SkiaSharp/nuget/build/net462/SkiaSharp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,16 @@

<!-- Linux: Musl -->
<_NativeSkiaSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-x86\native\libSkiaSharp*.so">
<Dir>x86\</Dir>
<Dir>musl-x86\</Dir>
</_NativeSkiaSharpFile>
<_NativeSkiaSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-x64\native\libSkiaSharp*.so">
<Dir>x64\</Dir>
<Dir>musl-x64\</Dir>
</_NativeSkiaSharpFile>
<_NativeSkiaSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-arm\native\libSkiaSharp*.so">
<Dir>arm\</Dir>
<Dir>musl-arm\</Dir>
</_NativeSkiaSharpFile>
<_NativeSkiaSharpFile Include="$(MSBuildThisFileDirectory)..\..\runtimes\linux-musl-arm64\native\libSkiaSharp*.so">
<Dir>arm64\</Dir>
<Dir>musl-arm64\</Dir>
</_NativeSkiaSharpFile>

<!-- macOS -->
Expand Down
12 changes: 12 additions & 0 deletions tests/Tests/ApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

0 comments on commit 8b44e79

Please sign in to comment.