Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly Detect & Handle Musl Systems #1657

Merged
merged 16 commits into from
May 20, 2021
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 @@ private static class Mac

private static class Linux
{
private const string SystemLibrary = "libdl.so";
private const string SystemLibrary = "dl";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattleibow apparently this throws DllNotFoundException on a somewhat clean Ubuntu 20.04 installation


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>
mattleibow marked this conversation as resolved.
Show resolved Hide resolved
</_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);
}
}
}