Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@

name: Python Tests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
on: [push, pull_request]

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest] # macos-latest
os: [ubuntu-latest, windows-latest, macos-latest]
python: ['3.9', '3.8', '3.7', '3.6', pypy3]

steps:
Expand Down
2 changes: 1 addition & 1 deletion clr_loader/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def __getitem__(self, path):
return self.get_assembly(path)


def get_mono(domain=None):
def get_mono(domain=None, config_file=None, path=None, gc=None):
from .mono import Mono

impl = Mono(domain=domain)
Expand Down
4 changes: 3 additions & 1 deletion clr_loader/ffi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ def load_hostfxr(dotnet_root):

def load_mono(path=None, gc=None):
# Preload C++ standard library, Mono needs that and doesn't properly link against it
ffi.dlopen("stdc++", ffi.RTLD_GLOBAL)
if sys.platform.startswith("linux"):
ffi.dlopen("stdc++", ffi.RTLD_GLOBAL)

if path is None:
from ctypes.util import find_library

Expand Down
17 changes: 16 additions & 1 deletion clr_loader/hostfxr.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,28 @@ def __init__(self, runtime_config, dotnet_root=None):
if not dotnet_root:
dotnet_root = os.environ.get("DOTNET_ROOT", None)

if not dotnet_root and sys.platform == 'win32':
# On Windows, the host library is stored separately from dotnet.exe for x86
if sys.maxsize > 2 ** 32:
possible_root = os.path.join(os.environ.get("ProgramFiles"), "dotnet")
else:
possible_root = os.path.join(os.environ.get("ProgramFiles(x86)"), "dotnet")

if os.path.isdir(possible_root):
dotnet_root = possible_root

if not dotnet_root:
dotnet_path = shutil.which("dotnet")
if not dotnet_path:
raise RuntimeError("Can not determine dotnet root")

try:
dotnet_tmp_path = os.readlink(dotnet_path)
# Pypy does not provide os.readlink right now
if hasattr(os, "readlink"):
dotnet_tmp_path = os.readlink(dotnet_path)
else:
dotnet_tmp_path = dotnet_path

if os.path.isabs(dotnet_tmp_path):
dotnet_path = dotnet_tmp_path
else:
Expand Down
6 changes: 3 additions & 3 deletions clr_loader/mono.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@


class Mono:
def __init__(self, domain=None, config_file=None):
def __init__(self, domain=None, config_file=None, path=None, gc=None):
self._assemblies = {}
initialize(config_file=config_file)
initialize(config_file=config_file, path=path, gc=gc)

if domain is None:
self._domain = _ROOT_DOMAIN
Expand Down Expand Up @@ -84,7 +84,7 @@ def initialize(config_file, path=None, gc=None):
global _MONO, _ROOT_DOMAIN
if _MONO is None:
_MONO = load_mono(path=path, gc=gc)

if config_file is None:
config_file = ffi.NULL
else:
Expand Down
6 changes: 6 additions & 0 deletions example/example.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@
<TargetFrameworks>netcoreapp31;netstandard20</TargetFrameworks>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
38 changes: 28 additions & 10 deletions tests/test_common.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,51 @@
import pytest
from subprocess import check_call
import os
from cffi import FFI
NULL = FFI().NULL
import sys


@pytest.fixture(scope="session")
def example_netstandard(tmpdir_factory):
return build_example(tmpdir_factory, "netstandard20")

@pytest.fixture(scope="session")
def example_dll(tmpdir_factory):
out = str(tmpdir_factory.mktemp("example"))
def example_netcore(tmpdir_factory):
return build_example(tmpdir_factory, "netcoreapp31")

def build_example(tmpdir_factory, framework):
out = str(tmpdir_factory.mktemp(f"example-{framework}"))
proj_path = os.path.join(os.path.dirname(__file__), "../example")

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

return out


def test_mono(example_dll):
@pytest.mark.xfail
def test_mono(example_netstandard):
from clr_loader import get_mono

mono = get_mono()
asm = mono.get_assembly(os.path.join(example_dll, "example.dll"))
asm = mono.get_assembly(os.path.join(example_netstandard, "example.dll"))

run_tests(asm)


def test_coreclr(example_dll):
def test_coreclr(example_netcore):
from clr_loader import get_coreclr

coreclr = get_coreclr(os.path.join(example_dll, "example.runtimeconfig.json"))
asm = coreclr.get_assembly(os.path.join(example_dll, "example.dll"))
coreclr = get_coreclr(os.path.join(example_netcore, "example.runtimeconfig.json"))
asm = coreclr.get_assembly(os.path.join(example_netcore, "example.dll"))

run_tests(asm)


@pytest.mark.skipif(sys.platform != 'win32', reason=".NET Framework only exists on Windows")
def test_netfx(example_netstandard):
from clr_loader import get_netfx

netfx = get_netfx()
asm = netfx.get_assembly(os.path.join(example_netstandard, "example.dll"))

run_tests(asm)

Expand Down