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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .github/workflows/build_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ jobs:
mkdir /tmp/ci-cache
chmod 755 /tmp/ci-cache

- uses: quantinuum/hugrverse-env/install-hugrenv-action@main
with:
packages: "llvm"

Comment on lines +113 to +116
# --------------------------------
# Build selene-sim wheel
# --------------------------------
Expand Down
63 changes: 63 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 38 additions & 10 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,27 @@ def get_platform_suffix() -> str:
]


def _compile_inline_guppy_source_to_hugr_bytes(guppy_source: str) -> bytes:
def _compile_inline_guppy_source_to_hugr_bytes(
guppy_source: str, emit_debug: bool
) -> bytes:
# check if guppy is installed
if importlib.util.find_spec("guppylang") is None:
raise RuntimeError(
"Guppy is not installed. Please install guppylang to compile inline guppy source."
)

maybe_debug = (
""
if not emit_debug
else """
from guppylang_internals.debug_mode import turn_on_debug_mode

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once 1.1 is released you should be able to just pass debug_mode = True wherever you actually call compile instead of doing this but I guess for now this can't be changed

turn_on_debug_mode()
"""
)

# This executes trusted inline source defined in this repository's test files.
standalone_file = f"""
{guppy_source}
standalone_file = f"""{guppy_source}
{maybe_debug}

from pathlib import Path
compiled_hugr = main.compile()
Expand All @@ -75,7 +86,7 @@ def _compile_inline_guppy_source_to_hugr_bytes(guppy_source: str) -> bytes:
# make temporary directory
import tempfile

with tempfile.TemporaryDirectory() as temp_dir:
with tempfile.TemporaryDirectory(delete=False) as temp_dir:
temp_path = Path(temp_dir) / "temp_guppy_source.py"
temp_path.write_text(standalone_file)
# execute the file in a subprocess to avoid any issues with stateful execution of guppy code in the same process
Expand All @@ -87,7 +98,7 @@ def _compile_inline_guppy_source_to_hugr_bytes(guppy_source: str) -> bytes:


def _compile_hugr_to_llvm_ir_for_target(
hugr_bytes: bytes, qis_platform: str, target: str
hugr_bytes: bytes, qis_platform: str, target: str, emit_debug: bool
) -> str:
try:
from selene_hugr_qis_compiler import compile_to_llvm_ir
Expand All @@ -96,19 +107,32 @@ def _compile_hugr_to_llvm_ir_for_target(
"--compile-guppy requires selene_hugr_qis_compiler and guppylang to be installed."
) from exc

return compile_to_llvm_ir(hugr_bytes, platform=qis_platform, target_triple=target)
result = compile_to_llvm_ir(
hugr_bytes, platform=qis_platform, target_triple=target, emit_debug=emit_debug
)
if emit_debug:
# sanitize debug file paths for reproducibility
import re

result = re.sub(
r'filename: "[^"]+temp_guppy_source.py"',
'filename: "/sanitized/path/program.py"',
result,
)
result = re.sub('directory: "[^"]+"', 'directory: "/sanitized/path"', result)
return result


def _hash_guppy(guppy_source: str) -> str:
return hashlib.sha256(guppy_source.encode()).hexdigest()


def _compile_inline_guppy_source_to_llvm_ir(
guppy_source: str, *, qis_platform: str, target: str
guppy_source: str, *, qis_platform: str, target: str, emit_debug: bool
) -> str:
hugr_bytes = _compile_inline_guppy_source_to_hugr_bytes(guppy_source)
hugr_bytes = _compile_inline_guppy_source_to_hugr_bytes(guppy_source, emit_debug)
return _compile_hugr_to_llvm_ir_for_target(
hugr_bytes, qis_platform=qis_platform, target=target
hugr_bytes, qis_platform=qis_platform, target=target, emit_debug=emit_debug
)


Expand All @@ -119,6 +143,7 @@ def _resolve(
program_name: str,
guppy_source: str,
qis_platform: str = "helios",
emit_debug: bool = False,
) -> Path | bytes:
test_name = request.node.name
test_path = Path(request.node.fspath)
Expand All @@ -138,7 +163,10 @@ def _resolve(
for qis_platform_it in SUPPORTED_QIS_PLATFORMS:
for target in SUPPORTED_TARGETS:
llvm_ir = _compile_inline_guppy_source_to_llvm_ir(
guppy_source, qis_platform=qis_platform_it, target=target
guppy_source,
qis_platform=qis_platform_it,
target=target,
emit_debug=emit_debug,
)
(
resources_dir / f"{program_name}-{qis_platform_it}-{target}.ll"
Expand Down
8 changes: 6 additions & 2 deletions devenv.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{ pkgs, lib, inputs, config, ... }:
{
let
hugrenv = pkgs.callPackage ./hugrenv.nix { packages = ["llvm"]; };
in {
config = {
packages = with pkgs; [
cmake
Expand All @@ -17,10 +19,12 @@
enterShell = ''
eval "$(just --completions bash)"
export LD_LIBRARY_PATH="${lib.makeLibraryPath [ pkgs.stdenv.cc.cc ]}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export PATH="${hugrenv}/bin:$PATH"
'';

env = {
LIBCLANG_PATH = "${pkgs.libclang.lib}";
"LIBCLANG_PATH" = "${hugrenv}/lib";
"HUGRENV_PATH" = "${hugrenv}";
};


Expand Down
58 changes: 58 additions & 0 deletions hatch_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,62 @@ def extract_libs(self):
shutil.copy(lib_path, destination)


class HugrenvTools:
def __init__(self, hook: "BundleBuildHook") -> None:
self.hook = hook
assert "HUGRENV_PATH" in os.environ, (
"HUGRENV_PATH environment variable is not set. This is required for bundling Hugrenv tools into selene's _dist directory."
)
self.hugrenv_path = Path(os.environ["HUGRENV_PATH"])
self.is_cibw_host_path = str(self.hugrenv_path).startswith("/host/")
assert self.hugrenv_path.is_dir(), (
f"HUGRENV_PATH ('{self.hugrenv_path}') does not exist or is not a directory as required."
)

def resolve_artifact(self, directory: str, name: str) -> Path:
seen: set[Path] = set()
path = self.hugrenv_path / directory / name
while path.is_symlink():
if path in seen:
raise RuntimeError(f"Symlink loop while resolving {path}")
seen.add(path)
target = path.readlink()
if target.is_absolute():
if self.is_cibw_host_path:
target = Path("/host") / target.relative_to("/")
path = target
else:
path = Path(os.path.normpath(path.parent / target))
return path

def extract_artifact(self, directory: str, name: str):
artifact_path = self.resolve_artifact(directory, name)
assert artifact_path.is_file(), (
f"Hugrenv artifact '{name}' not found at {artifact_path}"
)
dist_dir = (
Path(self.hook.root) / f"selene-sim/python/selene_sim/_dist/{directory}"
)
dist_dir.mkdir(parents=True, exist_ok=True)
self.hook.app.display_info(f"Copying {artifact_path} to {dist_dir}")
shutil.copy(artifact_path, dist_dir)
dist_path = dist_dir / name
dist_path.chmod(0o755)

def extract_binary(self, name):
if sys.platform == "win32":
name += ".exe"
self.extract_artifact("bin", name)

def extract_library(self, name):
raise NotImplementedError("extract_library is not implemented yet.")

def extract(self):
self.extract_binary("llvm-symbolizer")
if sys.platform == "darwin":
self.extract_binary("dsymutil")


class BundleBuildHook(BuildHookInterface):
def target_is_windows(self) -> bool:
return sys.platform == "win32" or os.environ.get(
Expand Down Expand Up @@ -290,6 +346,8 @@ def initialize(self, version: str, build_data: dict) -> None:
utilities_builder = UtilitiesBuild(self)
utilities_builder.build_all()
utilities_builder.extract_libs()
hugrenv_tools = HugrenvTools(self)
hugrenv_tools.extract()

packages = [Path("selene-sim/python/selene_sim")]
for topic_dir in Path("selene-ext").iterdir():
Expand Down
31 changes: 31 additions & 0 deletions hugrenv.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"version": "0.5.0",
"hashes": {
"macosx_11_0": {
"aarch64": {
"llvm": "sha256-vAyAnlsZcTbddA/pZZR3n1TP6ZWi2AEL9lFsfSqoGIo=",
"tket": "sha256-+YbO4aE+3HM5di09cnNpvaLKM/8yg5hvvuzQL5xCa+g="
},
"x86_64": {
"llvm": "sha256-yxaf4SZQFikmUfy5v3OxnKAhbCxn+xTXTwVu8GeZKrg=",
"tket": "sha256-goKko59ADWtZvlpDI4lJBuixVk/qzhafhNH/i1Ir2wQ="
}
},
"manylinux_2_28": {
"aarch64": {
"llvm": "sha256-f3/vh+VGPVvLDRgYUlnOaCXGKokh+seBuZ2SUN7514k=",
"tket": "sha256-BUOI/FEZ3p6XDOqKOVKWDDm5qMD5Cs2ghWxd5wXk8Nc="
},
"x86_64": {
"llvm": "sha256-xF5Mg5/qrnn2HtWDnp9s1RK0SeyHjgkMHWZgHKRxjIQ=",
"tket": "sha256-q5dXP1Fiq3tcHhE3lYQO9CYFoZzAPXCI5BWrT4HKrNo="
}
},
"win": {
"amd64": {
"llvm": "sha256-e41NcJtwyz8iqKgs0y09T123q8FIzeqe2ARuwom1Fl4=",
"tket": "sha256-bcY00WM56lsRMzgXfOgHZx/PZ4xeGT1KauMpHheAMTo="
}
}
}
}
19 changes: 19 additions & 0 deletions hugrenv.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
pkgs ? import <nixpkgs> {},
platform ? if pkgs.stdenv.isDarwin then "macosx_11_0" else "manylinux_2_28",
arch ? if pkgs.stdenv.isAarch64 then "aarch64" else "x86_64",
packages ? [ "tket" "llvm" ],
}:
let
sources = builtins.fromJSON (builtins.readFile ./hugrenv.lock);
version = sources.version;
get-package = package: pkgs.fetchzip {
url = let
path="https://github.com/Quantinuum/hugrverse-env/releases/download/v${version}/hugrenv-${package}-${platform}_${arch}.tar.gz";
in builtins.trace "fetching ${package} from ${path}" path;
sha256 = sources.hashes.${platform}.${arch}.${package};
};
in pkgs.symlinkJoin {
name = "hugrenv-${version}-${pkgs.lib.concatStringsSep "-" [platform arch]}_${pkgs.lib.concatStringsSep "-" packages}";
paths = map get-package packages;
}
Loading