Load specific native libraries on desktop/netfx
This fixes 2 issues: - loading multiple versions of libSkiaSharp (#1252) - resolving the issue with 32/64 bit dll (#713)
This commit is contained in:
Родитель
c23eab0bf9
Коммит
7cda786b8a
|
@ -0,0 +1,198 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
#if HARFBUZZ
|
||||||
|
namespace HarfBuzzSharp
|
||||||
|
#else
|
||||||
|
namespace SkiaSharp
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if USE_DELEGATES || USE_LIBRARY_LOADER
|
||||||
|
internal static class LibraryLoader
|
||||||
|
{
|
||||||
|
static LibraryLoader ()
|
||||||
|
{
|
||||||
|
if (PlatformConfiguration.IsWindows)
|
||||||
|
Extension = ".dll";
|
||||||
|
else if (PlatformConfiguration.IsMac)
|
||||||
|
Extension = ".dylib";
|
||||||
|
else
|
||||||
|
Extension = ".so";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Extension { get; }
|
||||||
|
|
||||||
|
public static IntPtr LoadLocalLibrary<T> (string libraryName)
|
||||||
|
{
|
||||||
|
var libraryPath = GetLibraryPath (libraryName);
|
||||||
|
|
||||||
|
var handle = LoadLibrary (libraryPath);
|
||||||
|
if (handle == IntPtr.Zero)
|
||||||
|
throw new DllNotFoundException ($"Unable to load library '{libraryName}'.");
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
|
||||||
|
static string GetLibraryPath (string libraryName)
|
||||||
|
{
|
||||||
|
var arch = IntPtr.Size == 8 ? "x64" : "x86";
|
||||||
|
|
||||||
|
var libWithExt = libraryName;
|
||||||
|
if (!libraryName.EndsWith (Extension, StringComparison.OrdinalIgnoreCase))
|
||||||
|
libWithExt += Extension;
|
||||||
|
|
||||||
|
// 1. try alongside managed assembly
|
||||||
|
var path = typeof (T).Assembly.Location;
|
||||||
|
if (!string.IsNullOrEmpty (path)) {
|
||||||
|
path = Path.GetDirectoryName (path);
|
||||||
|
// 1.1 in platform sub dir
|
||||||
|
path = Path.Combine (path, arch, libWithExt);
|
||||||
|
if (File.Exists (path))
|
||||||
|
return path;
|
||||||
|
// 1.2 in root
|
||||||
|
path = Path.Combine (path, libWithExt);
|
||||||
|
if (File.Exists (path))
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. try current directory
|
||||||
|
path = Directory.GetCurrentDirectory ();
|
||||||
|
if (!string.IsNullOrEmpty (path)) {
|
||||||
|
// 2.1 in platform sub dir
|
||||||
|
path = Path.Combine (path, arch, libWithExt);
|
||||||
|
if (File.Exists (path))
|
||||||
|
return path;
|
||||||
|
// 2.2 in root
|
||||||
|
path = Path.Combine (path, libWithExt);
|
||||||
|
if (File.Exists (path))
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. use PATH or default loading mechanism
|
||||||
|
return libraryName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T GetSymbolDelegate<T> (IntPtr library, string name)
|
||||||
|
where T : Delegate
|
||||||
|
{
|
||||||
|
var symbol = GetSymbol (library, name);
|
||||||
|
if (symbol == IntPtr.Zero)
|
||||||
|
throw new EntryPointNotFoundException ($"Unable to load symbol '{name}'.");
|
||||||
|
|
||||||
|
#if __NET_45__
|
||||||
|
return (T)Marshal.GetDelegateForFunctionPointer (symbol, typeof (T));
|
||||||
|
#else
|
||||||
|
return Marshal.GetDelegateForFunctionPointer<T> (symbol);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntPtr LoadLibrary (string libraryName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty (libraryName))
|
||||||
|
throw new ArgumentNullException (nameof (libraryName));
|
||||||
|
|
||||||
|
IntPtr handle;
|
||||||
|
if (PlatformConfiguration.IsWindows)
|
||||||
|
handle = Win32.LoadLibrary (libraryName);
|
||||||
|
else if (PlatformConfiguration.IsLinux)
|
||||||
|
handle = Linux.dlopen (libraryName);
|
||||||
|
else if (PlatformConfiguration.IsMac)
|
||||||
|
handle = Mac.dlopen (libraryName);
|
||||||
|
else
|
||||||
|
throw new PlatformNotSupportedException ($"Current platform is unknown, unable to load library '{libraryName}'.");
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntPtr GetSymbol (IntPtr library, string symbolName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty (symbolName))
|
||||||
|
throw new ArgumentNullException (nameof (symbolName));
|
||||||
|
|
||||||
|
IntPtr handle;
|
||||||
|
if (PlatformConfiguration.IsWindows)
|
||||||
|
handle = Win32.GetProcAddress (library, symbolName);
|
||||||
|
else if (PlatformConfiguration.IsLinux)
|
||||||
|
handle = Linux.dlsym (library, symbolName);
|
||||||
|
else if (PlatformConfiguration.IsMac)
|
||||||
|
handle = Mac.dlsym (library, symbolName);
|
||||||
|
else
|
||||||
|
throw new PlatformNotSupportedException ($"Current platform is unknown, unable to load symbol '{symbolName}' from library {library}.");
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FreeLibrary (IntPtr library)
|
||||||
|
{
|
||||||
|
if (library == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PlatformConfiguration.IsWindows)
|
||||||
|
Win32.FreeLibrary (library);
|
||||||
|
else if (PlatformConfiguration.IsLinux)
|
||||||
|
Linux.dlclose (library);
|
||||||
|
else if (PlatformConfiguration.IsMac)
|
||||||
|
Mac.dlclose (library);
|
||||||
|
else
|
||||||
|
throw new PlatformNotSupportedException ($"Current platform is unknown, unable to close library '{library}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable IDE1006 // Naming Styles
|
||||||
|
private static class Mac
|
||||||
|
{
|
||||||
|
private const string SystemLibrary = "/usr/lib/libSystem.dylib";
|
||||||
|
|
||||||
|
private const int RTLD_LAZY = 1;
|
||||||
|
private const int RTLD_NOW = 2;
|
||||||
|
|
||||||
|
public static IntPtr dlopen (string path, bool lazy = true) =>
|
||||||
|
dlopen (path, lazy ? RTLD_LAZY : RTLD_NOW);
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary)]
|
||||||
|
public static extern IntPtr dlopen (string path, int mode);
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary)]
|
||||||
|
public static extern IntPtr dlsym (IntPtr handle, string symbol);
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary)]
|
||||||
|
public static extern void dlclose (IntPtr handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Linux
|
||||||
|
{
|
||||||
|
private const string SystemLibrary = "libdl.so";
|
||||||
|
|
||||||
|
private const int RTLD_LAZY = 1;
|
||||||
|
private const int RTLD_NOW = 2;
|
||||||
|
|
||||||
|
public static IntPtr dlopen (string path, bool lazy = true) =>
|
||||||
|
dlopen (path, lazy ? RTLD_LAZY : RTLD_NOW);
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary)]
|
||||||
|
public static extern IntPtr dlopen (string path, int mode);
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary)]
|
||||||
|
public static extern IntPtr dlsym (IntPtr handle, string symbol);
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary)]
|
||||||
|
public static extern void dlclose (IntPtr handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Win32
|
||||||
|
{
|
||||||
|
private const string SystemLibrary = "Kernel32.dll";
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary, SetLastError = true, CharSet = CharSet.Ansi)]
|
||||||
|
public static extern IntPtr LoadLibrary (string lpFileName);
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary, SetLastError = true, CharSet = CharSet.Ansi)]
|
||||||
|
public static extern IntPtr GetProcAddress (IntPtr hModule, string lpProcName);
|
||||||
|
|
||||||
|
[DllImport (SystemLibrary, SetLastError = true, CharSet = CharSet.Ansi)]
|
||||||
|
public static extern void FreeLibrary (IntPtr hModule);
|
||||||
|
}
|
||||||
|
#pragma warning restore IDE1006 // Naming Styles
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
#if HARFBUZZ
|
#if HARFBUZZ
|
||||||
|
@ -11,20 +10,62 @@ namespace SkiaSharp
|
||||||
internal static class PlatformConfiguration
|
internal static class PlatformConfiguration
|
||||||
{
|
{
|
||||||
public static bool IsUnix { get; }
|
public static bool IsUnix { get; }
|
||||||
|
|
||||||
public static bool IsWindows { get; }
|
public static bool IsWindows { get; }
|
||||||
|
|
||||||
|
public static bool IsMac { get; }
|
||||||
|
|
||||||
|
public static bool IsLinux { get; }
|
||||||
|
|
||||||
static PlatformConfiguration ()
|
static PlatformConfiguration ()
|
||||||
{
|
{
|
||||||
#if WINDOWS_UWP
|
#if WINDOWS_UWP
|
||||||
|
IsMac = false;
|
||||||
|
IsLinux = false;
|
||||||
IsUnix = false;
|
IsUnix = false;
|
||||||
IsWindows = true;
|
IsWindows = true;
|
||||||
#elif NET_STANDARD
|
#elif NET_STANDARD || __NET_46__
|
||||||
IsUnix = RuntimeInformation.IsOSPlatform (OSPlatform.OSX) || RuntimeInformation.IsOSPlatform (OSPlatform.Linux);
|
IsMac = RuntimeInformation.IsOSPlatform (OSPlatform.OSX);
|
||||||
|
IsLinux = RuntimeInformation.IsOSPlatform (OSPlatform.Linux);
|
||||||
|
IsUnix = IsMac || IsLinux;
|
||||||
IsWindows = RuntimeInformation.IsOSPlatform (OSPlatform.Windows);
|
IsWindows = RuntimeInformation.IsOSPlatform (OSPlatform.Windows);
|
||||||
#else
|
#else
|
||||||
IsUnix = Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix;
|
IsUnix = Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix;
|
||||||
IsWindows = !IsUnix;
|
IsWindows = !IsUnix;
|
||||||
|
IsMac = IsUnix && MacPlatformDetector.IsMac.Value;
|
||||||
|
IsLinux = IsUnix && !IsMac;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !NET_STANDARD && !__NET_46__
|
||||||
|
#pragma warning disable IDE1006 // Naming Styles
|
||||||
|
private static class MacPlatformDetector
|
||||||
|
{
|
||||||
|
internal static readonly Lazy<bool> IsMac = new Lazy<bool> (IsRunningOnMac);
|
||||||
|
|
||||||
|
[DllImport ("libc")]
|
||||||
|
static extern int uname (IntPtr buf);
|
||||||
|
|
||||||
|
static bool IsRunningOnMac ()
|
||||||
|
{
|
||||||
|
IntPtr buf = IntPtr.Zero;
|
||||||
|
try {
|
||||||
|
buf = Marshal.AllocHGlobal (8192);
|
||||||
|
// This is a hacktastic way of getting sysname from uname ()
|
||||||
|
if (uname (buf) == 0) {
|
||||||
|
string os = Marshal.PtrToStringAnsi (buf);
|
||||||
|
if (os == "Darwin")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
} finally {
|
||||||
|
if (buf != IntPtr.Zero)
|
||||||
|
Marshal.FreeHGlobal (buf);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore IDE1006 // Naming Styles
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace SkiaSharp
|
using System;
|
||||||
|
|
||||||
|
namespace SkiaSharp
|
||||||
{
|
{
|
||||||
internal partial class SkiaApi
|
internal partial class SkiaApi
|
||||||
{
|
{
|
||||||
|
@ -21,5 +23,18 @@
|
||||||
#else
|
#else
|
||||||
private const string SKIA = "libSkiaSharp";
|
private const string SKIA = "libSkiaSharp";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if USE_DELEGATES
|
||||||
|
private static IntPtr libSkiaSharpHandle;
|
||||||
|
|
||||||
|
private static T Get<T> (string name)
|
||||||
|
where T : Delegate
|
||||||
|
{
|
||||||
|
if (libSkiaSharpHandle == IntPtr.Zero)
|
||||||
|
libSkiaSharpHandle = LibraryLoader.LoadLocalLibrary<SkiaApi> (SKIA);
|
||||||
|
|
||||||
|
return LibraryLoader.GetSymbolDelegate<T> (libSkiaSharpHandle, name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -152,7 +152,7 @@ namespace SkiaSharp
|
||||||
if (data.Length == 0)
|
if (data.Length == 0)
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
#if __DESKTOP__
|
#if __NET_45__
|
||||||
// TODO: improve this copy for old .NET 4.5
|
// TODO: improve this copy for old .NET 4.5
|
||||||
var array = data.ToArray ();
|
var array = data.ToArray ();
|
||||||
return encoding switch
|
return encoding switch
|
||||||
|
|
|
@ -8,8 +8,14 @@
|
||||||
<PropertyGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
|
<PropertyGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
|
||||||
<DefineConstants>$(DefineConstants);NET_STANDARD</DefineConstants>
|
<DefineConstants>$(DefineConstants);NET_STANDARD</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
|
||||||
|
<DefineConstants>$(DefineConstants);USE_DELEGATES;__DESKTOP__</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="$(TargetFramework.StartsWith('net45'))">
|
<PropertyGroup Condition="$(TargetFramework.StartsWith('net45'))">
|
||||||
<DefineConstants>$(DefineConstants);__DESKTOP__</DefineConstants>
|
<DefineConstants>$(DefineConstants);__NET_45__</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="$(TargetFramework.StartsWith('net46'))">
|
||||||
|
<DefineConstants>$(DefineConstants);__NET_46__</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
|
||||||
<PackageReference Include="System.IO.UnmanagedMemoryStream" Version="4.3.0" />
|
<PackageReference Include="System.IO.UnmanagedMemoryStream" Version="4.3.0" />
|
||||||
|
|
|
@ -100,10 +100,14 @@
|
||||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="..\..\output\native\windows\$(Platform)\libSkiaSharp.dll" CopyToOutputDirectory="Always" Visible="false"
|
<Content Include="..\..\output\native\windows\x64\libSkiaSharp.dll" Link="x64\libSkiaSharp.dll" CopyToOutputDirectory="Always" Visible="false"
|
||||||
Condition=" Exists('..\..\output\native\windows\$(Platform)\libSkiaSharp.dll') or '$(IsWindows)' == 'true' " />
|
Condition=" Exists('..\..\output\native\windows\x64\libSkiaSharp.dll') or '$(IsWindows)' == 'true' " />
|
||||||
<Content Include="..\..\output\native\windows\$(Platform)\libSkiaSharp.pdb" CopyToOutputDirectory="Always" Visible="false"
|
<Content Include="..\..\output\native\windows\x64\libSkiaSharp.pdb" Link="x64\libSkiaSharp.pdb" CopyToOutputDirectory="Always" Visible="false"
|
||||||
Condition=" Exists('..\..\output\native\windows\$(Platform)\libSkiaSharp.pdb') or '$(IsWindows)' == 'true' " />
|
Condition=" Exists('..\..\output\native\windows\x64\libSkiaSharp.pdb') or '$(IsWindows)' == 'true' " />
|
||||||
|
<Content Include="..\..\output\native\windows\x86\libSkiaSharp.dll" Link="x86\libSkiaSharp.dll" CopyToOutputDirectory="Always" Visible="false"
|
||||||
|
Condition=" Exists('..\..\output\native\windows\x86\libSkiaSharp.dll') or '$(IsWindows)' == 'true' " />
|
||||||
|
<Content Include="..\..\output\native\windows\x86\libSkiaSharp.pdb" Link="x86\libSkiaSharp.pdb" CopyToOutputDirectory="Always" Visible="false"
|
||||||
|
Condition=" Exists('..\..\output\native\windows\x64\libSkiaSharp.pdb') or '$(IsWindows)' == 'true' " />
|
||||||
<Content Include="..\..\output\native\windows\$(Platform)\libHarfBuzzSharp.dll" CopyToOutputDirectory="Always" Visible="false"
|
<Content Include="..\..\output\native\windows\$(Platform)\libHarfBuzzSharp.dll" CopyToOutputDirectory="Always" Visible="false"
|
||||||
Condition=" Exists('..\..\output\native\windows\$(Platform)\libHarfBuzzSharp.dll') or '$(IsWindows)' == 'true' " />
|
Condition=" Exists('..\..\output\native\windows\$(Platform)\libHarfBuzzSharp.dll') or '$(IsWindows)' == 'true' " />
|
||||||
<Content Include="..\..\output\native\windows\$(Platform)\libHarfBuzzSharp.pdb" CopyToOutputDirectory="Always" Visible="false"
|
<Content Include="..\..\output\native\windows\$(Platform)\libHarfBuzzSharp.pdb" CopyToOutputDirectory="Always" Visible="false"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
<DefineConstants>$(DefineConstants);NET_STANDARD</DefineConstants>
|
<DefineConstants>$(DefineConstants);NET_STANDARD;USE_LIBRARY_LOADER</DefineConstants>
|
||||||
<RootNamespace>SkiaSharp.Tests</RootNamespace>
|
<RootNamespace>SkiaSharp.Tests</RootNamespace>
|
||||||
<AssemblyName>SkiaSharp.Tests</AssemblyName>
|
<AssemblyName>SkiaSharp.Tests</AssemblyName>
|
||||||
<SkipGenerateAssemblyVersionInfo>true</SkipGenerateAssemblyVersionInfo>
|
<SkipGenerateAssemblyVersionInfo>true</SkipGenerateAssemblyVersionInfo>
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\Tests\**\*.cs" Link="%(RecursiveDir)%(FileName)%(Extension)" />
|
<Compile Include="..\Tests\**\*.cs" Link="%(RecursiveDir)%(FileName)%(Extension)" />
|
||||||
|
<Compile Include="..\..\binding\Binding.Shared\LibraryLoader.cs" Link="PlatformUtils\LibraryLoader.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="..\Content\**\*" Link="%(RecursiveDir)%(FileName)%(Extension)" CopyToOutputDirectory="Always" />
|
<Content Include="..\Content\**\*" Link="%(RecursiveDir)%(FileName)%(Extension)" CopyToOutputDirectory="Always" />
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace SkiaSharp.Tests
|
namespace SkiaSharp.Tests
|
||||||
{
|
{
|
||||||
|
@ -11,10 +10,10 @@ namespace SkiaSharp.Tests
|
||||||
protected const string GpuCategory = "GPU";
|
protected const string GpuCategory = "GPU";
|
||||||
protected const string MatchCharacterCategory = "MatchCharacter";
|
protected const string MatchCharacterCategory = "MatchCharacter";
|
||||||
|
|
||||||
protected static bool IsLinux;
|
protected static bool IsLinux = PlatformConfiguration.IsLinux;
|
||||||
protected static bool IsMac;
|
protected static bool IsMac = PlatformConfiguration.IsMac;
|
||||||
protected static bool IsUnix;
|
protected static bool IsUnix = PlatformConfiguration.IsUnix;
|
||||||
protected static bool IsWindows;
|
protected static bool IsWindows = PlatformConfiguration.IsWindows;
|
||||||
|
|
||||||
protected static bool IsRuntimeMono;
|
protected static bool IsRuntimeMono;
|
||||||
|
|
||||||
|
@ -54,19 +53,6 @@ namespace SkiaSharp.Tests
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// set the OS fields
|
|
||||||
#if NET_STANDARD
|
|
||||||
IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
|
||||||
IsMac = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
|
||||||
IsUnix = IsLinux || IsMac;
|
|
||||||
IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
|
||||||
#else
|
|
||||||
IsMac = MacPlatformDetector.IsMac.Value;
|
|
||||||
IsUnix = Environment.OSVersion.Platform == PlatformID.Unix || IsMac;
|
|
||||||
IsLinux = IsUnix && !IsMac;
|
|
||||||
IsWindows = !IsUnix;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
IsRuntimeMono = Type.GetType("Mono.Runtime") != null;
|
IsRuntimeMono = Type.GetType("Mono.Runtime") != null;
|
||||||
|
|
||||||
// set the test fields
|
// set the test fields
|
||||||
|
@ -82,71 +68,5 @@ namespace SkiaSharp.Tests
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
GC.WaitForPendingFinalizers();
|
GC.WaitForPendingFinalizers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MacPlatformDetector
|
|
||||||
{
|
|
||||||
internal static readonly Lazy<bool> IsMac = new Lazy<bool>(IsRunningOnMac);
|
|
||||||
|
|
||||||
[DllImport("libc")]
|
|
||||||
static extern int uname(IntPtr buf);
|
|
||||||
|
|
||||||
static bool IsRunningOnMac()
|
|
||||||
{
|
|
||||||
IntPtr buf = IntPtr.Zero;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
buf = Marshal.AllocHGlobal(8192);
|
|
||||||
// This is a hacktastic way of getting sysname from uname ()
|
|
||||||
if (uname(buf) == 0)
|
|
||||||
{
|
|
||||||
string os = Marshal.PtrToStringAnsi(buf);
|
|
||||||
if (os == "Darwin")
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (buf != IntPtr.Zero)
|
|
||||||
Marshal.FreeHGlobal(buf);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MacDynamicLibraries
|
|
||||||
{
|
|
||||||
private const string SystemLibrary = "/usr/lib/libSystem.dylib";
|
|
||||||
[DllImport(SystemLibrary)]
|
|
||||||
public static extern IntPtr dlopen(string path, int mode);
|
|
||||||
[DllImport(SystemLibrary)]
|
|
||||||
public static extern IntPtr dlsym(IntPtr handle, string symbol);
|
|
||||||
[DllImport(SystemLibrary)]
|
|
||||||
public static extern void dlclose(IntPtr handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LinuxDynamicLibraries
|
|
||||||
{
|
|
||||||
private const string SystemLibrary = "libdl.so";
|
|
||||||
[DllImport(SystemLibrary)]
|
|
||||||
public static extern IntPtr dlopen(string path, int mode);
|
|
||||||
[DllImport(SystemLibrary)]
|
|
||||||
public static extern IntPtr dlsym(IntPtr handle, string symbol);
|
|
||||||
[DllImport(SystemLibrary)]
|
|
||||||
public static extern void dlclose(IntPtr handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class WindowsDynamicLibraries
|
|
||||||
{
|
|
||||||
private const string SystemLibrary = "Kernel32.dll";
|
|
||||||
[DllImport(SystemLibrary, SetLastError = true, CharSet = CharSet.Ansi)]
|
|
||||||
public static extern IntPtr LoadLibrary(string lpFileName);
|
|
||||||
[DllImport(SystemLibrary, SetLastError = true, CharSet = CharSet.Ansi)]
|
|
||||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
|
|
||||||
[DllImport(SystemLibrary, SetLastError = true, CharSet = CharSet.Ansi)]
|
|
||||||
public static extern void FreeLibrary(IntPtr hModule);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,21 +37,21 @@ namespace SkiaSharp.Tests
|
||||||
ctx.MakeCurrent();
|
ctx.MakeCurrent();
|
||||||
|
|
||||||
if (IsMac) {
|
if (IsMac) {
|
||||||
var lib = MacDynamicLibraries.dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", 1);
|
var lib = LibraryLoader.LoadLibrary("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib");
|
||||||
|
|
||||||
var glInterface = GRGlInterface.Create(name => {
|
var glInterface = GRGlInterface.Create(name => {
|
||||||
return MacDynamicLibraries.dlsym(lib, name);
|
return LibraryLoader.GetSymbol(lib, name);
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.NotNull(glInterface);
|
Assert.NotNull(glInterface);
|
||||||
Assert.True(glInterface.Validate());
|
Assert.True(glInterface.Validate());
|
||||||
|
|
||||||
MacDynamicLibraries.dlclose(lib);
|
LibraryLoader.FreeLibrary(lib);
|
||||||
} else if (IsWindows) {
|
} else if (IsWindows) {
|
||||||
var lib = WindowsDynamicLibraries.LoadLibrary("opengl32.dll");
|
var lib = LibraryLoader.LoadLibrary("opengl32.dll");
|
||||||
|
|
||||||
var glInterface = GRGlInterface.Create(name => {
|
var glInterface = GRGlInterface.Create(name => {
|
||||||
var ptr = WindowsDynamicLibraries.GetProcAddress(lib, name);
|
var ptr = LibraryLoader.GetSymbol(lib, name);
|
||||||
if (ptr == IntPtr.Zero) {
|
if (ptr == IntPtr.Zero) {
|
||||||
ptr = wglGetProcAddress(name);
|
ptr = wglGetProcAddress(name);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ namespace SkiaSharp.Tests
|
||||||
Assert.NotNull(glInterface);
|
Assert.NotNull(glInterface);
|
||||||
Assert.True(glInterface.Validate());
|
Assert.True(glInterface.Validate());
|
||||||
|
|
||||||
WindowsDynamicLibraries.FreeLibrary(lib);
|
LibraryLoader.FreeLibrary(lib);
|
||||||
} else if (IsLinux) {
|
} else if (IsLinux) {
|
||||||
var glInterface = GRGlInterface.Create(name => {
|
var glInterface = GRGlInterface.Create(name => {
|
||||||
return glXGetProcAddress(name);
|
return glXGetProcAddress(name);
|
||||||
|
|
|
@ -333,14 +333,11 @@ namespace SkiaSharpGenerator
|
||||||
{
|
{
|
||||||
Log?.LogVerbose($" {function.Name}");
|
Log?.LogVerbose($" {function.Name}");
|
||||||
|
|
||||||
writer.WriteLine();
|
|
||||||
writer.WriteLine($"\t\t// {function}");
|
|
||||||
writer.WriteLine($"\t\t[DllImport ({config.DllName}, CallingConvention = CallingConvention.Cdecl)]");
|
|
||||||
|
|
||||||
var name = function.Name;
|
var name = function.Name;
|
||||||
functionMappings.TryGetValue(name, out var funcMap);
|
functionMappings.TryGetValue(name, out var funcMap);
|
||||||
|
|
||||||
var paramsList = new List<string>();
|
var paramsList = new List<string>();
|
||||||
|
var paramNamesList = new List<string>();
|
||||||
for (var i = 0; i < function.Parameters.Count; i++)
|
for (var i = 0; i < function.Parameters.Count; i++)
|
||||||
{
|
{
|
||||||
var p = function.Parameters[i];
|
var p = function.Parameters[i];
|
||||||
|
@ -352,9 +349,11 @@ namespace SkiaSharpGenerator
|
||||||
if (funcMap != null && funcMap.Parameters.TryGetValue(i.ToString(), out var newT))
|
if (funcMap != null && funcMap.Parameters.TryGetValue(i.ToString(), out var newT))
|
||||||
t = newT;
|
t = newT;
|
||||||
paramsList.Add($"{t} {n}");
|
paramsList.Add($"{t} {n}");
|
||||||
|
paramNamesList.Add(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnType = GetType(function.ReturnType);
|
var returnType = GetType(function.ReturnType);
|
||||||
|
var retAttr = "";
|
||||||
if (funcMap != null && funcMap.Parameters.TryGetValue("-1", out var newR))
|
if (funcMap != null && funcMap.Parameters.TryGetValue("-1", out var newR))
|
||||||
{
|
{
|
||||||
returnType = newR;
|
returnType = newR;
|
||||||
|
@ -362,9 +361,27 @@ namespace SkiaSharpGenerator
|
||||||
else if (GetCppType(function.ReturnType) == "bool")
|
else if (GetCppType(function.ReturnType) == "bool")
|
||||||
{
|
{
|
||||||
returnType = "bool";
|
returnType = "bool";
|
||||||
writer.WriteLine($"\t\t[return: MarshalAs (UnmanagedType.I1)]");
|
retAttr = $"[return: MarshalAs (UnmanagedType.I1)]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer.WriteLine();
|
||||||
|
writer.WriteLine($"\t\t// {function}");
|
||||||
|
writer.WriteLine($"\t\t#if !USE_DELEGATES");
|
||||||
|
writer.WriteLine($"\t\t[DllImport ({config.DllName}, CallingConvention = CallingConvention.Cdecl)]");
|
||||||
|
if (!string.IsNullOrEmpty(retAttr))
|
||||||
|
writer.WriteLine($"\t\t{retAttr}");
|
||||||
writer.WriteLine($"\t\tinternal static extern {returnType} {name} ({string.Join(", ", paramsList)});");
|
writer.WriteLine($"\t\tinternal static extern {returnType} {name} ({string.Join(", ", paramsList)});");
|
||||||
|
writer.WriteLine($"\t\t#else");
|
||||||
|
writer.WriteLine($"\t\tprivate partial class Delegates {{");
|
||||||
|
writer.WriteLine($"\t\t\t[UnmanagedFunctionPointer(CallingConvention.Cdecl)]");
|
||||||
|
if (!string.IsNullOrEmpty(retAttr))
|
||||||
|
writer.WriteLine($"\t\t\t{retAttr}");
|
||||||
|
writer.WriteLine($"\t\t\tinternal delegate {returnType} {name} ({string.Join(", ", paramsList)});");
|
||||||
|
writer.WriteLine($"\t\t}}");
|
||||||
|
writer.WriteLine($"\t\tprivate static Delegates.{name} {name}_delegate;");
|
||||||
|
writer.WriteLine($"\t\tinternal static {returnType} {name} ({string.Join(", ", paramsList)}) =>");
|
||||||
|
writer.WriteLine($"\t\t\t({name}_delegate ??= Get<Delegates.{name}>(\"{name}\")).Invoke({string.Join(", ", paramNamesList)});");
|
||||||
|
writer.WriteLine($"\t\t#endif");
|
||||||
}
|
}
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
writer.WriteLine($"\t\t#endregion");
|
writer.WriteLine($"\t\t#endregion");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче