-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy path__init__.py
More file actions
84 lines (60 loc) · 2.38 KB
/
__init__.py
File metadata and controls
84 lines (60 loc) · 2.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import sys
from pathlib import Path
import cffi
from . import hostfxr, mono, netfx
__all__ = ["ffi", "load_hostfxr", "load_mono", "load_netfx"]
ffi = cffi.FFI()
for cdef in hostfxr.cdef + mono.cdef + netfx.cdef:
ffi.cdef(cdef)
def load_hostfxr(dotnet_root: Path):
hostfxr_name = _get_dll_name("hostfxr")
dotnet_root = dotnet_root.absolute()
# Find all hostfxr versions by looking for the library file in version subdirectories
hostfxr_path = dotnet_root / "host" / "fxr"
hostfxr_paths = hostfxr_path.glob(f"*/{hostfxr_name}")
error_report: list[str] = []
for hostfxr_path in reversed(sorted(hostfxr_paths, key=_path_to_version)):
try:
return ffi.dlopen(str(hostfxr_path))
except Exception as err:
error_report.append(f"Path {hostfxr_path} gave the following error:\n{err}")
try:
return ffi.dlopen(str(dotnet_root / hostfxr_name))
except Exception as err:
error_report.append(f"Path {hostfxr_path} gave the following error:\n{err}")
raise RuntimeError(
f"Could not find a suitable hostfxr library in {dotnet_root}. The following paths were scanned:\n\n"
+ ("\n\n".join(error_report))
)
def load_mono(path: Path | None = None):
# Preload C++ standard library, Mono needs that and doesn't properly link against it
if sys.platform == "linux":
ffi.dlopen("stdc++", ffi.RTLD_GLOBAL)
path_str = str(path) if path else None
return ffi.dlopen(path_str, ffi.RTLD_GLOBAL)
def load_netfx():
if sys.platform != "win32":
raise RuntimeError(".NET Framework is only supported on Windows")
dirname = Path(__file__).parent / "dlls"
if sys.maxsize > 2**32:
arch = "amd64"
else:
arch = "x86"
path = dirname / arch / "ClrLoader.dll"
return ffi.dlopen(str(path))
def _path_to_version(path: Path) -> tuple[int, int, int]:
name = path.parent.name
try:
# Handle pre-release versions like "10.0.0-rc.1" by taking only the version part
version_part = name.split("-")[0]
res = list(map(int, version_part.split(".")))
return tuple(res + [0, 0, 0])[:3]
except Exception:
return (0, 0, 0)
def _get_dll_name(name: str) -> str:
if sys.platform == "win32":
return f"{name}.dll"
elif sys.platform == "darwin":
return f"lib{name}.dylib"
else:
return f"lib{name}.so"