diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88635c0..bed6591 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,23 +11,37 @@ on: branches: [main] workflow_call: +# Cancels old running job if a new one is triggered (e.g. by a push onto the same branch). +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always jobs: run-tests: - name: Run tests on ${{ matrix.os }} + name: Run tests on ${{ matrix.environment }} ${{ matrix.os }} strategy: matrix: - os: ["ubuntu-latest", "windows-latest"] - runs-on: ${{ matrix.os }} + os: [ "ubuntu-latest", "windows-latest" ] + environment: [ "HL", "GH" ] + runs-on: ${{ fromJson( + matrix.environment == 'HL' && + format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-amd", "JobId=cargo-hyperlight-{2}-{3}-{4}"]', + matrix.os == 'windows-latest' && 'Windows' || 'Linux', + matrix.os == 'windows-latest' && 'win2025' || 'kvm', + github.run_id, + github.run_number, + github.run_attempt) + || format('["{0}"]', matrix.os) ) }} steps: - uses: actions/checkout@v7 - uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: Swatinem/rust-cache@v2 - uses: extractions/setup-just@v4 - name: Enable kvm - if: runner.os == 'Linux' + if: runner.os == 'Linux' && runner.arch == 'X64' && matrix.environment == 'GH' run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules @@ -39,11 +53,18 @@ jobs: shell: bash run: just build-guest - name: Run example + if: runner.arch == 'X64' shell: bash run: just run-guest - - name: Test `new` subcommand + - name: Build C guest example + shell: bash + run: just build-c-guest + - name: Run C guest example + shell: bash + run: just run-c-guest + - name: Run other tests shell: bash - run: just test-new + run: just test spelling: name: Spell check with typos @@ -76,4 +97,4 @@ jobs: run: just fmt - name: Check clippy shell: bash - run: just clippy \ No newline at end of file + run: just clippy diff --git a/.gitignore b/.gitignore index 2dcd3c9..fcdb023 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target -/examples/*/target +/examples/**/target +/examples/c/sysroot +/examples/c/guest/guest \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index a7036af..37daf8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -85,6 +85,8 @@ dependencies = [ "libc", "object", "os_str_bytes", + "proc-macro2", + "quote", "regex", "rustc-demangle", "semver", diff --git a/Cargo.toml b/Cargo.toml index f2726ee..338d754 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,5 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tempfile = "3" which = { version = "8", features = ["regex"] } +quote = "1.0" +proc-macro2 = "1.0" \ No newline at end of file diff --git a/README.md b/README.md index a5439f5..dbc9e8b 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Then to build the hyperlight guest binary, run cargo hyperlight build --release ``` -Your binary will be built for the `x86_64-hyperlight-none` target by default, and placed in `target/x86_64-hyperlight-none/release/guest`. +Your binary will be built for the `x86_64-hyperlight-none` target (or `aarch64-hyperlight-none` on ARM) by default, and placed in `target/-hyperlight-none/release/guest`. There's no need for any extra configuration, the command will take care of everything. diff --git a/build.rs b/build.rs index 2246ee5..dec170d 100644 --- a/build.rs +++ b/build.rs @@ -29,6 +29,11 @@ fn main() { println!("cargo:rustc-env=GIT_HASH={}", git_hash); println!("cargo:rustc-env=GIT_DATE={}", git_date); + println!( + "cargo:rustc-env=CARGO_HYPERLIGHT_HOST_TRIPLE={}", + std::env::var("TARGET").unwrap() + ); + // Re-run build script if git HEAD changes println!("cargo:rerun-if-changed=.git/HEAD"); } diff --git a/examples/c/fetch-capi/Cargo.lock b/examples/c/fetch-capi/Cargo.lock new file mode 100644 index 0000000..5e3b1c3 --- /dev/null +++ b/examples/c/fetch-capi/Cargo.lock @@ -0,0 +1,859 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "buddy_system_allocator" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1af5a01adeeade54c9f5060300227a8ee64c05b6376f28e9b8ee3b72dd2056f" +dependencies = [ + "spin", +] + +[[package]] +name = "cbindgen" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ecb53484c9c167ba674026b656d8a27d7657a58e6066aa902bfb1a4aa00ae20" +dependencies = [ + "clap", + "heck", + "indexmap", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "tempfile", + "toml", +] + +[[package]] +name = "cc" +version = "1.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +dependencies = [ + "find-msvc-tools", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fetch_hyperlight_guest_capi" +version = "0.0.0" +dependencies = [ + "hyperlight_guest_capi", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flatbuffers" +version = "25.12.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" +dependencies = [ + "bitflags", + "rustc_version", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hyperlight-common" +version = "0.15.0" +source = "git+https://github.com/hyperlight-dev/hyperlight?rev=v0.15.0#9749e047750a215dea680707433a12f9b33b0397" +dependencies = [ + "anyhow", + "flatbuffers", + "log", + "spin", + "thiserror", + "tracing-core", +] + +[[package]] +name = "hyperlight-guest" +version = "0.15.0" +source = "git+https://github.com/hyperlight-dev/hyperlight?rev=v0.15.0#9749e047750a215dea680707433a12f9b33b0397" +dependencies = [ + "anyhow", + "flatbuffers", + "hyperlight-common", + "serde_json", + "tracing", +] + +[[package]] +name = "hyperlight-guest-bin" +version = "0.15.0" +source = "git+https://github.com/hyperlight-dev/hyperlight?rev=v0.15.0#9749e047750a215dea680707433a12f9b33b0397" +dependencies = [ + "buddy_system_allocator", + "flatbuffers", + "hyperlight-common", + "hyperlight-guest", + "hyperlight-guest-macro", + "hyperlight-guest-tracing", + "hyperlight-libc", + "linkme", + "log", + "spin", + "tracing", +] + +[[package]] +name = "hyperlight-guest-macro" +version = "0.15.0" +source = "git+https://github.com/hyperlight-dev/hyperlight?rev=v0.15.0#9749e047750a215dea680707433a12f9b33b0397" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "hyperlight-guest-tracing" +version = "0.15.0" +source = "git+https://github.com/hyperlight-dev/hyperlight?rev=v0.15.0#9749e047750a215dea680707433a12f9b33b0397" +dependencies = [ + "hyperlight-common", + "spin", + "tracing", + "tracing-core", +] + +[[package]] +name = "hyperlight-libc" +version = "0.15.0" +source = "git+https://github.com/hyperlight-dev/hyperlight?rev=v0.15.0#9749e047750a215dea680707433a12f9b33b0397" +dependencies = [ + "anyhow", + "bindgen", + "cc", + "glob", +] + +[[package]] +name = "hyperlight_guest_capi" +version = "0.15.0" +source = "git+https://github.com/hyperlight-dev/hyperlight?rev=v0.15.0#9749e047750a215dea680707433a12f9b33b0397" +dependencies = [ + "cbindgen", + "flatbuffers", + "hyperlight-common", + "hyperlight-guest", + "hyperlight-guest-bin", + "log", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "linkme" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83272d46373fb8decca684579ac3e7c8f3d71d4cc3aa693df8759e260ae41cf" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d59e20403c7d08fe62b4376edfe5c7fb2ef1e6b1465379686d0f21c8df444b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.3", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.3", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/examples/c/fetch-capi/Cargo.toml b/examples/c/fetch-capi/Cargo.toml new file mode 100644 index 0000000..c4e153c --- /dev/null +++ b/examples/c/fetch-capi/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fetch_hyperlight_guest_capi" +version = "0.0.0" +edition = "2024" +publish = false + +[dependencies] +hyperlight_guest_capi = { git = "https://github.com/hyperlight-dev/hyperlight", rev = "v0.15.0" } diff --git a/examples/c/fetch-capi/src/lib.rs b/examples/c/fetch-capi/src/lib.rs new file mode 100644 index 0000000..13f323d --- /dev/null +++ b/examples/c/fetch-capi/src/lib.rs @@ -0,0 +1,3 @@ +#![no_std] + +core::compile_error!("This crate is not meant to be built"); diff --git a/examples/c/guest/main.c b/examples/c/guest/main.c new file mode 100644 index 0000000..0126d00 --- /dev/null +++ b/examples/c/guest/main.c @@ -0,0 +1,19 @@ +#include +#include +#include + +int say_hello(const char *string) { + int n = printf("Hello %s\n", string); + fflush(stdout); + return n; +} + +HYPERLIGHT_WRAP_FUNCTION(say_hello, Int, 1, String); +void hyperlight_main(void) +{ + HYPERLIGHT_REGISTER_FUNCTION("SayHello", say_hello); +} + +hl_Vec *c_guest_dispatch_function(const hl_FunctionCall *function_call) { + return NULL; +} diff --git a/examples/guest/Cargo.lock b/examples/guest/Cargo.lock index 1d1eaf1..ca7c73c 100644 --- a/examples/guest/Cargo.lock +++ b/examples/guest/Cargo.lock @@ -13,9 +13,29 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] [[package]] name = "bindgen" @@ -45,11 +65,11 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "buddy_system_allocator" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0108968a3a2dab95b089c0fc3f1afa7759aa5ebe6f1d86d206d6f7ba726eb" +checksum = "c1af5a01adeeade54c9f5060300227a8ee64c05b6376f28e9b8ee3b72dd2056f" dependencies = [ - "spin 0.9.8", + "spin", ] [[package]] @@ -94,6 +114,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "find-msvc-tools" version = "0.1.4" @@ -102,9 +128,9 @@ checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "flatbuffers" -version = "25.9.23" +version = "25.12.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b6620799e7340ebd9968d2e0708eb82cf1971e9a16821e2091b6d6e475eed5" +checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" dependencies = [ "bitflags", "rustc_version", @@ -120,70 +146,111 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" name = "guest" version = "0.0.0" dependencies = [ - "bindgen", + "bindgen 0.72.1", "cc", "hyperlight-common", "hyperlight-guest", "hyperlight-guest-bin", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "hyperlight-common" -version = "0.11.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "409ac43d32b148aa71473d5bca0b5ff4cf72ddf4e9cb4550e9a189d807e6c0d4" +checksum = "a29190c35e3883c3e0944007f47a0997f8ebcf784a2a3f35c0311e513b019416" dependencies = [ "anyhow", "flatbuffers", "log", - "spin 0.10.0", + "spin", + "thiserror", + "tracing-core", ] [[package]] name = "hyperlight-guest" -version = "0.11.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27be04c1916c8483d6ec3486bd753b0e0757c30eb94aad53ba1e52da2f7ca00" +checksum = "82a676e88a6640b5cf621171c67f609d1e662713624562597518be6fdb0e0b30" dependencies = [ "anyhow", "flatbuffers", "hyperlight-common", - "hyperlight-guest-tracing", "serde_json", "tracing", ] [[package]] name = "hyperlight-guest-bin" -version = "0.11.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a8193539c50452e90e0c5ee906d251a1b2b6121a6040fc532b2468d9ef2184" +checksum = "0bc349c61dc771769308a2079d398488cd0c52d9bdcad8cf633922b288dd2aed" dependencies = [ "buddy_system_allocator", - "cc", - "cfg-if", "flatbuffers", - "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-macro", "hyperlight-guest-tracing", + "hyperlight-libc", + "linkme", "log", - "spin 0.10.0", + "spin", "tracing", ] +[[package]] +name = "hyperlight-guest-macro" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bef332d8490f2ebe5b8d52f7d39263f82580c54e9505980fea8186fd6679ea3" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "hyperlight-guest-tracing" -version = "0.11.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670c97963e19dd9e2855ed8ef1db47074d72036beb2ac5e621bd5796be2856b0" +checksum = "ca03b1ccd29c0c277555d8bd737257d0598554004f9667bb196227d5ed8b5b7e" dependencies = [ "hyperlight-common", - "spin 0.10.0", + "spin", "tracing", "tracing-core", ] +[[package]] +name = "hyperlight-libc" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd6f523d9383e9c8b3820bb141b4deb45b5470135ee069cbc387c3a2a3d55c7" +dependencies = [ + "anyhow", + "bindgen 0.71.1", + "cc", + "glob", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itertools" version = "0.13.0" @@ -215,6 +282,26 @@ dependencies = [ "windows-link", ] +[[package]] +name = "linkme" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83272d46373fb8decca684579ac3e7c8f3d71d4cc3aa693df8759e260ae41cf" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d59e20403c7d08fe62b4376edfe5c7fb2ef1e6b1465379686d0f21c8df444b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "lock_api" version = "0.4.14" @@ -226,9 +313,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "memchr" @@ -268,6 +355,15 @@ dependencies = [ "syn", ] +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.103" @@ -396,15 +492,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - [[package]] name = "spin" version = "0.10.0" @@ -425,11 +512,61 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -438,9 +575,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -449,9 +586,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" [[package]] name = "unicode-ident" @@ -464,3 +601,12 @@ name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] diff --git a/examples/guest/Cargo.toml b/examples/guest/Cargo.toml index 5ab53cc..53428e4 100644 --- a/examples/guest/Cargo.toml +++ b/examples/guest/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" publish = false [dependencies] -hyperlight-common = { version = "0.11.0", default-features = false } -hyperlight-guest = "0.11.0" -hyperlight-guest-bin = "0.11.0" +hyperlight-common = { version = "0.15.0", default-features = false } +hyperlight-guest = "0.15.0" +hyperlight-guest-bin = "0.15.0" [build-dependencies] cc = "1.2" diff --git a/examples/guest/src/host_print.c b/examples/guest/src/host_print.c index eab41ee..9551582 100644 --- a/examples/guest/src/host_print.c +++ b/examples/guest/src/host_print.c @@ -1,7 +1,9 @@ #include "host_print.h" -#include +#include int host_print(const char *s, size_t len) { - return printf("%.*s", (int)len, s); + int n = printf("%.*s", (int)len, s); + fflush(stdout); + return n; } diff --git a/examples/guest/src/main.rs b/examples/guest/src/main.rs index 7b7768d..1083336 100644 --- a/examples/guest/src/main.rs +++ b/examples/guest/src/main.rs @@ -29,7 +29,7 @@ fn host_print(s: impl AsRef<[u8]>) -> i32 { unsafe { ffi::host_print(s.as_ptr() as _, s.len()) } } -pub fn say_hello(func: &FunctionCall) -> Result> { +pub fn say_hello(func: FunctionCall) -> Result> { let params = func.parameters.as_deref().unwrap_or_default(); let Some(ParameterValue::String(name)) = params.first() else { return Err(HyperlightGuestError::new( @@ -48,7 +48,7 @@ pub extern "C" fn hyperlight_main() { "SayHello".into(), [ParameterType::String].into(), ReturnType::Int, - say_hello as usize, + say_hello, )); } diff --git a/examples/host/Cargo.lock b/examples/host/Cargo.lock index 58794df..00bd4ae 100644 --- a/examples/host/Cargo.lock +++ b/examples/host/Cargo.lock @@ -2,18 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.8.27", -] - [[package]] name = "aho-corasick" version = "1.1.4" @@ -34,9 +22,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arrayref" @@ -50,17 +38,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "autocfg" version = "1.5.0" @@ -75,21 +52,22 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "blake3" -version = "1.8.2" +version = "1.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", + "cpufeatures 0.3.0", ] [[package]] @@ -127,18 +105,6 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - [[package]] name = "cc" version = "1.2.44" @@ -163,6 +129,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core", +] + [[package]] name = "chrono" version = "0.4.42" @@ -176,9 +153,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" [[package]] name = "core-foundation-sys" @@ -195,6 +172,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -262,20 +248,6 @@ dependencies = [ "syn", ] -[[package]] -name = "elfcore" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824386967a6a98e7f99d5c15d40cd1534b0ebfc4193a7109689dcf5322e8d744" -dependencies = [ - "libc", - "nix", - "smallvec", - "thiserror 1.0.69", - "tracing", - "zerocopy 0.7.35", -] - [[package]] name = "find-msvc-tools" version = "0.1.4" @@ -284,11 +256,11 @@ checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "flatbuffers" -version = "25.9.23" +version = "25.12.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b6620799e7340ebd9968d2e0708eb82cf1971e9a16821e2091b6d6e475eed5" +checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "rustc_version", ] @@ -330,17 +302,29 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "rand_core", +] + [[package]] name = "git2" version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "libc", "libgit2-sys", "log", @@ -371,12 +355,6 @@ dependencies = [ "scroll", ] -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "host" version = "0.0.0" @@ -387,31 +365,32 @@ dependencies = [ [[package]] name = "hyperlight-common" -version = "0.11.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "409ac43d32b148aa71473d5bca0b5ff4cf72ddf4e9cb4550e9a189d807e6c0d4" +checksum = "a29190c35e3883c3e0944007f47a0997f8ebcf784a2a3f35c0311e513b019416" dependencies = [ "anyhow", "flatbuffers", "log", "spin", + "thiserror", "tracing", + "tracing-core", ] [[package]] name = "hyperlight-host" -version = "0.11.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49984fc8631a27d214550204350e4cc2ca304a37da759ea37407d0d1e4863eb6" +checksum = "634584fae781c9ea278a13f1fbecd25d220c543cfb5bbbbc496b7e30fc97c251" dependencies = [ "anyhow", - "bitflags 2.10.0", + "bitflags 2.13.0", "blake3", "built", "cfg-if", "cfg_aliases", "crossbeam-channel", - "elfcore", "flatbuffers", "goblin", "hyperlight-common", @@ -427,9 +406,8 @@ dependencies = [ "rand", "rust-embed", "serde_json", - "sha256", "termcolor", - "thiserror 2.0.17", + "thiserror", "tracing", "tracing-core", "tracing-log", @@ -608,7 +586,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "333f77a20344a448f3f70664918135fddeb804e938f28a99d685bd92926e0b19" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "kvm-bindings", "libc", "vmm-sys-util", @@ -622,9 +600,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libgit2-sys" @@ -644,7 +622,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "libc", ] @@ -677,9 +655,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "memchr" @@ -689,12 +667,12 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "metrics" -version = "0.24.2" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dea7ac8057892855ec285c440160265225438c3c45072613c25a4b26e98ef5" +checksum = "89550ee9f79e88fef3119de263694973a8adb26c21d75322164fb8c493039fe2" dependencies = [ - "ahash", "portable-atomic", + "rapidhash", ] [[package]] @@ -706,7 +684,7 @@ dependencies = [ "libc", "num_enum", "vmm-sys-util", - "zerocopy 0.8.27", + "zerocopy", ] [[package]] @@ -717,21 +695,10 @@ checksum = "748f59f22dccd910080a6315fc692bd04bd8c94ae2fc346957ec34b7d985eaa0" dependencies = [ "libc", "mshv-bindings", - "thiserror 2.0.17", + "thiserror", "vmm-sys-util", ] -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -823,15 +790,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy 0.8.27", -] - [[package]] name = "proc-macro2" version = "1.0.103" @@ -857,32 +815,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "rand" -version = "0.9.4" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" -dependencies = [ - "rand_chacha", - "rand_core", -] +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] -name = "rand_chacha" -version = "0.9.0" +name = "rand" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ - "ppv-lite86", + "chacha20", + "getrandom 0.4.3", "rand_core", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rapidhash" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" dependencies = [ - "getrandom 0.3.4", + "rustversion", ] [[package]] @@ -893,7 +854,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.17", + "thiserror", ] [[package]] @@ -915,9 +876,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rust-embed" -version = "8.9.0" +version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca" +checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -1061,23 +1022,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] -[[package]] -name = "sha256" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6" -dependencies = [ - "async-trait", - "bytes", - "hex", - "sha2", - "tokio", -] - [[package]] name = "shellexpand" version = "3.1.1" @@ -1147,38 +1095,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.69" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -1195,21 +1123,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tokio" -version = "1.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" -dependencies = [ - "bytes", - "pin-project-lite", -] - [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -1219,9 +1137,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -1230,9 +1148,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -1281,11 +1199,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.18.1" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "js-sys", "wasm-bindgen", ] @@ -1582,34 +1500,13 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - [[package]] name = "zerocopy" version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "zerocopy-derive 0.8.27", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "zerocopy-derive", ] [[package]] diff --git a/examples/host/Cargo.toml b/examples/host/Cargo.toml index cdafb59..0ac28e9 100644 --- a/examples/host/Cargo.toml +++ b/examples/host/Cargo.toml @@ -6,4 +6,4 @@ publish = false [dependencies] anyhow = "1.0" -hyperlight-host = "0.11.0" +hyperlight-host = "0.15.0" diff --git a/examples/host/src/main.rs b/examples/host/src/main.rs index e37aee1..7a80fa3 100644 --- a/examples/host/src/main.rs +++ b/examples/host/src/main.rs @@ -10,7 +10,7 @@ fn main() -> anyhow::Result<()> { let mut config = SandboxConfiguration::default(); config.set_heap_size(1024 * 1024); // 1 MiB - config.set_stack_size(1024 * 1024); // 1 MiB + config.set_scratch_size(1024 * 1024); // 1 MiB // create the sandbox let mut sbox = hyperlight_host::UninitializedSandbox::new(guest, Some(config))?.evolve()?; diff --git a/justfile b/justfile index c87396f..f97432a 100644 --- a/justfile +++ b/justfile @@ -26,7 +26,21 @@ build-guest: cargo hyperlight build --manifest-path ./examples/guest/Cargo.toml run-guest: build-guest - cargo run --manifest-path ./examples/host/Cargo.toml -- ./target/x86_64-hyperlight-none/debug/guest + cargo run --manifest-path ./examples/host/Cargo.toml -- ./target/{{arch()}}-hyperlight-none/debug/guest test-new: cargo test --test new + +test-clang-parser: + cargo test --test clang_parser + +test: test-new test-clang-parser + +build-c-sysroot: + cargo hyperlight build-c-sysroot --manifest-path examples/c/fetch-capi/Cargo.toml --c-sysroot-dir examples/c/sysroot + +build-c-guest: build-c-sysroot + examples/c/sysroot/bin/clang examples/c/guest/main.c -o examples/c/guest/guest -lhyperlight_guest_capi -fuse-ld=lld + +run-c-guest: build-c-guest + cargo run --manifest-path ./examples/host/Cargo.toml -- ./examples/c/guest/guest diff --git a/src/cargo_cmd.rs b/src/cargo_cmd.rs index 6c0b1de..920d364 100644 --- a/src/cargo_cmd.rs +++ b/src/cargo_cmd.rs @@ -22,10 +22,6 @@ pub trait CargoCmd { flags: impl AsRef, ) -> &mut Self; fn allow_unstable(&mut self) -> &mut Self; - fn resolve_env( - &self, - base: impl IntoIterator, impl AsRef)>, - ) -> HashMap; fn checked_output(&mut self) -> Result; fn checked_status(&mut self) -> Result<()>; } @@ -48,8 +44,8 @@ impl CargoBinary { pub fn find_cargo() -> Result { let cargo = match env::var_os("CARGO") { - Some(cargo) => Path::new(&cargo).canonicalize()?, - None => which::which("cargo")?.canonicalize()?, + Some(cargo) => PathBuf::from(cargo), + None => which::which("cargo")?, }; let rustup_toolchain = env::var_os("RUSTUP_TOOLCHAIN"); Ok(CargoBinary { @@ -195,13 +191,6 @@ impl CargoCmd for Command { self.env("RUSTC_BOOTSTRAP", "1") } - fn resolve_env( - &self, - base: impl IntoIterator, impl AsRef)>, - ) -> HashMap { - merge_env(base, self.get_envs()) - } - fn checked_output(&mut self) -> Result { let output = self.output(); diff --git a/src/cli.rs b/src/cli.rs index a8298a0..17e0df8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -17,6 +17,9 @@ pub struct Args { pub manifest_path: Option, pub target_dir: PathBuf, pub target: String, + pub host: String, + pub with_guest_capi: bool, + pub c_sysroot_dir: Option, pub env: HashMap, pub current_dir: PathBuf, pub clang: Option, @@ -170,10 +173,17 @@ impl Args { let target_dir = value.current_dir.join(target_dir); + let host = value + .host + .unwrap_or(env!("CARGO_HYPERLIGHT_HOST_TRIPLE").to_string()); + Ok(Args { manifest_path, target_dir, target, + host, + with_guest_capi: value.with_guest_capi, + c_sysroot_dir: value.c_sysroot_dir, env: value.env, current_dir: value.current_dir, clang: toolchain::find_cc().ok(), @@ -196,6 +206,17 @@ struct ArgsImpl { /// Target triple to build for target: Option, + /// Target triple to use for host utilities/wrappers, enabling a + /// building a distributable C sysroot for Canadian cross usecases + host: Option, + + /// Whether to include hyperlight-guest-capi headers and libs in + /// the built sysroot, used for building distributable C sysroots + with_guest_capi: bool, + + /// When building a C sysroot, the target C sysroot directory + c_sysroot_dir: Option, + /// Environment variables to set env: HashMap, @@ -203,6 +224,20 @@ struct ArgsImpl { pub current_dir: PathBuf, } +fn parse_flag(flag: &str, arg: &OsStr) -> Option { + let value = arg.strip_prefix(flag)?; + if value.is_empty() { + Some(true) + } else { + let lower = value.strip_prefix("=")?.to_ascii_lowercase(); + if lower == "false" || lower == "0" { + Some(false) + } else { + Some(true) + } + } +} + fn parse_arg( flag: &str, arg: &OsStr, @@ -237,6 +272,15 @@ impl ArgsImpl { this.target = Some(triplet.to_string_lossy().to_string()); continue; } + if let Some(host) = parse_arg("--host", &arg, &mut args) { + this.host = Some(host.to_string_lossy().to_string()); + } + if let Some(capi) = parse_flag("--with-guest-capi", &arg) { + this.with_guest_capi = capi; + } + if let Some(dir) = parse_arg("--c-sysroot-dir", &arg, &mut args) { + this.c_sysroot_dir = Some(PathBuf::from(dir)); + } } this } diff --git a/src/command.rs b/src/command.rs index 9beccf4..86a1155 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,10 +1,9 @@ use std::collections::{BTreeMap, HashMap}; -use std::convert::Infallible; -use std::ffi::{OsStr, OsString, c_char}; +use std::env; +use std::ffi::{OsStr, OsString}; use std::fmt::Debug; use std::path::{Path, PathBuf}; use std::process::Command as StdCommand; -use std::{env, iter}; use anyhow::{Context, Result}; use os_str_bytes::OsStrBytesExt; @@ -65,7 +64,7 @@ impl Debug for Command { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let args = self.build_args_infallible(); let mut cmd = self.command(); - cmd.populate_from_args(&args); + cmd.populate_from_args(&args, false); write!(f, "env ")?; if let Some(current_dir) = &self.current_dir { @@ -529,7 +528,35 @@ impl Command { fn command(&self) -> StdCommand { let mut command = self.cargo.command(); - command.args(self.get_args()); + // Filter out --target and --target-dir from forwarded args since + // populate_from_args sets them via env vars with the resolved values + let args: Vec<_> = self.get_args().map(|a| a.to_owned()).collect(); + let mut skip_next = false; + for arg in args.iter() { + if skip_next { + skip_next = false; + continue; + } + let arg_str = arg.to_string_lossy(); + if arg_str == "--target" || arg_str == "--target-dir" { + skip_next = true; // skip the next arg (the value) + continue; + } + if arg_str.starts_with("--target=") || arg_str.starts_with("--target-dir=") { + continue; + } + if arg_str == "--host" { + skip_next = true; + continue; + } + if arg_str.starts_with("--host=") { + continue; + } + if arg_str.starts_with("--with-guest-capi") { + continue; + } + command.arg(arg); + } if let Some(cwd) = &self.current_dir { command.current_dir(cwd); } @@ -569,7 +596,7 @@ impl Command { self.cargo.path.as_os_str() } - fn build_args(&self) -> Args { + pub fn build_args(&self) -> Args { // parse the arguments and environment variables match Args::parse( self.get_args(), @@ -632,132 +659,11 @@ impl Command { .context("Failed to prepare sysroot")?; self.command() - .populate_from_args(&args) + .populate_from_args(&args, false) .checked_status() .context("Failed to execute cargo")?; Ok(()) } - - /// Executes the cargo command, replacing the current process. - /// - /// This function will never return on success, as it replaces the current process - /// with the cargo process. On error, it will print the error and exit with code 101. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```no_run - /// use cargo_hyperlight::cargo; - /// - /// cargo() - /// .unwrap() - /// .arg("build") - /// .exec(); // This will never return - /// ``` - /// - /// # Errors - /// - /// This function will exit the process with code 101 if: - /// - The sysroot preparation fails - /// - The process replacement fails - pub fn exec(&self) -> ! { - match self.exec_impl() { - Err(e) => { - eprintln!("{e:?}"); - std::process::exit(101); - } - } - } - - /// Internal implementation of process replacement. - /// - /// This method prepares the sysroot and then calls the low-level `exec` function - /// to replace the current process. - fn exec_impl(&self) -> anyhow::Result { - let args = self.build_args(); - - args.prepare_sysroot() - .context("Failed to prepare sysroot")?; - - let mut command = self.command(); - command.populate_from_args(&args); - - if let Some(cwd) = self.get_current_dir() { - env::set_current_dir(cwd).context("Failed to change current directory")?; - } - - Ok(exec( - command.get_program(), - command.get_args(), - command.resolve_env(self.base_env()), - )?) - } -} - -/// Replaces the current process with the specified program using `execvpe`. -/// -/// This function converts the provided arguments and environment variables into -/// the format expected by the `execvpe` system call and then replaces the current -/// process with the new program. -/// -/// # Arguments -/// -/// * `program` - The path to the program to execute -/// * `args` - The command-line arguments to pass to the program -/// * `envs` - The environment variables to set for the new process -/// -/// # Returns -/// -/// This function should never return on success. On failure, it returns an -/// `std::io::Error` describing what went wrong. -/// -/// # Safety -/// -/// This function uses unsafe code to call `libc::execvpe`. The implementation -/// carefully manages memory to ensure null-terminated strings are properly -/// constructed for the system call. -fn exec( - program: impl AsRef, - args: impl IntoIterator>, - envs: impl IntoIterator, impl AsRef)>, -) -> std::io::Result { - let mut env_bytes = vec![]; - let mut env_offsets = vec![]; - for (k, v) in envs.into_iter() { - env_offsets.push(env_bytes.len()); - env_bytes.extend_from_slice(k.as_ref().as_encoded_bytes()); - env_bytes.push(b'='); - env_bytes.extend_from_slice(v.as_ref().as_encoded_bytes()); - env_bytes.push(0); - } - let env_ptrs = env_offsets - .into_iter() - .map(|offset| env_bytes[offset..].as_ptr() as *const c_char) - .chain(iter::once(std::ptr::null())) - .collect::>(); - - let mut arg_bytes = vec![]; - let mut arg_offsets = vec![]; - - arg_offsets.push(arg_bytes.len()); - arg_bytes.extend_from_slice(program.as_ref().as_encoded_bytes()); - arg_bytes.push(0); - - for arg in args { - arg_offsets.push(arg_bytes.len()); - arg_bytes.extend_from_slice(arg.as_ref().as_encoded_bytes()); - arg_bytes.push(0); - } - let arg_ptrs = arg_offsets - .into_iter() - .map(|offset| arg_bytes[offset..].as_ptr() as *const c_char) - .chain(iter::once(std::ptr::null())) - .collect::>(); - - unsafe { libc::execvpe(arg_ptrs[0], arg_ptrs.as_ptr(), env_ptrs.as_ptr()) }; - - Err(std::io::Error::last_os_error()) } /// Returns `true` if the given environment variable should be preserved diff --git a/src/lib.rs b/src/lib.rs index 39a5897..230492a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,11 +4,13 @@ mod cargo_cmd; mod cli; mod command; mod sysroot; -mod toolchain; +pub mod toolchain; +pub mod toolchain_flags; use cargo_cmd::CargoCmd; -use cli::Args; +pub use cli::Args; pub use command::Command; +mod util; /// Constructs a new `Command` for launching cargo targeting /// [hyperlight](https://github.com/hyperlight-dev/hyperlight) guest code. @@ -58,12 +60,24 @@ impl Args { self.sysroot_dir().join("target") } - pub fn libs_dir(&self) -> std::path::PathBuf { + pub fn c_libs_dir(&self) -> std::path::PathBuf { + self.sysroot_dir().join("lib") + } + + pub fn wrapper_src_dir(&self) -> std::path::PathBuf { + self.sysroot_dir().join("wrapper") + } + + pub fn wrapper_dir(&self) -> std::path::PathBuf { + self.sysroot_dir().join("bin") + } + + pub fn rust_libs_dir(&self) -> std::path::PathBuf { self.triplet_dir().join("lib") } pub fn includes_dir(&self) -> std::path::PathBuf { - self.triplet_dir().join("include") + self.sysroot_dir().join("include") } pub fn crate_dir(&self) -> std::path::PathBuf { @@ -72,11 +86,11 @@ impl Args { } trait CargoCommandExt { - fn populate_from_args(&mut self, args: &Args) -> &mut Self; + fn populate_from_args(&mut self, args: &Args, bootstrap: bool) -> &mut Self; } impl CargoCommandExt for std::process::Command { - fn populate_from_args(&mut self, args: &Args) -> &mut Self { + fn populate_from_args(&mut self, args: &Args, bootstrap: bool) -> &mut Self { self.target(&args.target); self.sysroot(args.sysroot_dir()); self.append_rustflags("--cfg=hyperlight"); @@ -95,7 +109,7 @@ impl CargoCommandExt for std::process::Command { } else { // do nothing, let cc-rs find ar itself } - self.append_cflags(&args.target, toolchain::cflags(args)); + self.append_cflags(&args.target, toolchain::cflags(args, bootstrap).joined()); self } diff --git a/src/main.rs b/src/main.rs index e89babc..b8e152a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,106 @@ -use std::env; +use std::ffi::{OsStr, OsString}; +use std::{env, iter}; -use cargo_hyperlight::cargo; +use anyhow::{Result, anyhow}; +use cargo_hyperlight::{Args, cargo, toolchain, toolchain_flags}; mod new; mod perf; +mod util; const VERSION: &str = env!("CARGO_PKG_VERSION"); const GIT_HASH: &str = env!("GIT_HASH"); const GIT_DATE: &str = env!("GIT_DATE"); +enum FlagKind { + C, + Ld, + Libs, +} +impl FlagKind { + fn parse(x: &OsStr) -> Option { + use FlagKind::*; + match x.to_str()? { + "cflags" => Some(C), + "ldflags" => Some(Ld), + "libs" => Some(Libs), + _ => None, + } + } + fn get_flags(&self, args: &Args) -> toolchain_flags::Flags { + use FlagKind::*; + match self { + C => toolchain::cflags(args, false), + Ld => toolchain::ldflags(args), + Libs => toolchain::libs(args), + } + } +} +enum SpecialCommand { + Version, + Perf, + New, + BuildCSysroot, + Flags(FlagKind), +} +impl SpecialCommand { + fn parse(x: &OsStr) -> Option { + use SpecialCommand::*; + match x.to_str()? { + "--version" | "-V" => Some(Version), + "perf" => Some(Perf), + "new" => Some(New), + "build-c-sysroot" => Some(BuildCSysroot), + _ => FlagKind::parse(x).map(Flags), + } + } + fn execute(self, args: impl Iterator) -> Result<()> { + use SpecialCommand::*; + match self { + Version => { + println!("cargo-hyperlight {} ({} {})", VERSION, GIT_HASH, GIT_DATE); + } + Perf => perf::run(args)?, + New => new::run(args)?, + BuildCSysroot => { + let built_args = cargo()? + // a C sysroot needs the C API library + .arg("--with-guest-capi") + .args(args) + .build_args(); + let sysroot_dir = built_args + .c_sysroot_dir + .as_ref() + .ok_or(anyhow!("Usage: cargo-hyperlight build-c-sysroot [opts] --c-sysroot-dir "))?; + built_args.prepare_sysroot()?; + util::union_glob( + iter::once(&built_args.wrapper_dir()), + &sysroot_dir.join("bin"), + "**/*", + )?; + util::union_glob( + iter::once(&built_args.includes_dir()), + &sysroot_dir.join("include"), + "**/*.h", + )?; + util::union_glob_with_predicate( + iter::once(&built_args.c_libs_dir()), + &sysroot_dir.join("lib"), + "**/*", + |x| !x.starts_with("rustlib"), + )?; + } + Flags(k) => { + let built_args = cargo()?.args(args).build_args(); + built_args.prepare_sysroot()?; + let flags = k.get_flags(&built_args).joined(); + println!("{}", flags.to_str().ok_or(anyhow!("flags were not UTF-8"))?); + } + } + Ok(()) + } +} + fn main() { // Skip binary name; when invoked as `cargo hyperlight`, cargo passes // "hyperlight" as argv[1] — skip that too. @@ -17,28 +109,16 @@ fn main() { args.next(); } - match args.peek().map(|a| a.to_os_string()) { - Some(a) if a == "--version" || a == "-V" => { - println!("cargo-hyperlight {} ({} {})", VERSION, GIT_HASH, GIT_DATE); - } - Some(a) if a == "perf" => { - if let Err(e) = perf::run(args) { - eprintln!("{e:?}"); - std::process::exit(1); - } - } - Some(a) if a == "new" => { - if let Err(e) = new::run(args) { - eprintln!("{e:?}"); - std::process::exit(1); - } - } - _ => { - cargo() - .expect("Failed to create cargo command") - .args(args) - .status() - .expect("Failed to execute cargo"); + if let Some(sc) = args.peek().and_then(|x| SpecialCommand::parse(x)) { + if let Err(e) = sc.execute(args) { + eprintln!("{e:?}"); + std::process::exit(1); } + } else { + cargo() + .expect("Failed to create cargo command") + .args(args) + .status() + .expect("Failed to execute cargo"); } } diff --git a/src/sysroot.rs b/src/sysroot.rs index f9545d6..0e49de7 100644 --- a/src/sysroot.rs +++ b/src/sysroot.rs @@ -10,18 +10,18 @@ use crate::cli::Args; const CARGO_TOML: &str = include_str!("dummy/_Cargo.toml"); const LIB_RS: &str = include_str!("dummy/_lib.rs"); -#[derive(serde::Deserialize, Default)] -struct CargoBuildMessageTarget { - name: String, +#[derive(serde::Deserialize, Default, Debug)] +pub(crate) struct CargoBuildMessageTarget { + pub(crate) name: String, } -#[derive(serde::Deserialize)] -struct CargoBuildMessage { - reason: String, +#[derive(serde::Deserialize, Debug)] +pub(crate) struct CargoBuildMessage { + pub(crate) reason: String, #[serde(default)] - target: CargoBuildMessageTarget, + pub(crate) target: CargoBuildMessageTarget, #[serde(default)] - filenames: Vec, + pub(crate) filenames: Vec, } pub fn build(args: &Args) -> Result<()> { @@ -45,10 +45,31 @@ pub fn build(args: &Args) -> Result<()> { spec.remove("rustc-abi"); spec } + "aarch64-hyperlight-none" => { + let mut spec = get_spec(args, "aarch64-unknown-none")?; + let Value::Object(custom) = json!({ + "code-model": "small", + "linker": "rust-lld", + "linker-flavor": "gnu-lld", + "pre-link-args": { + "gnu-lld": ["-znostart-stop-gc"], + }, + "relocation-model": "pic", + "direct-access-external-data": true, + "position-independent-executables": true, + "features": "+v8.1a,+strict-align,+neon,+fp-armv8" + }) else { + unreachable!() + }; + spec.extend(custom); + spec.remove("rustc-abi"); + spec + } triplet => bail!( "Unsupported target triple: {triplet:?} Supported values are: - * x86_64-hyperlight-none" + * x86_64-hyperlight-none + * aarch64-hyperlight-none" ), }; @@ -56,7 +77,7 @@ Supported values are: let target_dir = args.build_dir(); let triplet_dir = args.triplet_dir(); let crate_dir = args.crate_dir(); - let lib_dir = args.libs_dir(); + let lib_dir = args.rust_libs_dir(); std::fs::create_dir_all(&triplet_dir).context("Failed to create sysroot directories")?; std::fs::write( @@ -180,7 +201,8 @@ fn get_spec(args: &Args, triplet: impl AsRef) -> Result> .envs(args.env.iter()) .current_dir(&args.current_dir) .arg("rustc") - .target(triplet) + .arg("--target") + .arg(triplet.as_ref()) .manifest_path(&args.manifest_path) .arg("-Zunstable-options") .arg("--print=target-spec-json") diff --git a/src/toolchain.rs b/src/toolchain.rs index 0773935..e410bd2 100644 --- a/src/toolchain.rs +++ b/src/toolchain.rs @@ -1,11 +1,14 @@ -use std::ffi::OsString; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; -use anyhow::{Context, Result, bail}; +use anyhow::{Context, Result, ensure}; +use proc_macro2::TokenStream; +use quote::{TokenStreamExt, quote}; use regex::Regex; use crate::cargo_cmd::{CargoCmd, cargo_cmd}; use crate::cli::Args; +use crate::sysroot::CargoBuildMessage; +use crate::{toolchain_flags, util}; #[derive(serde::Deserialize)] struct CargoMetadata { @@ -21,7 +24,43 @@ struct CargoMetadataPackage { version: semver::Version, } -pub fn find_libc_dir(args: &Args) -> Result { +struct PackageDirectories { + hyperlight_libc: Option, + hyperlight_guest_bin: Option, + hyperlight_guest_capi: Option, +} +impl PackageDirectories { + fn libc(&self) -> Result { + self.hyperlight_libc + .as_ref() + .or(self.hyperlight_guest_bin.as_ref()) + .cloned() + .context( + "Could not find hyperlight-libc or hyperlight-guest-bin package in cargo metadata", + ) + } + fn guest_capi(&self) -> Result { + self.hyperlight_guest_capi + .clone() + .context("Could not find hyperlight-guest-capi package in cargo metadata") + } +} + +fn find_package_dir(metadata: &CargoMetadata, name: &str) -> Result> { + metadata + .packages + .iter() + .find(|x| x.name == name) + .map(|pkg| { + pkg.manifest_path + .parent() + .with_context(|| format!("Failed to get directory for {name}")) + .map(|x| x.to_path_buf()) + }) + .transpose() +} + +fn find_package_dirs(args: &Args) -> Result { let metadata = cargo_cmd()? .env_clear() .envs(args.env.iter()) @@ -37,37 +76,177 @@ pub fn find_libc_dir(args: &Args) -> Result { let metadata = serde_json::from_slice::(&metadata.stdout) .context("Failed to parse cargo metadata")?; - let hyperlight_libc = metadata - .packages - .iter() - .find(|pkg| pkg.name == "hyperlight-libc"); - - if let Some(hyperlight_libc) = hyperlight_libc { - let hyperlight_libc_dir = hyperlight_libc - .manifest_path - .parent() - .context("Failed to get directory for hyperlight-libc")?; - return Ok(hyperlight_libc_dir.to_path_buf()); + Ok(PackageDirectories { + hyperlight_libc: find_package_dir(&metadata, "hyperlight-libc")?, + hyperlight_guest_bin: find_package_dir(&metadata, "hyperlight-guest-bin")?, + hyperlight_guest_capi: if args.with_guest_capi { + find_package_dir(&metadata, "hyperlight_guest_capi")? + } else { + None + }, + }) +} + +fn copy_includes(src_dirs: impl Iterator>, dst_dir: &Path) -> Result<()> { + util::union_glob(src_dirs, dst_dir, "**/*.h") +} + +fn build_guest_capi(args: &Args, capi_dir: &Path) -> Result<()> { + use crate::CargoCommandExt; + let output = cargo_cmd()? + .env_clear() + .envs(args.env.iter()) + .arg("build") + .manifest_path(&Some(capi_dir.join("Cargo.toml"))) + .target_dir(args.build_dir()) + .arg("--message-format=json") + .env_remove("RUSTC_WORKSPACE_WRAPPER") + .populate_from_args(args, true) + .output() + .context("Failed to build capi cargo project")?; + ensure!( + output.status.success(), + "Failed to build capi\n{}", + String::from_utf8_lossy(&output.stderr) + ); + + let messages = String::from_utf8_lossy(&output.stdout); + + for message in messages.lines() { + let message = serde_json::from_str::(message) + .context("Failed to parse sysroot build message")?; + if message.reason == "compiler-artifact" { + let name = message.target.name; + if name == "hyperlight_guest_capi" { + for file in message.filenames { + let file_name = file.file_name().with_context(|| { + format!( + "Failed to get filename for capi build artifact {}", + file.display() + ) + })?; + let dst = args.c_libs_dir().join(file_name); + std::fs::copy(&file, &dst)?; + } + } + } } - let hyperlight_guest_bin = metadata - .packages - .iter() - .find(|pkg| pkg.name == "hyperlight-guest-bin"); - - if let Some(hyperlight_guest_bin) = hyperlight_guest_bin { - let hyperlight_guest_bin_dir = hyperlight_guest_bin - .manifest_path - .parent() - .context("Failed to get directory for hyperlight-guest-bin")?; - return Ok(hyperlight_guest_bin_dir.to_path_buf()); + Ok(()) +} + +fn path_to_tokens(p: &Path) -> TokenStream { + let mut tokens = quote! { + let mut x: ::std::path::PathBuf = ::std::path::PathBuf::new(); + }; + for x in p.iter() { + let s = x.to_string_lossy(); + tokens.append_all(quote! { + x.push(#s); + }); } + tokens.append_all(quote! { x }); + quote! { { #tokens } } +} + +fn build_wrappers(args: &Args) -> Result<()> { + const CARGO_TOML: &str = include_str!("wrapper/_Cargo.toml"); + const MAIN_RS: &str = include_str!("wrapper/_main.rs"); + const CLANG_PARSER_RS: &str = include_str!("wrapper/_clang_parser.rs"); + const FLAGS_RS: &str = include_str!("toolchain_flags.rs"); + + let wrapper_src_dir = args.wrapper_src_dir(); + std::fs::create_dir_all(&wrapper_src_dir) + .context("Failed to create wrapper source directory")?; + std::fs::write(wrapper_src_dir.join("Cargo.toml"), CARGO_TOML)?; + let wrapper_src_src_dir = wrapper_src_dir.join("src"); + std::fs::create_dir_all(&wrapper_src_src_dir) + .context("Failed to create wrapper source src directory")?; + std::fs::write(wrapper_src_src_dir.join("main.rs"), MAIN_RS)?; + std::fs::write(wrapper_src_src_dir.join("clang_parser.rs"), CLANG_PARSER_RS)?; + std::fs::write(wrapper_src_src_dir.join("toolchain_flags.rs"), FLAGS_RS)?; + let includes_toks = path_to_tokens(args.includes_dir().strip_prefix(args.sysroot_dir())?); + let c_libs_toks = path_to_tokens(args.c_libs_dir().strip_prefix(args.sysroot_dir())?); + let wrapper_toks = path_to_tokens(args.wrapper_dir().strip_prefix(args.sysroot_dir())?); + let target = &args.target; + let with_guest_capi = args.with_guest_capi; + std::fs::write( + wrapper_src_src_dir.join("args.rs"), + (quote! { + pub(crate) fn args(root: &std::path::Path) -> crate::toolchain_flags::Args { + crate::toolchain_flags::Args { + includes_dir: root.join(#includes_toks), + c_libs_dir: root.join(#c_libs_toks), + wrapper_dir: root.join(#wrapper_toks), + target: #target.to_string(), + with_guest_capi: #with_guest_capi, + } + } + }) + .to_string(), + )?; + + let output = cargo_cmd()? + .env_clear() + .envs(args.env.iter()) + .current_dir(&args.current_dir) + .arg("build") + .target(&args.host) + .manifest_path(&Some(wrapper_src_dir.join("Cargo.toml"))) + .target_dir(args.build_dir()) + .arg("--release") + .arg("--message-format=json") + .env_remove("RUSTC_WORKSPACE_WRAPPER") + .output() + .context("Failed to build wrapper cargo project")?; + ensure!( + output.status.success(), + "Failed to build wrapper\n{}", + String::from_utf8_lossy(&output.stderr) + ); - bail!("Could not find hyperlight-libc or hyperlight-guest-bin package in cargo metadata"); + let messages = String::from_utf8_lossy(&output.stdout); + + for message in messages.lines() { + let message = serde_json::from_str::(message) + .context("Failed to parse wrapper build message")?; + if message.reason == "compiler-artifact" { + let name = message.target.name; + if name == "hyperlight-sysroot-wrappers" { + let files: Vec<_> = message + .filenames + .iter() + .filter(|x| x.extension() != Some("pdb".as_ref())) + .collect(); + ensure!( + files.len() == 1, + "hyperlight-sysroot-wrappers produced wrong number of binaries", + ); + let target_uses_exe = message.filenames[0].extension() == Some("exe".as_ref()); + let dir = args.wrapper_dir(); + let bin_name = |n| { + let mut p = dir.join(n); + if target_uses_exe { + p.set_extension("exe"); + } + p + }; + std::fs::create_dir_all(&dir).context("Failed to create wrapper bin directory")?; + std::fs::copy(&message.filenames[0], bin_name("hyperlight-config"))?; + std::fs::copy(&message.filenames[0], bin_name("clang"))?; + std::fs::copy( + &message.filenames[0], + bin_name(&format!("{}-clang", target)), + )?; + } + } + } + Ok(()) } pub fn prepare(args: &Args) -> Result<()> { - let libc_dir = find_libc_dir(args)?; + let package_dirs = find_package_dirs(args)?; + let libc_dir = package_dirs.libc()?; let include_dst_dir = args.includes_dir(); @@ -75,69 +254,61 @@ pub fn prepare(args: &Args) -> Result<()> { .context("Failed to create sysroot include directory")?; // Detect which libc variant is present: picolibc or legacy musl - let include_dirs: &[&str] = &[ + let mut include_dirs: Vec<&str> = vec![ // directories for musl "third_party/printf/", "third_party/musl/include", "third_party/musl/arch/generic", - "third_party/musl/arch/x86_64", "third_party/musl/src/internal", // directories for picolibc "third_party/picolibc/libc/include", "third_party/picolibc/libc/stdio", "include", ]; + if !args.target.starts_with("aarch64") { + include_dirs.push("third_party/musl/arch/x86_64"); + } - for dir in include_dirs { - let include_src_dir = libc_dir.join(dir); - let files = glob::glob(&format!("{}/**/*.h", include_src_dir.display())) - .context("Failed to read include source directory")?; + let capi_dir = args + .with_guest_capi + .then(|| { + let d = package_dirs.guest_capi()?; + build_guest_capi(args, &d)?; + Ok::<_, anyhow::Error>(d) + }) + .transpose()?; - for file in files { - let src = file.context("Failed to read include source file")?; - let dst = src.strip_prefix(&include_src_dir).unwrap(); - let dst = include_dst_dir.join(dst); + let include_dirs = include_dirs + .into_iter() + .map(|dir| libc_dir.join(dir)) + .chain(capi_dir.map(|x| x.join("include"))); + copy_includes(include_dirs, &include_dst_dir)?; - std::fs::create_dir_all(dst.parent().unwrap()) - .context("Failed to create include subdirectory")?; - std::fs::copy(&src, &dst).context("Failed to copy include file")?; - } - } + build_wrappers(args)?; Ok(()) } -pub fn cflags(args: &Args) -> OsString { - const FLAGS: &[&str] = &[ - // terrible hack, see - // https://github.com/hyperlight-dev/hyperlight/blob/main/src/hyperlight_guest_bin/build.rs#L80 - "--target=x86_64-unknown-linux-none", - "-U__linux__", - // Our rust target also has this set since it based off "x86_64-unknown-none" - "-fPIC", - // We don't support stack protectors at the moment, but Arch Linux clang - // auto-enables them for -linux platforms, so explicitly disable them. - "-fno-stack-protector", - "-fstack-clash-protection", - "-mstack-probe-size=4096", - "-mno-red-zone", - "-nostdlibinc", - // Define HYPERLIGHT as we use this to conditionally enable/disable code - // in the libc headers - "-DHYPERLIGHT=1", - "-D__HYPERLIGHT__=1", - ]; - - let mut flags = OsString::new(); - for flag in FLAGS { - flags.push(flag); - flags.push(" "); +impl From<&Args> for toolchain_flags::Args { + fn from(args: &Args) -> toolchain_flags::Args { + toolchain_flags::Args { + includes_dir: args.includes_dir(), + c_libs_dir: args.c_libs_dir(), + wrapper_dir: args.wrapper_dir(), + target: args.target.clone(), + with_guest_capi: args.with_guest_capi, + } } - flags.push(" "); - flags.push("-isystem"); - flags.push(" "); - flags.push(args.includes_dir().as_os_str()); - flags +} + +pub fn cflags(args: &Args, bootstrap: bool) -> toolchain_flags::Flags { + toolchain_flags::cflags(&args.into(), bootstrap) +} +pub fn ldflags(args: &Args) -> toolchain_flags::Flags { + toolchain_flags::ldflags(&args.into()) +} +pub fn libs(args: &Args) -> toolchain_flags::Flags { + toolchain_flags::libs(&args.into()) } pub fn find_cc() -> Result { @@ -153,12 +324,21 @@ pub fn find_cc() -> Result { } pub fn find_ar() -> Result { - if let Ok(path) = which::which("ar") { - return Ok(path); - } - if let Ok(path) = which::which("llvm-ar") { - return Ok(path); + #[cfg(not(target_os = "macos"))] + let ar = which::which("ar"); + let llvm_ar = which::which("llvm-ar"); + // The system archiver on macOS can't deal with ELFs, so check + // `llvm-ar` first there (but stillfall back to `ar` when it's not + // available, since the correct LLVM ar is named `ar` in some + // environments, like when building in Nix); + #[cfg(target_os = "macos")] + let preferred_ar = llvm_ar.or(ar); + #[cfg(not(target_os = "macos"))] + let preferred_ar = ar.or(llvm_ar); + if let Ok(ar) = preferred_ar { + return Ok(ar); } + // try with postfixed version llvm-ar, e.g., llvm-ar-20 let re = Regex::new(r"llvm-ar-\d+").unwrap(); which::which_re(&re) diff --git a/src/toolchain_flags.rs b/src/toolchain_flags.rs new file mode 100644 index 0000000..ac9a970 --- /dev/null +++ b/src/toolchain_flags.rs @@ -0,0 +1,114 @@ +// this file is used both from the cargo-hyperlight library (via +// `mod`) and from the wrapper and config scripts that are built for +// $HOST in a package specified in wrapper/_Cargo.toml. So, it can +// only use imports available in both those environments. + +use std::borrow::Cow; +use std::ffi::{OsStr, OsString}; +use std::path::PathBuf; + +pub(crate) struct Args { + pub(crate) includes_dir: PathBuf, + pub(crate) c_libs_dir: PathBuf, + #[allow(unused)] // used in the wrapper, but not the host + pub(crate) wrapper_dir: PathBuf, + pub(crate) target: String, + pub(crate) with_guest_capi: bool, +} +impl Args { + fn clang_target(&self) -> &'static OsStr { + if self.target.starts_with("aarch64") { + "--target=aarch64-unknown-linux-none".as_ref() + } else { + "--target=x86_64-unknown-linux-none".as_ref() + } + } +} + +fn os(x: &(impl AsRef + ?Sized)) -> Cow<'_, OsStr> { + x.as_ref().into() +} + +pub struct Flags(pub(crate) Vec>); +impl Flags { + /// This will behave badly with spaces/special characters/etc, + /// which is why it is called `joined` and not + /// `joined_escaped`. That's OK for all the flags we use for now. + pub fn joined(&self) -> OsString { + let mut all = OsString::new(); + all.push(&self.0[0]); + for flag in &self.0[1..] { + all.push(os(" ")); + all.push(flag); + } + all + } +} + +pub(crate) fn cflags(args: &Args, bootstrap: bool) -> Flags { + const COMMON_FLAGS: &[&str] = &[ + "-U__linux__", + "-fPIC", + // We don't support stack protectors at the moment, but Arch Linux clang + // auto-enables them for -linux platforms, so explicitly disable them. + "-fno-stack-protector", + "-fstack-clash-protection", + "-mstack-probe-size=4096", + "-nostdlibinc", + // Define HYPERLIGHT as we use this to conditionally enable/disable code + // in the libc headers + "-DHYPERLIGHT=1", + "-D__HYPERLIGHT__=1", + ]; + + const X86_64_FLAGS: &[&str] = &["-mno-red-zone"]; + + const AARCH64_FLAGS: &[&str] = &["-mstrict-align", "-march=armv8.1-a+fp+simd"]; + + let mut flags: Vec> = Vec::new(); + flags.push(args.clang_target().into()); + COMMON_FLAGS + .iter() + .chain(if args.target.starts_with("x86_64") { + X86_64_FLAGS.iter() + } else if args.target.starts_with("aarch64") { + AARCH64_FLAGS.iter() + } else { + [].iter() + }) + .for_each(|x| flags.push(os(x))); + + if !bootstrap { + flags.push(os("-isystem")); + flags.push(Cow::Owned(args.includes_dir.clone().into())); + } + Flags(flags) +} + +pub(crate) fn ldflags(args: &Args) -> Flags { + const COMMON_FLAGS: &[&str] = &[ + "-e", + "entrypoint", + "-nostdlib", + "-pie", + "-Wl,--no-dynamic-linker", + ]; + + let mut flags = Vec::new(); + flags.push(args.clang_target().into()); + COMMON_FLAGS.iter().for_each(|x| flags.push(os(x))); + + flags.push(os("-L")); + flags.push(Cow::Owned(args.c_libs_dir.clone().into())); + + Flags(flags) +} + +pub(crate) fn libs(args: &Args) -> Flags { + let mut flags = Vec::new(); + if args.with_guest_capi { + flags.push(os("-l")); + flags.push(os("hyperlight_guest_capi")); + } + Flags(flags) +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..6de08cf --- /dev/null +++ b/src/util.rs @@ -0,0 +1,95 @@ +use std::collections::HashSet; +use std::fs; +use std::path::Path; + +use anyhow::{Context, Result}; + +/// Make the `dst_dir` into the union of a subset of the directory +/// trees rooted at `src_dirs`. The files considered to be part of the +/// src directory trees are those for which +/// - the pattern `glob` matches their (relative) path; and +/// - the `predicate` returns true +/// +/// Bug: extraneous empty directories may remain in the output +/// directory +/// +/// For example, with a filesystem layout of: +/// a/ +/// b.h +/// no.y +/// skip.h +/// b/ +/// c.h +/// c/ +/// d.h +/// e.x +/// Calling `union_glob_with_predicate` with `srcs` set to `["a", +/// "b"]` and `dst` to `"c"`, the glob `"*.h"`, and the predicate +/// `|path| path != "skip.h"` would result in `c` containing +/// c/ +/// b.h +/// c.h +pub(crate) fn union_glob_with_predicate( + src_dirs: impl Iterator>, + dst_dir: &Path, + glob: &str, + predicate: impl Fn(&Path) -> bool, +) -> Result<()> { + let mut copied = HashSet::new(); + + for src_dir in src_dirs { + let src_dir = src_dir.as_ref(); + let files = glob::glob(&format!("{}/{}", src_dir.display(), glob)) + .context("Failed to read source directory")?; + for file in files { + let src = file.context("Failed to read source file")?; + if !src.is_file() { + // contents will also show up + continue; + } + let suffix = src.strip_prefix(src_dir)?; + if !predicate(suffix) { + continue; + } + let dst = dst_dir.join(suffix); + + let parent_dir = dst.parent().ok_or(anyhow::anyhow!( + "Could not get parent directory of destination file" + ))?; + fs::create_dir_all(parent_dir).context("Failed to create subdirectory")?; + fs::copy(&src, &dst).context("Failed to copy file")?; + let canon = dst + .canonicalize() + .context("Failed to canonicalize copied file")?; + copied.insert(canon); + } + } + + // This doesn't do a good job of cleaning up empty directories, + // but that shouldn't cause any problems right now, since this is + // only used for header files/libraries/binaries. + let dst_files = glob::glob(&format!("{}/**/*", dst_dir.display())) + .context("Failed to read destination directory")?; + for dst_file in dst_files { + let dst = dst_file.context("Failed to read destination file")?; + let canon = dst + .canonicalize() + .context("Failed to canonicalize existing file")?; + if !copied.contains(&canon) && dst.is_file() { + fs::remove_file(canon).context("Failed to remove stale destination file")?; + } + } + Ok(()) +} + +/// See the documentation for [`union_glob_with_predicate`] above; +/// this convenience wrapper simply removes the need to explicitly +/// pass a predicate when all files matching the glob should be +/// included. +pub(crate) fn union_glob( + src_dir: impl Iterator>, + dst_dir: &Path, + glob: &str, +) -> Result<()> { + union_glob_with_predicate(src_dir, dst_dir, glob, |_| true) +} diff --git a/src/wrapper/_Cargo.toml b/src/wrapper/_Cargo.toml new file mode 100644 index 0000000..706dfc4 --- /dev/null +++ b/src/wrapper/_Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "hyperlight-sysroot-wrappers" +version = "0.0.0" +edition = "2024" + +[workspace] + +[dependencies] \ No newline at end of file diff --git a/src/wrapper/_clang_parser.rs b/src/wrapper/_clang_parser.rs new file mode 100644 index 0000000..ab799a6 --- /dev/null +++ b/src/wrapper/_clang_parser.rs @@ -0,0 +1,65 @@ +use std::ffi::OsStr; + +#[derive(Copy, Clone)] +pub(crate) struct ClangCmdInfo { + pub(crate) has_non_flag: bool, + pub(crate) has_non_link_flag: bool, +} +impl ClangCmdInfo { + pub(crate) fn will_link(self) -> bool { + !self.has_non_link_flag && self.has_non_flag + } +} + +pub(crate) fn parse_clang_cmd<'a>(cmd: impl Iterator) -> ClangCmdInfo { + // We can add cflags unconditionally, but to know whether or not + // to add ldflags, we need to know whether this compiler driver + // invocation is expected to link or not. + // + // We look through the arguments to produce two pieces of state: + // - `found_non_link_flag`: If true, we found some flag (like -c) + // which means that the compiler driver will not invoke the + // linker, so we should not include the linker + // arguments. Currently, we detect: + // + `-c`, `-S`, `-E`, `-M`, `-MM` + // + `-x -header` + // - `found_non_flag`: If true, there was at least one non-flag + // argument, so the driver will actually be compiling + // something. This is important to catch someone running + // e.g. `clang -v` and avoid inserting the linker arguments, + // which would trigger a great number of warnings. + let mut flags_valid: bool = true; + let mut found_non_link_flag: bool = false; + let mut found_non_flag: bool = false; + let mut iter = cmd.map(OsStr::to_str).map(Option::unwrap); + while let Some(arg) = iter.next() { + if !flags_valid || &arg[0..1] != "-" { + found_non_flag = true; + } + if arg == "--" { + flags_valid = false; + } + if flags_valid && &arg[0..1] == "-" { + let flag = &arg[1..]; + if flag == "c" || flag == "S" || flag == "E" || flag == "M" || flag == "MM" { + found_non_link_flag = true; + } + if &flag[0..1] == "x" { + let lang = if flag.len() > 1 { + Some(&flag[1..]) + } else { + iter.next() + }; + if let Some(lang) = lang + && lang.ends_with("-header") + { + found_non_link_flag = true; + } + } + } + } + ClangCmdInfo { + has_non_link_flag: found_non_link_flag, + has_non_flag: found_non_flag, + } +} diff --git a/src/wrapper/_main.rs b/src/wrapper/_main.rs new file mode 100644 index 0000000..f3d77fe --- /dev/null +++ b/src/wrapper/_main.rs @@ -0,0 +1,107 @@ +use std::borrow::Cow; +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fs; +use std::path::{self, Path, PathBuf}; +use std::process::exit; + +mod args; +mod toolchain_flags; +mod clang_parser; + +use toolchain_flags::Args; +use clang_parser::parse_clang_cmd; + +fn usage() -> ! { + eprintln!("This multi-call binary should be used as one of the following names: +- hyperlight-config +- clang +"); + exit(1); +} + +fn hyperlight_config(args: &Args, mut cmd: env::ArgsOs) { + while let Some(flag) = cmd.next() { + if flag == "--cflags" { + println!("{}", toolchain_flags::cflags(&args, false).joined().to_str().unwrap()); + } else if flag == "--ldflags" { + println!("{}", toolchain_flags::ldflags(&args).joined().to_str().unwrap()); + } else if flag == "--libs" { + println!("{}", toolchain_flags::libs(&args).joined().to_str().unwrap()); + } else { + eprintln!("Unknown flag `{}`", flag.display()); + exit(1); + } + } +} + +/// Since path entries may not exist (especially on Windows), +/// use the original if there are any errors. +fn normalize(x: &Path) -> Cow<'_, Path> { + if let Ok(y) = fs::canonicalize(x) { + Cow::Owned(y) + } else { + Cow::Borrowed(x) + } +} + +fn find_next(args: &Args, tool_name: &str) -> PathBuf { + let var_name = format!("HYPERLIGHT_TOOLCHAIN_{}", tool_name.to_lowercase().replace("-", "_")); + if let Some(path) = env::var_os(var_name) { + return path.into(); + } + let wrapper_dir = normalize(&args.wrapper_dir); + let path = env::var_os("PATH").expect("$PATH should exist"); + for path in env::split_paths(&path) { + let abs_path = normalize(&path); + if abs_path == wrapper_dir { + continue; + } + let base_path = path.join(tool_name); + if base_path.exists() { + return base_path; + } + let exe_path = base_path.with_extension("exe"); + if exe_path.exists() { + return exe_path; + } + } + panic!("Could not find base system implementation of {}", tool_name); +} + +fn clang(args: &Args, tool_name: &str, cmd: env::ArgsOs) { + let cmd: Vec<_> = cmd.collect(); + let info = parse_clang_cmd(cmd.iter().map(>::as_ref)); + let mut proc = std::process::Command::new(find_next(args, tool_name)); + proc.args(toolchain_flags::cflags(&args, false).0); + if info.will_link() { + proc.args(toolchain_flags::ldflags(&args).0); + } + proc.args(cmd); + // TODO: should we auto-add libs? It's probably more flexible to not + proc.status().expect("Failed to run system clang"); +} + +fn main() { + let mut cmd = env::args_os(); + let Some(bin) = cmd.next() else { usage(); }; + let mut bin = PathBuf::from(bin); + if bin.extension() == Some("exe".as_ref()) { + bin.set_extension(""); + } + let bin_name = bin.file_name().unwrap().to_str().unwrap(); + + let sysroot_base = bin.parent().unwrap().parent().unwrap(); + // use absolute instead of fs::canonicalize because Clang does not + // properly support \\?\ paths in include paths. + let sysroot_base = path::absolute(sysroot_base).unwrap(); + let args = args::args(&sysroot_base); + + if bin_name == "hyperlight-config" { + hyperlight_config(&args, cmd); + } else if bin_name == "clang" || bin_name == format!("{0}-clang", args.target) { + clang(&args, &bin_name, cmd); + } else { + usage(); + } +} diff --git a/tests/clang_parser.rs b/tests/clang_parser.rs new file mode 100644 index 0000000..73681b5 --- /dev/null +++ b/tests/clang_parser.rs @@ -0,0 +1,61 @@ +//! Tests for the logic used in the clang frontend wrapper + +#[path = "../src/wrapper/_clang_parser.rs"] +mod clang_parser; + +use std::ffi::OsStr; + +use clang_parser::parse_clang_cmd; + +macro_rules! parse_test { + ($name:ident, $args:tt, $non_flag:tt, $non_link_flag:tt, $will_link:tt) => { + #[test] + fn $name() { + let args: &[&str] = &$args; + let strs = args.iter().map(|x| OsStr::new(x)); + let info = parse_clang_cmd(strs); + assert_eq!(info.has_non_flag, $non_flag); + assert_eq!(info.has_non_link_flag, $non_link_flag); + assert_eq!(info.will_link(), $will_link); + } + }; +} + +parse_test!(empty, [], false, false, false); +parse_test!(no_args, ["-v"], false, false, false); +parse_test!(linking, ["foo.c"], true, false, true); +parse_test!(non_link_flag_c, ["-c", "foo.c"], true, true, false); +parse_test!(non_link_flag_s, ["-S", "foo.c"], true, true, false); +parse_test!(non_link_flag_e, ["-E", "foo.c"], true, true, false); +parse_test!(non_link_flag_m, ["-M", "foo.c"], true, true, false); +parse_test!(non_link_flag_mm, ["-MM", "foo.c"], true, true, false); +parse_test!( + non_link_flag_lang_space, + ["-x", "foo-header", "foo.c"], + true, + true, + false +); +parse_test!( + non_link_flag_lang_nospace, + ["-xfoo-header", "foo.c"], + true, + true, + false +); +parse_test!(end_of_flags_empty, ["--"], false, false, false); +parse_test!(end_of_flags_with_flag_like, ["--", "-v"], true, false, true); +parse_test!( + end_of_flags_with_non_link_flag_like, + ["--", "-c"], + true, + false, + true +); +parse_test!( + end_of_flags_with_non_link_flag, + ["-c", "--", "-v"], + true, + true, + false +);