Skip to content

Commit 7595fda

Browse files
authored
Merge pull request #894 from filmor/drop-mono-linux-flag
Get the correct library loading functions at runtime
2 parents fc7d8a4 + 537ee5f commit 7595fda

File tree

6 files changed

+258
-131
lines changed

6 files changed

+258
-131
lines changed

src/embed_tests/TestRuntime.cs

+4-3
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

+2
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

+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Runtime.InteropServices;
4+
5+
namespace Python.Runtime.Platform
6+
{
7+
interface ILibraryLoader
8+
{
9+
IntPtr Load(string dllToLoad);
10+
11+
IntPtr GetFunction(IntPtr hModule, string procedureName);
12+
13+
void Free(IntPtr hModule);
14+
}
15+
16+
static class LibraryLoader
17+
{
18+
public static ILibraryLoader Get(OperatingSystemType os)
19+
{
20+
switch (os)
21+
{
22+
case OperatingSystemType.Windows:
23+
return new WindowsLoader();
24+
case OperatingSystemType.Darwin:
25+
return new DarwinLoader();
26+
case OperatingSystemType.Linux:
27+
return new LinuxLoader();
28+
default:
29+
throw new PlatformNotSupportedException($"This operating system ({os}) is not supported");
30+
}
31+
}
32+
}
33+
34+
class LinuxLoader : ILibraryLoader
35+
{
36+
private static int RTLD_NOW = 0x2;
37+
private static int RTLD_GLOBAL = 0x100;
38+
private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
39+
private const string NativeDll = "libdl.so";
40+
41+
public IntPtr Load(string dllToLoad)
42+
{
43+
var filename = $"lib{dllToLoad}.so";
44+
ClearError();
45+
var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
46+
if (res == IntPtr.Zero)
47+
{
48+
var err = GetError();
49+
throw new DllNotFoundException($"Could not load {filename} with flags RTLD_NOW | RTLD_GLOBAL: {err}");
50+
}
51+
52+
return res;
53+
}
54+
55+
public void Free(IntPtr handle)
56+
{
57+
dlclose(handle);
58+
}
59+
60+
public IntPtr GetFunction(IntPtr dllHandle, string name)
61+
{
62+
// look in the exe if dllHandle is NULL
63+
if (dllHandle == IntPtr.Zero)
64+
{
65+
dllHandle = RTLD_DEFAULT;
66+
}
67+
68+
ClearError();
69+
IntPtr res = dlsym(dllHandle, name);
70+
if (res == IntPtr.Zero)
71+
{
72+
var err = GetError();
73+
throw new MissingMethodException($"Failed to load symbol {name}: {err}");
74+
}
75+
return res;
76+
}
77+
78+
void ClearError()
79+
{
80+
dlerror();
81+
}
82+
83+
string GetError()
84+
{
85+
var res = dlerror();
86+
if (res != IntPtr.Zero)
87+
return Marshal.PtrToStringAnsi(res);
88+
else
89+
return null;
90+
}
91+
92+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
93+
public static extern IntPtr dlopen(string fileName, int flags);
94+
95+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
96+
private static extern IntPtr dlsym(IntPtr handle, string symbol);
97+
98+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
99+
private static extern int dlclose(IntPtr handle);
100+
101+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
102+
private static extern IntPtr dlerror();
103+
}
104+
105+
class DarwinLoader : ILibraryLoader
106+
{
107+
private static int RTLD_NOW = 0x2;
108+
private static int RTLD_GLOBAL = 0x8;
109+
private const string NativeDll = "/usr/lib/libSystem.dylib";
110+
private static IntPtr RTLD_DEFAULT = new IntPtr(-2);
111+
112+
public IntPtr Load(string dllToLoad)
113+
{
114+
var filename = $"lib{dllToLoad}.dylib";
115+
ClearError();
116+
var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
117+
if (res == IntPtr.Zero)
118+
{
119+
var err = GetError();
120+
throw new DllNotFoundException($"Could not load {filename} with flags RTLD_NOW | RTLD_GLOBAL: {err}");
121+
}
122+
123+
return res;
124+
}
125+
126+
public void Free(IntPtr handle)
127+
{
128+
dlclose(handle);
129+
}
130+
131+
public IntPtr GetFunction(IntPtr dllHandle, string name)
132+
{
133+
// look in the exe if dllHandle is NULL
134+
if (dllHandle == IntPtr.Zero)
135+
{
136+
dllHandle = RTLD_DEFAULT;
137+
}
138+
139+
ClearError();
140+
IntPtr res = dlsym(dllHandle, name);
141+
if (res == IntPtr.Zero)
142+
{
143+
var err = GetError();
144+
throw new MissingMethodException($"Failed to load symbol {name}: {err}");
145+
}
146+
return res;
147+
}
148+
149+
void ClearError()
150+
{
151+
dlerror();
152+
}
153+
154+
string GetError()
155+
{
156+
var res = dlerror();
157+
if (res != IntPtr.Zero)
158+
return Marshal.PtrToStringAnsi(res);
159+
else
160+
return null;
161+
}
162+
163+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
164+
public static extern IntPtr dlopen(String fileName, int flags);
165+
166+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
167+
private static extern IntPtr dlsym(IntPtr handle, String symbol);
168+
169+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
170+
private static extern int dlclose(IntPtr handle);
171+
172+
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
173+
private static extern IntPtr dlerror();
174+
}
175+
176+
class WindowsLoader : ILibraryLoader
177+
{
178+
private const string NativeDll = "kernel32.dll";
179+
180+
181+
public IntPtr Load(string dllToLoad)
182+
{
183+
var res = WindowsLoader.LoadLibrary(dllToLoad);
184+
if (res == IntPtr.Zero)
185+
throw new DllNotFoundException($"Could not load {dllToLoad}", new Win32Exception());
186+
return res;
187+
}
188+
189+
public IntPtr GetFunction(IntPtr hModule, string procedureName)
190+
{
191+
var res = WindowsLoader.GetProcAddress(hModule, procedureName);
192+
if (res == IntPtr.Zero)
193+
throw new MissingMethodException($"Failed to load symbol {procedureName}", new Win32Exception());
194+
return res;
195+
}
196+
197+
public void Free(IntPtr hModule) => WindowsLoader.FreeLibrary(hModule);
198+
199+
[DllImport(NativeDll, SetLastError = true)]
200+
static extern IntPtr LoadLibrary(string dllToLoad);
201+
202+
[DllImport(NativeDll, SetLastError = true)]
203+
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
204+
205+
[DllImport(NativeDll)]
206+
static extern bool FreeLibrary(IntPtr hModule);
207+
}
208+
}

src/runtime/platform/Types.cs

+22
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+
}

0 commit comments

Comments
 (0)