Skip to content

Commit 0c83ca0

Browse files
committed
Refactor mono loading for better defaults
- Use SGen garbage collector by default - Use default installation paths for Windows and macOS
1 parent 5da44c1 commit 0c83ca0

File tree

6 files changed

+54
-35
lines changed

6 files changed

+54
-35
lines changed

clr_loader/__init__.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
from typing import Dict, Optional
22

33
from .wrappers import Runtime
4+
from .util.find import find_libmono, find_dotnet_root
45

56
__all__ = ["get_mono", "get_netfx", "get_coreclr"]
67

78

89
def get_mono(
910
domain: Optional[str] = None,
1011
config_file: Optional[str] = None,
11-
path: Optional[str] = None,
12-
gc: Optional[str] = None,
12+
libmono: Optional[str] = None,
13+
sgen: bool = True,
1314
) -> Runtime:
1415
from .mono import Mono
1516

16-
impl = Mono(domain=domain, config_file=config_file, path=path, gc=gc)
17+
if libmono is None:
18+
libmono = find_libmono(sgen)
19+
20+
impl = Mono(domain=domain, config_file=config_file, libmono=libmono)
1721
return Runtime(impl)
1822

1923

2024
def get_coreclr(
21-
runtime_config: str, dotnet_root: Optional[str] = None,
22-
properties: Optional[Dict[str, str]] = None
25+
runtime_config: str,
26+
dotnet_root: Optional[str] = None,
27+
properties: Optional[Dict[str, str]] = None,
2328
) -> Runtime:
2429
from .hostfxr import DotnetCoreRuntime
2530

31+
if dotnet_root is None:
32+
dotnet_root = find_dotnet_root()
33+
2634
impl = DotnetCoreRuntime(runtime_config=runtime_config, dotnet_root=dotnet_root)
2735
if properties:
2836
for key, value in properties:

clr_loader/ffi/__init__.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,6 @@ def load_mono(path: Optional[str] = None, gc: Optional[str] = None):
3333
if sys.platform.startswith("linux"):
3434
ffi.dlopen("stdc++", ffi.RTLD_GLOBAL)
3535

36-
if path is None:
37-
from ctypes.util import find_library
38-
39-
path = find_library(f"mono{gc or ''}-2.0")
40-
if path is None:
41-
raise RuntimeError("Could not find libmono")
42-
4336
return ffi.dlopen(path, ffi.RTLD_GLOBAL)
4437

4538

clr_loader/hostfxr.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import os
22
import sys
3-
from typing import Optional
43

54
from .ffi import ffi, load_hostfxr
65
from .util import check_result, find_dotnet_root
@@ -9,7 +8,7 @@
98

109

1110
class DotnetCoreRuntime:
12-
def __init__(self, runtime_config: str, dotnet_root: Optional[str] = None):
11+
def __init__(self, runtime_config: str, dotnet_root: str):
1312
self._dotnet_root = dotnet_root or find_dotnet_root()
1413
self._dll = load_hostfxr(self._dotnet_root)
1514
self._is_finalized = False

clr_loader/mono.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111

1212

1313
class Mono:
14-
def __init__(self, domain=None, config_file=None, path=None, gc=None):
14+
def __init__(self, libmono, domain=None, config_file=None):
1515
self._assemblies = {}
16-
initialize(config_file=config_file, path=path, gc=gc)
16+
17+
initialize(config_file=config_file, libmono=libmono)
1718

1819
if domain is None:
1920
self._domain = _ROOT_DOMAIN
@@ -80,10 +81,10 @@ def __call__(self, ptr, size):
8081
return unboxed[0]
8182

8283

83-
def initialize(config_file, path=None, gc=None):
84+
def initialize(config_file: str, libmono: str) -> None:
8485
global _MONO, _ROOT_DOMAIN
8586
if _MONO is None:
86-
_MONO = load_mono(path=path, gc=gc)
87+
_MONO = load_mono(libmono)
8788

8889
if config_file is None:
8990
config_file = ffi.NULL

clr_loader/util/find.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,32 @@ def find_dotnet_root() -> str:
4242
pass
4343

4444
return os.path.dirname(dotnet_path)
45+
46+
47+
def find_libmono(sgen: bool = True) -> str:
48+
unix_name = f"mono{'sgen' if sgen else ''}-2.0"
49+
if sys.platform == "win32":
50+
if sys.maxsize > 2 ** 32:
51+
prog_files = os.environ.get("ProgramFiles")
52+
else:
53+
prog_files = os.environ.get("ProgramFiles(x86)")
54+
55+
# Ignore sgen on Windows, the main installation only contains this DLL
56+
path = fr"{prog_files}\Mono\bin\mono-2.0-sgen.dll"
57+
58+
elif sys.platform == "darwin":
59+
path = (
60+
"/Library/Frameworks/Mono.framework/Versions/"
61+
"Current"
62+
f"/lib/libmono{unix_name}.dylib"
63+
)
64+
65+
else:
66+
from ctypes.util import find_library
67+
68+
path = find_library(unix_name)
69+
70+
if path is None:
71+
raise RuntimeError("Could not find libmono")
72+
73+
return path

tests/test_common.py

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
def example_netstandard(tmpdir_factory):
99
return build_example(tmpdir_factory, "netstandard20")
1010

11+
1112
@pytest.fixture(scope="session")
1213
def example_netcore(tmpdir_factory):
1314
return build_example(tmpdir_factory, "netcoreapp31")
1415

16+
1517
def build_example(tmpdir_factory, framework):
1618
out = str(tmpdir_factory.mktemp(f"example-{framework}"))
1719
proj_path = os.path.join(os.path.dirname(__file__), "../example")
@@ -24,21 +26,7 @@ def build_example(tmpdir_factory, framework):
2426
def test_mono(example_netstandard):
2527
from clr_loader import get_mono
2628

27-
if sys.platform == 'win32':
28-
if sys.maxsize > 2**32:
29-
prog_files = os.environ.get("ProgramFiles")
30-
else:
31-
prog_files = os.environ.get("ProgramFiles(x86)")
32-
33-
path = fr"{prog_files}\Mono\bin\mono-2.0-sgen.dll"
34-
35-
elif sys.platform == "darwin":
36-
path = "/Library/Frameworks/Mono.framework/Versions/Current/lib/libmono-2.0.dylib"
37-
38-
else:
39-
path = None
40-
41-
mono = get_mono(path=path)
29+
mono = get_mono()
4230
asm = mono.get_assembly(os.path.join(example_netstandard, "example.dll"))
4331

4432
run_tests(asm)
@@ -53,7 +41,9 @@ def test_coreclr(example_netcore):
5341
run_tests(asm)
5442

5543

56-
@pytest.mark.skipif(sys.platform != 'win32', reason=".NET Framework only exists on Windows")
44+
@pytest.mark.skipif(
45+
sys.platform != "win32", reason=".NET Framework only exists on Windows"
46+
)
5747
def test_netfx(example_netstandard):
5848
from clr_loader import get_netfx
5949

@@ -68,4 +58,3 @@ def run_tests(asm):
6858
test_data = b"testy mctestface"
6959
res = func(test_data)
7060
assert res == len(test_data)
71-

0 commit comments

Comments
 (0)