Properly Detect & Handle Musl Systems (#1657)

Fixes #1637
This commit is contained in:
Matthew Leibowitz 2021-05-20 09:09:31 +02:00 коммит произвёл GitHub
Родитель 3a4adf7b6e
Коммит 8b44e793bf
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 106 добавлений и 51 удалений

Просмотреть файл

@ -47,57 +47,24 @@ namespace SkiaSharp
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 @@ namespace SkiaSharp
// 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)
@ -192,7 +191,7 @@ namespace SkiaSharp
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;

Просмотреть файл

@ -37,7 +37,6 @@ namespace SkiaSharp
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 @@ namespace SkiaSharp
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
}
}

Просмотреть файл

@ -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 -->

Просмотреть файл

@ -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 -->

Просмотреть файл

@ -247,5 +247,17 @@ namespace SkiaSharp.Tests
{
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);
}
}
}