Merge pull request #894 from filmor/drop-mono-linux-flag
Get the correct library loading functions at runtime
This commit is contained in:
Коммит
7595fda74a
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using Python.Runtime;
|
||||
using Python.Runtime.Platform;
|
||||
|
||||
namespace Python.EmbeddingTest
|
||||
{
|
||||
|
@ -26,10 +27,10 @@ namespace Python.EmbeddingTest
|
|||
{
|
||||
Runtime.Runtime.Initialize();
|
||||
|
||||
Assert.That(Runtime.Runtime.Machine, Is.Not.EqualTo(Runtime.Runtime.MachineType.Other));
|
||||
Assert.That(Runtime.Runtime.Machine, Is.Not.EqualTo(MachineType.Other));
|
||||
Assert.That(!string.IsNullOrEmpty(Runtime.Runtime.MachineName));
|
||||
|
||||
Assert.That(Runtime.Runtime.OperatingSystem, Is.Not.EqualTo(Runtime.Runtime.OperatingSystemType.Other));
|
||||
Assert.That(Runtime.Runtime.OperatingSystem, Is.Not.EqualTo(OperatingSystemType.Other));
|
||||
Assert.That(!string.IsNullOrEmpty(Runtime.Runtime.OperatingSystemName));
|
||||
|
||||
// Don't shut down the runtime: if the python engine was initialized
|
||||
|
@ -39,7 +40,7 @@ namespace Python.EmbeddingTest
|
|||
[Test]
|
||||
public static void Py_IsInitializedValue()
|
||||
{
|
||||
Runtime.Runtime.Py_Finalize();
|
||||
Runtime.Runtime.Py_Finalize();
|
||||
Assert.AreEqual(0, Runtime.Runtime.Py_IsInitialized());
|
||||
Runtime.Runtime.Py_Initialize();
|
||||
Assert.AreEqual(1, Runtime.Runtime.Py_IsInitialized());
|
||||
|
|
|
@ -140,6 +140,8 @@
|
|||
<Compile Include="typemanager.cs" />
|
||||
<Compile Include="typemethod.cs" />
|
||||
<Compile Include="Util.cs" />
|
||||
<Compile Include="platform\Types.cs" />
|
||||
<Compile Include="platform\LibraryLoader.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(PythonInteropFile)' != '' ">
|
||||
<Compile Include="$(PythonInteropFile)" />
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime.Platform
|
||||
{
|
||||
interface ILibraryLoader
|
||||
{
|
||||
IntPtr Load(string dllToLoad);
|
||||
|
||||
IntPtr GetFunction(IntPtr hModule, string procedureName);
|
||||
|
||||
void Free(IntPtr hModule);
|
||||
}
|
||||
|
||||
static class LibraryLoader
|
||||
{
|
||||
public static ILibraryLoader Get(OperatingSystemType os)
|
||||
{
|
||||
switch (os)
|
||||
{
|
||||
case OperatingSystemType.Windows:
|
||||
return new WindowsLoader();
|
||||
case OperatingSystemType.Darwin:
|
||||
return new DarwinLoader();
|
||||
case OperatingSystemType.Linux:
|
||||
return new LinuxLoader();
|
||||
default:
|
||||
throw new PlatformNotSupportedException($"This operating system ({os}) is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LinuxLoader : ILibraryLoader
|
||||
{
|
||||
private static int RTLD_NOW = 0x2;
|
||||
private static int RTLD_GLOBAL = 0x100;
|
||||
private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
|
||||
private const string NativeDll = "libdl.so";
|
||||
|
||||
public IntPtr Load(string dllToLoad)
|
||||
{
|
||||
var filename = $"lib{dllToLoad}.so";
|
||||
ClearError();
|
||||
var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (res == IntPtr.Zero)
|
||||
{
|
||||
var err = GetError();
|
||||
throw new DllNotFoundException($"Could not load {filename} with flags RTLD_NOW | RTLD_GLOBAL: {err}");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void Free(IntPtr handle)
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
public IntPtr GetFunction(IntPtr dllHandle, string name)
|
||||
{
|
||||
// look in the exe if dllHandle is NULL
|
||||
if (dllHandle == IntPtr.Zero)
|
||||
{
|
||||
dllHandle = RTLD_DEFAULT;
|
||||
}
|
||||
|
||||
ClearError();
|
||||
IntPtr res = dlsym(dllHandle, name);
|
||||
if (res == IntPtr.Zero)
|
||||
{
|
||||
var err = GetError();
|
||||
throw new MissingMethodException($"Failed to load symbol {name}: {err}");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ClearError()
|
||||
{
|
||||
dlerror();
|
||||
}
|
||||
|
||||
string GetError()
|
||||
{
|
||||
var res = dlerror();
|
||||
if (res != IntPtr.Zero)
|
||||
return Marshal.PtrToStringAnsi(res);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
public static extern IntPtr dlopen(string fileName, int flags);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
private static extern IntPtr dlsym(IntPtr handle, string symbol);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int dlclose(IntPtr handle);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr dlerror();
|
||||
}
|
||||
|
||||
class DarwinLoader : ILibraryLoader
|
||||
{
|
||||
private static int RTLD_NOW = 0x2;
|
||||
private static int RTLD_GLOBAL = 0x8;
|
||||
private const string NativeDll = "/usr/lib/libSystem.dylib";
|
||||
private static IntPtr RTLD_DEFAULT = new IntPtr(-2);
|
||||
|
||||
public IntPtr Load(string dllToLoad)
|
||||
{
|
||||
var filename = $"lib{dllToLoad}.dylib";
|
||||
ClearError();
|
||||
var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (res == IntPtr.Zero)
|
||||
{
|
||||
var err = GetError();
|
||||
throw new DllNotFoundException($"Could not load {filename} with flags RTLD_NOW | RTLD_GLOBAL: {err}");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void Free(IntPtr handle)
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
public IntPtr GetFunction(IntPtr dllHandle, string name)
|
||||
{
|
||||
// look in the exe if dllHandle is NULL
|
||||
if (dllHandle == IntPtr.Zero)
|
||||
{
|
||||
dllHandle = RTLD_DEFAULT;
|
||||
}
|
||||
|
||||
ClearError();
|
||||
IntPtr res = dlsym(dllHandle, name);
|
||||
if (res == IntPtr.Zero)
|
||||
{
|
||||
var err = GetError();
|
||||
throw new MissingMethodException($"Failed to load symbol {name}: {err}");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ClearError()
|
||||
{
|
||||
dlerror();
|
||||
}
|
||||
|
||||
string GetError()
|
||||
{
|
||||
var res = dlerror();
|
||||
if (res != IntPtr.Zero)
|
||||
return Marshal.PtrToStringAnsi(res);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
public static extern IntPtr dlopen(String fileName, int flags);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
private static extern IntPtr dlsym(IntPtr handle, String symbol);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int dlclose(IntPtr handle);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr dlerror();
|
||||
}
|
||||
|
||||
class WindowsLoader : ILibraryLoader
|
||||
{
|
||||
private const string NativeDll = "kernel32.dll";
|
||||
|
||||
|
||||
public IntPtr Load(string dllToLoad)
|
||||
{
|
||||
var res = WindowsLoader.LoadLibrary(dllToLoad);
|
||||
if (res == IntPtr.Zero)
|
||||
throw new DllNotFoundException($"Could not load {dllToLoad}", new Win32Exception());
|
||||
return res;
|
||||
}
|
||||
|
||||
public IntPtr GetFunction(IntPtr hModule, string procedureName)
|
||||
{
|
||||
var res = WindowsLoader.GetProcAddress(hModule, procedureName);
|
||||
if (res == IntPtr.Zero)
|
||||
throw new MissingMethodException($"Failed to load symbol {procedureName}", new Win32Exception());
|
||||
return res;
|
||||
}
|
||||
|
||||
public void Free(IntPtr hModule) => WindowsLoader.FreeLibrary(hModule);
|
||||
|
||||
[DllImport(NativeDll, SetLastError = true)]
|
||||
static extern IntPtr LoadLibrary(string dllToLoad);
|
||||
|
||||
[DllImport(NativeDll, SetLastError = true)]
|
||||
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
||||
|
||||
[DllImport(NativeDll)]
|
||||
static extern bool FreeLibrary(IntPtr hModule);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
namespace Python.Runtime.Platform
|
||||
{
|
||||
public enum MachineType
|
||||
{
|
||||
i386,
|
||||
x86_64,
|
||||
armv7l,
|
||||
armv8,
|
||||
Other
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Operating system type as reported by Python.
|
||||
/// </summary>
|
||||
public enum OperatingSystemType
|
||||
{
|
||||
Windows,
|
||||
Darwin,
|
||||
Linux,
|
||||
Other
|
||||
}
|
||||
}
|
|
@ -4,99 +4,10 @@ using System.Security;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using Python.Runtime.Platform;
|
||||
|
||||
namespace Python.Runtime
|
||||
{
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
internal static class NativeMethods
|
||||
{
|
||||
#if MONO_LINUX || MONO_OSX
|
||||
#if NETSTANDARD
|
||||
private static int RTLD_NOW = 0x2;
|
||||
#if MONO_LINUX
|
||||
private static int RTLD_GLOBAL = 0x100;
|
||||
private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
|
||||
private const string NativeDll = "libdl.so";
|
||||
public static IntPtr LoadLibrary(string fileName)
|
||||
{
|
||||
return dlopen($"lib{fileName}.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
}
|
||||
#elif MONO_OSX
|
||||
private static int RTLD_GLOBAL = 0x8;
|
||||
private const string NativeDll = "/usr/lib/libSystem.dylib";
|
||||
private static IntPtr RTLD_DEFAULT = new IntPtr(-2);
|
||||
|
||||
public static IntPtr LoadLibrary(string fileName)
|
||||
{
|
||||
return dlopen($"lib{fileName}.dylib", RTLD_NOW | RTLD_GLOBAL);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
private static int RTLD_NOW = 0x2;
|
||||
private static int RTLD_SHARED = 0x20;
|
||||
#if MONO_OSX
|
||||
private static IntPtr RTLD_DEFAULT = new IntPtr(-2);
|
||||
private const string NativeDll = "__Internal";
|
||||
#elif MONO_LINUX
|
||||
private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
|
||||
private const string NativeDll = "libdl.so";
|
||||
#endif
|
||||
|
||||
public static IntPtr LoadLibrary(string fileName)
|
||||
{
|
||||
return dlopen(fileName, RTLD_NOW | RTLD_SHARED);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
public static void FreeLibrary(IntPtr handle)
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
public static IntPtr GetProcAddress(IntPtr dllHandle, string name)
|
||||
{
|
||||
// look in the exe if dllHandle is NULL
|
||||
if (dllHandle == IntPtr.Zero)
|
||||
{
|
||||
dllHandle = RTLD_DEFAULT;
|
||||
}
|
||||
|
||||
// clear previous errors if any
|
||||
dlerror();
|
||||
IntPtr res = dlsym(dllHandle, name);
|
||||
IntPtr errPtr = dlerror();
|
||||
if (errPtr != IntPtr.Zero)
|
||||
{
|
||||
throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
public static extern IntPtr dlopen(String fileName, int flags);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
private static extern IntPtr dlsym(IntPtr handle, String symbol);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int dlclose(IntPtr handle);
|
||||
|
||||
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr dlerror();
|
||||
#else // Windows
|
||||
private const string NativeDll = "kernel32.dll";
|
||||
|
||||
[DllImport(NativeDll)]
|
||||
public static extern IntPtr LoadLibrary(string dllToLoad);
|
||||
|
||||
[DllImport(NativeDll)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
||||
|
||||
[DllImport(NativeDll)]
|
||||
public static extern bool FreeLibrary(IntPtr hModule);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates the low-level Python C API. Note that it is
|
||||
|
@ -197,17 +108,6 @@ namespace Python.Runtime
|
|||
// .NET core: System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
internal static bool IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT;
|
||||
|
||||
/// <summary>
|
||||
/// Operating system type as reported by Python.
|
||||
/// </summary>
|
||||
public enum OperatingSystemType
|
||||
{
|
||||
Windows,
|
||||
Darwin,
|
||||
Linux,
|
||||
Other
|
||||
}
|
||||
|
||||
static readonly Dictionary<string, OperatingSystemType> OperatingSystemTypeMapping = new Dictionary<string, OperatingSystemType>()
|
||||
{
|
||||
{ "Windows", OperatingSystemType.Windows },
|
||||
|
@ -225,14 +125,6 @@ namespace Python.Runtime
|
|||
/// </summary>
|
||||
public static string OperatingSystemName { get; private set; }
|
||||
|
||||
public enum MachineType
|
||||
{
|
||||
i386,
|
||||
x86_64,
|
||||
armv7l,
|
||||
armv8,
|
||||
Other
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Map lower-case version of the python machine name to the processor
|
||||
|
@ -397,25 +289,25 @@ namespace Python.Runtime
|
|||
|
||||
Error = new IntPtr(-1);
|
||||
|
||||
IntPtr dllLocal = IntPtr.Zero;
|
||||
|
||||
if (_PythonDll != "__Internal")
|
||||
{
|
||||
dllLocal = NativeMethods.LoadLibrary(_PythonDll);
|
||||
}
|
||||
_PyObject_NextNotImplemented = NativeMethods.GetProcAddress(dllLocal, "_PyObject_NextNotImplemented");
|
||||
|
||||
#if !(MONO_LINUX || MONO_OSX)
|
||||
if (dllLocal != IntPtr.Zero)
|
||||
{
|
||||
NativeMethods.FreeLibrary(dllLocal);
|
||||
}
|
||||
#endif
|
||||
// Initialize data about the platform we're running on. We need
|
||||
// this for the type manager and potentially other details. Must
|
||||
// happen after caching the python types, above.
|
||||
InitializePlatformData();
|
||||
|
||||
IntPtr dllLocal = IntPtr.Zero;
|
||||
var loader = LibraryLoader.Get(OperatingSystem);
|
||||
|
||||
if (_PythonDll != "__Internal")
|
||||
{
|
||||
dllLocal = loader.Load(_PythonDll);
|
||||
}
|
||||
_PyObject_NextNotImplemented = loader.GetFunction(dllLocal, "_PyObject_NextNotImplemented");
|
||||
|
||||
if (dllLocal != IntPtr.Zero)
|
||||
{
|
||||
loader.Free(dllLocal);
|
||||
}
|
||||
|
||||
// Initialize modules that depend on the runtime class.
|
||||
AssemblyManager.Initialize();
|
||||
PyCLRMetaType = MetaType.Initialize();
|
||||
|
|
|
@ -3,9 +3,11 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Python.Runtime.Platform;
|
||||
|
||||
namespace Python.Runtime
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The TypeManager class is responsible for building binary-compatible
|
||||
/// Python type objects that are implemented in managed code.
|
||||
|
@ -504,15 +506,15 @@ namespace Python.Runtime
|
|||
{
|
||||
get
|
||||
{
|
||||
switch(Runtime.Machine)
|
||||
switch (Runtime.Machine)
|
||||
{
|
||||
case Runtime.MachineType.i386:
|
||||
case MachineType.i386:
|
||||
return I386;
|
||||
case Runtime.MachineType.x86_64:
|
||||
case MachineType.x86_64:
|
||||
return X86_64;
|
||||
case Runtime.MachineType.armv7l:
|
||||
case MachineType.armv7l:
|
||||
return Armv7l;
|
||||
case Runtime.MachineType.armv8:
|
||||
case MachineType.armv8:
|
||||
return Armv8;
|
||||
default:
|
||||
throw new NotImplementedException($"No support for {Runtime.MachineName}");
|
||||
|
@ -635,9 +637,9 @@ namespace Python.Runtime
|
|||
{
|
||||
switch (Runtime.OperatingSystem)
|
||||
{
|
||||
case Runtime.OperatingSystemType.Darwin:
|
||||
case OperatingSystemType.Darwin:
|
||||
return 0x1000;
|
||||
case Runtime.OperatingSystemType.Linux:
|
||||
case OperatingSystemType.Linux:
|
||||
return 0x20;
|
||||
default:
|
||||
throw new NotImplementedException($"mmap is not supported on {Runtime.OperatingSystemName}");
|
||||
|
@ -668,10 +670,10 @@ namespace Python.Runtime
|
|||
{
|
||||
switch (Runtime.OperatingSystem)
|
||||
{
|
||||
case Runtime.OperatingSystemType.Darwin:
|
||||
case Runtime.OperatingSystemType.Linux:
|
||||
case OperatingSystemType.Darwin:
|
||||
case OperatingSystemType.Linux:
|
||||
return new UnixMemoryMapper();
|
||||
case Runtime.OperatingSystemType.Windows:
|
||||
case OperatingSystemType.Windows:
|
||||
return new WindowsMemoryMapper();
|
||||
default:
|
||||
throw new NotImplementedException($"No support for {Runtime.OperatingSystemName}");
|
||||
|
|
Загрузка…
Ссылка в новой задаче