Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1dd2ee1

Browse files
committed
Get the correct library loading functions at runtime
1 parent fc7d8a4 commit 1dd2ee1

File tree

6 files changed

+203
-131
lines changed

6 files changed

+203
-131
lines changed

src/embed_tests/TestRuntime.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using NUnit.Framework;
33
using Python.Runtime;
4+
using Python.Runtime.Platform;
45

56
namespace Python.EmbeddingTest
67
{
@@ -26,10 +27,10 @@ public static void PlatformCache()
2627
{
2728
Runtime.Runtime.Initialize();
2829

29-
Assert.That(Runtime.Runtime.Machine, Is.Not.EqualTo(Runtime.Runtime.MachineType.Other));
30+
Assert.That(Runtime.Runtime.Machine, Is.Not.EqualTo(MachineType.Other));
3031
Assert.That(!string.IsNullOrEmpty(Runtime.Runtime.MachineName));
3132

32-
Assert.That(Runtime.Runtime.OperatingSystem, Is.Not.EqualTo(Runtime.Runtime.OperatingSystemType.Other));
33+
Assert.That(Runtime.Runtime.OperatingSystem, Is.Not.EqualTo(OperatingSystemType.Other));
3334
Assert.That(!string.IsNullOrEmpty(Runtime.Runtime.OperatingSystemName));
3435

3536
// Don't shut down the runtime: if the python engine was initialized
@@ -39,7 +40,7 @@ public static void PlatformCache()
3940
[Test]
4041
public static void Py_IsInitializedValue()
4142
{
42-
Runtime.Runtime.Py_Finalize();
43+
Runtime.Runtime.Py_Finalize();
4344
Assert.AreEqual(0, Runtime.Runtime.Py_IsInitialized());
4445
Runtime.Runtime.Py_Initialize();
4546
Assert.AreEqual(1, Runtime.Runtime.Py_IsInitialized());

src/runtime/Python.Runtime.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@
140140
<Compile Include="typemanager.cs" />
141141
<Compile Include="typemethod.cs" />
142142
<Compile Include="Util.cs" />
143+
<Compile Include="platform\Types.cs" />
144+
<Compile Include="platform\LibraryLoader.cs" />
143145
</ItemGroup>
144146
<ItemGroup Condition=" '$(PythonInteropFile)' != '' ">
145147
<Compile Include="$(PythonInteropFile)" />

src/runtime/platform/LibraryLoader.cs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace Python.Runtime.Platform
5+
{
6+
interface ILibraryLoader
7+
{
8+
IntPtr Load(string dllToLoad);
9+
10+
IntPtr GetFunction(IntPtr hModule, string procedureName);
11+
12+
bool Free(IntPtr hModule);
13+
}
14+
15+
static class LibraryLoader
16+
{
17+
public static ILibraryLoader Get(OperatingSystemType os)
18+
{
19+
switch (os)
20+
{
21+
case OperatingSystemType.Windows:
22+
return new WindowsLoader();
23+
case OperatingSystemType.Darwin:
24+
return new DarwinLoader();
25+
case OperatingSystemType.Linux:
26+
return new LinuxLoader();
27+
default:
28+
throw new Exception($"This operating system ({os}) is not supported");
29+
}
30+
}
31+
}
32+
33+
class LinuxLoader : ILibraryLoader
34+
{
35+
private static int RTLD_NOW = 0x2;
36+
private static int RTLD_GLOBAL = 0x100;
37+
private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
38+
private const string NativeDll = "libdl.so";
39+
40+
public IntPtr Load(string fileName)
41+
{
42+
return dlopen($"lib{fileName}.so", RTLD_NOW | RTLD_GLOBAL);
43+
}
44+
45+
public bool Free(IntPtr handle)
46+
{
47+
dlclose(handle);
48+
return true;
49+
}
50+
51+
public IntPtr GetFunction(IntPtr dllHandle, string name)
52+
{
53+
// look in the exe if dllHandle is NULL
54+
if (dllHandle == IntPtr.Zero)
55+
{
56+
dllHandle = RTLD_DEFAULT;
57+
}
58+
59+
// clear previous errors if any
60+
dlerror();
61+
IntPtr res = dlsym(dllHandle, name);
62+
IntPtr errPtr = dlerror();
63+
if (errPtr != IntPtr.Zero)
64+
{
65+
throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
66+
}
67+
return res;
68+
}
69+
70+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
71+
public static extern IntPtr dlopen(String fileName, int flags);
72+
73+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
74+
private static extern IntPtr dlsym(IntPtr handle, String symbol);
75+
76+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
77+
private static extern int dlclose(IntPtr handle);
78+
79+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
80+
private static extern IntPtr dlerror();
81+
}
82+
83+
class DarwinLoader : ILibraryLoader
84+
{
85+
private static int RTLD_NOW = 0x2;
86+
private static int RTLD_GLOBAL = 0x8;
87+
private const string NativeDll = "/usr/lib/libSystem.dylib";
88+
private static IntPtr RTLD_DEFAULT = new IntPtr(-2);
89+
90+
public IntPtr Load(string fileName)
91+
{
92+
return dlopen($"lib{fileName}.dylib", RTLD_NOW | RTLD_GLOBAL);
93+
}
94+
95+
public bool Free(IntPtr handle)
96+
{
97+
dlclose(handle);
98+
return true;
99+
}
100+
101+
public IntPtr GetFunction(IntPtr dllHandle, string name)
102+
{
103+
// look in the exe if dllHandle is NULL
104+
if (dllHandle == IntPtr.Zero)
105+
{
106+
dllHandle = RTLD_DEFAULT;
107+
}
108+
109+
// clear previous errors if any
110+
dlerror();
111+
IntPtr res = dlsym(dllHandle, name);
112+
IntPtr errPtr = dlerror();
113+
if (errPtr != IntPtr.Zero)
114+
{
115+
throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
116+
}
117+
return res;
118+
}
119+
120+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
121+
public static extern IntPtr dlopen(String fileName, int flags);
122+
123+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
124+
private static extern IntPtr dlsym(IntPtr handle, String symbol);
125+
126+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
127+
private static extern int dlclose(IntPtr handle);
128+
129+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
130+
private static extern IntPtr dlerror();
131+
}
132+
133+
class WindowsLoader : ILibraryLoader
134+
{
135+
private const string NativeDll = "kernel32.dll";
136+
137+
[DllImport(NativeDll)]
138+
static extern IntPtr LoadLibrary(string dllToLoad);
139+
140+
public IntPtr Load(string dllToLoad) => WindowsLoader.LoadLibrary(dllToLoad);
141+
142+
[DllImport(NativeDll)]
143+
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
144+
145+
public IntPtr GetFunction(IntPtr hModule, string procedureName) => WindowsLoader.GetProcAddress(hModule, procedureName);
146+
147+
148+
[DllImport(NativeDll)]
149+
static extern bool FreeLibrary(IntPtr hModule);
150+
151+
public bool Free(IntPtr hModule) => WindowsLoader.FreeLibrary(hModule);
152+
}
153+
}

src/runtime/platform/Types.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace Python.Runtime.Platform
2+
{
3+
public enum MachineType
4+
{
5+
i386,
6+
x86_64,
7+
armv7l,
8+
armv8,
9+
Other
10+
};
11+
12+
/// <summary>
13+
/// Operating system type as reported by Python.
14+
/// </summary>
15+
public enum OperatingSystemType
16+
{
17+
Windows,
18+
Darwin,
19+
Linux,
20+
Other
21+
}
22+
}

src/runtime/runtime.cs

Lines changed: 10 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -7,96 +7,7 @@
77

88
namespace Python.Runtime
99
{
10-
[SuppressUnmanagedCodeSecurity]
11-
internal static class NativeMethods
12-
{
13-
#if MONO_LINUX || MONO_OSX
14-
#if NETSTANDARD
15-
private static int RTLD_NOW = 0x2;
16-
#if MONO_LINUX
17-
private static int RTLD_GLOBAL = 0x100;
18-
private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
19-
private const string NativeDll = "libdl.so";
20-
public static IntPtr LoadLibrary(string fileName)
21-
{
22-
return dlopen($"lib{fileName}.so", RTLD_NOW | RTLD_GLOBAL);
23-
}
24-
#elif MONO_OSX
25-
private static int RTLD_GLOBAL = 0x8;
26-
private const string NativeDll = "/usr/lib/libSystem.dylib";
27-
private static IntPtr RTLD_DEFAULT = new IntPtr(-2);
28-
29-
public static IntPtr LoadLibrary(string fileName)
30-
{
31-
return dlopen($"lib{fileName}.dylib", RTLD_NOW | RTLD_GLOBAL);
32-
}
33-
#endif
34-
#else
35-
private static int RTLD_NOW = 0x2;
36-
private static int RTLD_SHARED = 0x20;
37-
#if MONO_OSX
38-
private static IntPtr RTLD_DEFAULT = new IntPtr(-2);
39-
private const string NativeDll = "__Internal";
40-
#elif MONO_LINUX
41-
private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
42-
private const string NativeDll = "libdl.so";
43-
#endif
44-
45-
public static IntPtr LoadLibrary(string fileName)
46-
{
47-
return dlopen(fileName, RTLD_NOW | RTLD_SHARED);
48-
}
49-
#endif
50-
51-
52-
public static void FreeLibrary(IntPtr handle)
53-
{
54-
dlclose(handle);
55-
}
56-
57-
public static IntPtr GetProcAddress(IntPtr dllHandle, string name)
58-
{
59-
// look in the exe if dllHandle is NULL
60-
if (dllHandle == IntPtr.Zero)
61-
{
62-
dllHandle = RTLD_DEFAULT;
63-
}
64-
65-
// clear previous errors if any
66-
dlerror();
67-
IntPtr res = dlsym(dllHandle, name);
68-
IntPtr errPtr = dlerror();
69-
if (errPtr != IntPtr.Zero)
70-
{
71-
throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
72-
}
73-
return res;
74-
}
75-
76-
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
77-
public static extern IntPtr dlopen(String fileName, int flags);
78-
79-
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
80-
private static extern IntPtr dlsym(IntPtr handle, String symbol);
81-
82-
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
83-
private static extern int dlclose(IntPtr handle);
84-
85-
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
86-
private static extern IntPtr dlerror();
87-
#else // Windows
88-
private const string NativeDll = "kernel32.dll";
89-
90-
[DllImport(NativeDll)]
91-
public static extern IntPtr LoadLibrary(string dllToLoad);
92-
93-
[DllImport(NativeDll)]
94-
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
95-
96-
[DllImport(NativeDll)]
97-
public static extern bool FreeLibrary(IntPtr hModule);
98-
#endif
99-
}
10+
using Python.Runtime.Platform;
10011

10112
/// <summary>
10213
/// Encapsulates the low-level Python C API. Note that it is
@@ -197,17 +108,6 @@ public class Runtime
197108
// .NET core: System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
198109
internal static bool IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT;
199110

200-
/// <summary>
201-
/// Operating system type as reported by Python.
202-
/// </summary>
203-
public enum OperatingSystemType
204-
{
205-
Windows,
206-
Darwin,
207-
Linux,
208-
Other
209-
}
210-
211111
static readonly Dictionary<string, OperatingSystemType> OperatingSystemTypeMapping = new Dictionary<string, OperatingSystemType>()
212112
{
213113
{ "Windows", OperatingSystemType.Windows },
@@ -225,14 +125,6 @@ public enum OperatingSystemType
225125
/// </summary>
226126
public static string OperatingSystemName { get; private set; }
227127

228-
public enum MachineType
229-
{
230-
i386,
231-
x86_64,
232-
armv7l,
233-
armv8,
234-
Other
235-
};
236128

237129
/// <summary>
238130
/// Map lower-case version of the python machine name to the processor
@@ -397,24 +289,24 @@ internal static void Initialize(bool initSigs = false)
397289

398290
Error = new IntPtr(-1);
399291

292+
// Initialize data about the platform we're running on. We need
293+
// this for the type manager and potentially other details. Must
294+
// happen after caching the python types, above.
295+
InitializePlatformData();
296+
400297
IntPtr dllLocal = IntPtr.Zero;
298+
var loader = LibraryLoader.Get(OperatingSystem);
401299

402300
if (_PythonDll != "__Internal")
403301
{
404-
dllLocal = NativeMethods.LoadLibrary(_PythonDll);
302+
dllLocal = loader.Load(_PythonDll);
405303
}
406-
_PyObject_NextNotImplemented = NativeMethods.GetProcAddress(dllLocal, "_PyObject_NextNotImplemented");
304+
_PyObject_NextNotImplemented = loader.GetFunction(dllLocal, "_PyObject_NextNotImplemented");
407305

408-
#if !(MONO_LINUX || MONO_OSX)
409306
if (dllLocal != IntPtr.Zero)
410307
{
411-
NativeMethods.FreeLibrary(dllLocal);
308+
loader.Free(dllLocal);
412309
}
413-
#endif
414-
// Initialize data about the platform we're running on. We need
415-
// this for the type manager and potentially other details. Must
416-
// happen after caching the python types, above.
417-
InitializePlatformData();
418310

419311
// Initialize modules that depend on the runtime class.
420312
AssemblyManager.Initialize();

0 commit comments

Comments
 (0)