Skip to content

Commit

Permalink
Delay actually loading the runtime to fix property setting (#63)
Browse files Browse the repository at this point in the history
* Delay actually loading the runtime to fix property setting
* Launch test for properties in separate process
  • Loading branch information
filmor authored Aug 7, 2023
1 parent 63d7f69 commit 000bc78
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 14 deletions.
20 changes: 9 additions & 11 deletions clr_loader/hostfxr.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ def __init__(self, runtime_config: Path, dotnet_root: Path, **params: str):

self._dotnet_root = Path(dotnet_root)
self._dll = load_hostfxr(self._dotnet_root)
self._is_initialized = False
self._handle = _get_handle(self._dll, self._dotnet_root, runtime_config)
self._load_func = _get_load_func(self._dll, self._handle)
self._load_func = None

for key, value in params.items():
self[key] = value
Expand All @@ -36,7 +35,7 @@ def dotnet_root(self) -> Path:

@property
def is_initialized(self) -> bool:
return self._is_initialized
return self._load_func is not None

@property
def is_shutdown(self) -> bool:
Expand Down Expand Up @@ -81,18 +80,23 @@ def __iter__(self) -> Generator[Tuple[str, str], None, None]:
for i in range(size_ptr[0]):
yield (decode(keys_ptr[i]), decode(values_ptr[i]))

def _get_load_func(self):
if self._load_func is None:
self._load_func = _get_load_func(self._dll, self._handle)

return self._load_func

def _get_callable(self, assembly_path: StrOrPath, typename: str, function: str):
# TODO: Maybe use coreclr_get_delegate as well, supported with newer API
# versions of hostfxr
self._is_initialized = True

# Append assembly name to typename
assembly_path = Path(assembly_path)
assembly_name = assembly_path.stem
typename = f"{typename}, {assembly_name}"

delegate_ptr = ffi.new("void**")
res = self._load_func(
res = self._get_load_func()(
encode(str(assembly_path)),
encode(typename),
encode(function),
Expand All @@ -103,12 +107,6 @@ def _get_callable(self, assembly_path: StrOrPath, typename: str, function: str):
check_result(res)
return ffi.cast("component_entry_point_fn", delegate_ptr[0])

def _check_initialized(self) -> None:
if self._handle is None:
raise RuntimeError("Runtime is shut down")
elif not self._is_initialized:
raise RuntimeError("Runtime is not initialized")

def shutdown(self) -> None:
if self._handle is not None:
self._dll.hostfxr_close(self._handle)
Expand Down
21 changes: 18 additions & 3 deletions tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def example_netcore(tmpdir_factory):

def build_example(tmpdir_factory, framework):
out = Path(tmpdir_factory.mktemp(f"example-{framework}"))
proj_path = Path(__file__).parent.parent / "example"
proj_path = Path(__file__).parent.parent / "example" / "example.csproj"

check_call(["dotnet", "build", str(proj_path), "-o", str(out), "-f", framework])

Expand Down Expand Up @@ -75,6 +75,19 @@ def test_coreclr(example_netcore: Path):
run_tests(asm)


def test_coreclr_properties(example_netcore: Path):
from multiprocessing import get_context

p = get_context("spawn").Process(
target=_do_test_coreclr_autogenerated_runtimeconfig,
args=(example_netstandard,),
kwargs=dict(properties=dict(APP_CONTEXT_BASE_DIRECTORY=str(example_netcore))),
)
p.start()
p.join()
p.close()


def test_coreclr_autogenerated_runtimeconfig(example_netstandard: Path):
from multiprocessing import get_context

Expand All @@ -86,10 +99,12 @@ def test_coreclr_autogenerated_runtimeconfig(example_netstandard: Path):
p.close()


def _do_test_coreclr_autogenerated_runtimeconfig(example_netstandard: Path):
def _do_test_coreclr_autogenerated_runtimeconfig(
example_netstandard: Path, **properties
):
from clr_loader import get_coreclr

coreclr = get_coreclr()
coreclr = get_coreclr(properties=properties)
asm = coreclr.get_assembly(example_netstandard / "example.dll")

run_tests(asm)
Expand Down

0 comments on commit 000bc78

Please sign in to comment.