Repository navigation
Changes to allow different toolchains for host and guest - #1962
simongdavies wants to merge 2 commits into
Conversation
Host move to 1.99.1 Guest fixed at 1.94.1 until hyperlight target is upstreamed Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The guest debug-information regression remains unresolved, and cross-platform CI, Nix, and container changes need build validation.
1 open issue
What changed in this PR
Separates Hyperlight’s host and guest Rust toolchains without changing the minimum supported Rust version.
Changes:
- Pins host builds to Rust 1.99.1 and guest builds to 1.94.1.
- Updates CI, Nix, containers, and contributor documentation for separate toolchains.
- Resolves compiler and lint warnings.
| File | Description |
|---|---|
| src/tests/rust_guests/rust-toolchain.toml | Pins Rust guest toolchain. |
| src/hyperlight_testing/src/tracing_subscriber.rs | Removes redundant formatting borrows. |
| src/hyperlight_host/tests/sandbox_host_tests.rs | Removes obsolete import. |
| src/hyperlight_host/build.rs | Removes redundant formatting borrow. |
| src/hyperlight_guest_capi/rust-toolchain.toml | Pins C API guest toolchain. |
| src/hyperlight_component_util/src/util.rs | Removes redundant formatting borrow. |
| src/hyperlight_component_util/src/rtypes.rs | Iterates map keys directly. |
| src/hyperlight_component_util/src/emit.rs | Iterates map values directly. |
| rust-toolchain.toml | Pins host toolchain and components. |
| flake.nix | Supports separate toolchain selection. |
| CONTRIBUTING.md | Documents guest toolchain selection. |
| .github/workflows/ValidatePullRequest.yml | Installs both toolchains. |
| .github/workflows/RustNightly.yml | Updates setup and guest cache keys. |
| .github/workflows/RegenSnapshotGoldens.yml | Installs both toolchains. |
| .github/workflows/PrimeCaches.yml | Installs both toolchains. |
| .github/workflows/dep_update_guest_locks.yml | Installs both toolchains. |
| .github/workflows/dep_run_examples.yml | Installs both toolchains. |
| .github/workflows/dep_miri.yml | Uses file-based toolchain setup. |
| .github/workflows/dep_fuzzing.yml | Installs both toolchains. |
| .github/workflows/dep_code_checks.yml | Updates setup and guest cache keys. |
| .github/workflows/dep_build_test.yml | Installs both toolchains. |
| .github/workflows/dep_build_guests.yml | Supports guest pins and older commits. |
| .github/workflows/dep_benchmarks.yml | Installs both toolchains. |
| .github/workflows/CreateRelease.yml | Installs both toolchains. |
| .github/workflows/CreateDevcontainerImage.yml | Reads and passes both toolchain versions. |
| .github/workflows/Coverage.yml | Installs both toolchains. |
| .github/workflows/copilot-setup-steps.yml | Consolidates toolchain setup. |
| .github/workflows/CargoPublish.yml | Installs both toolchains. |
| .github/workflows/CargoAudit.yml | Uses file-based toolchain selection. |
| .devcontainer/Dockerfile | Installs separate host and guest toolchains. |
Review effort: Balanced
This comment has been minimized.
This comment has been minimized.
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Benchmark ResultsMeasured commit: kvm / amd (Linux) (➖ stable)No benchmark improved or regressed. Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
kvm / intel (Linux) (➖ stable)No benchmark improved or regressed. Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
mshv3 / amd (Linux) (➖ stable)No benchmark improved or regressed. Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
mshv3 / intel (Linux) (➖ stable)No benchmark improved or regressed. Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
hyperv-ws2025 / amd (Windows) (➖ stable)No benchmark improved or regressed. Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
hyperv-ws2025 / intel (Windows) (➖ stable)No benchmark improved or regressed. Benchmark Resultsfunction_call_codec
payload_allocation
sandboxes
slot_pool
snapshot_files
virtq_readonly
virtq_readwrite
Reported by |
| submodules: true | ||
|
|
||
| - uses: hyperlight-dev/ci-setup-workflow@2f4142ba17cf573af44fc1e1f1ffc743daded5b3 # v1.10.0 | ||
| - uses: hyperlight-dev/ci-setup-workflow@4b7107a0f24c523f503c861ddeb8180d3a23e7f7 # v2.1.0 |
There was a problem hiding this comment.
The v2 setup action calls actions-rust-lang/setup-rust-toolchain, which writes CARGO_PROFILE_DEV_DEBUG=0 to GITHUB_ENV when it is unset:
if [[ ! -v CARGO_PROFILE_DEV_DEBUG ]]; then
echo "CARGO_PROFILE_DEV_DEBUG=0" >> $GITHUB_ENV
fiThis job has no override. just tar-static-lib builds debug/libhyperlight_guest_capi.a with --profile dev, so the published debug archive has no debug info. Other jobs lose backtrace line numbers too. Could we set CARGO_PROFILE_DEV_DEBUG once in ci-setup-workflow before both setup steps, and drop the three per-workflow overrides? Otherwise add it to this workflow's env.
| // even though the warning is a false positive here. We suppress it because the ABI contract is | ||
| // the important thing. We also allow `unknown_lints` so older guest toolchains can still build | ||
| // even though they do not know this lint's name yet. | ||
| #![allow( |
There was a problem hiding this comment.
I don't think this is a false positive. The lint compares the whole signature with eq, and that includes safety (source). write builds a slice from a caller pointer and clock_gettime writes through one, so they should be unsafe extern "C" fn with # Safety docs. memory.rs already does this for malloc:
#[unsafe(no_mangle)]
unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: usize) -> isize {Then the module-wide allow can go. The unknown_lints allow also hides typos in other lint names in this module.
| return tomllib.load(source)["toolchain"]["channel"] | ||
| guest = channel("src/tests/rust_guests/rust-toolchain.toml") | ||
| if guest != channel("src/hyperlight_guest_capi/rust-toolchain.toml"): |
There was a problem hiding this comment.
This check runs only on pushes to main. A PR that bumps one guest toolchain file passes CI, the C API builds with a different rustc, and this workflow fails after merge. Could the same check run in dep_code_checks.yml?
| .clang_arg(format!("-I{}", include_dir.display())) | ||
| .clang_arg("-nostdlibinc") | ||
| // Preserve size_t in runtime function declarations for bindgen. | ||
| .clang_arg("-fno-builtin") |
There was a problem hiding this comment.
The flag makes sense and matches line 88. It does change public bindings though. Without it clang types builtins like strlen and memcpy with unsigned long, so bindgen emitted c_ulong. With it they keep size_t and become usize. These are re-exported as hyperlight_guest_bin::libc, so guest code like let n: u64 = unsafe { libc::strlen(p) }; stops compiling. Worth a breaking CHANGELOG entry?
| - uses: hyperlight-dev/ci-setup-workflow@4b7107a0f24c523f503c861ddeb8180d3a23e7f7 # v2.1.0 | ||
| with: | ||
| rust-toolchain: "1.94" | ||
| additional-toolchain-directory: src/tests/rust_guests |
There was a problem hiding this comment.
This job only runs root cargo build, so it doesn't need the guest toolchain. Same for other host-only and artifact-consuming jobs. Could we pass additional-toolchain-directory only where guests or the C API are built?
| @@ -0,0 +1,6 @@ | |||
| [toolchain] | |||
There was a problem hiding this comment.
hyperlight-guest-capi is still a root workspace member, so the toolchain depends on the working directory. cargo build -p hyperlight-guest-capi and rust-analyzer from the root use 1.99.1, and both toolchains share target/. Would it make sense to exclude it from the root workspace like src/tests/rust_guests? Could be a follow-up.
| && rustup target add x86_64-unknown-linux-gnu \ | ||
| && rustup target add x86_64-unknown-linux-musl \ | ||
| && rustup target add x86_64-unknown-none \ | ||
| && rustup component add clippy rustfmt --toolchain ${RUST_TOOLCHAIN} \ |
There was a problem hiding this comment.
nit: rustup default installs clippy and rustfmt with the default profile, so this line looks redundant. rustfmt in the toolchain files also seems unused since fmt runs on nightly.
|
|
||
| The root `rust-toolchain.toml` pins the rust version for host builds and tools. | ||
|
|
||
| Rust guests and the C API use Rust 1.94.1, pinned in |
There was a problem hiding this comment.
nit: the hard-coded version will go stale on the next bump. Maybe just point at the toolchain files.
| case "+$requested" in | ||
| ${clauses} | ||
| install) exit 0; ;; | ||
| +1.99.1) base="${toolchains.stable.rust}"; ;; |
There was a problem hiding this comment.
Is the stable channel dated 2026-10-15 guaranteed to be 1.99.1? Naming the toolchain attribute "1.99.1" would avoid this special case.

Enables different toolchains for host and guest.
Host - 1.99.1
Guest - 1.94.1
No change to MSRV.
Minor changes to resolve warnings from move to 1.99