name: CI on: # Run CI for PRs to `main` and to release branches. # # Note that PRs to `main` will run a subset of tests and PRs to the # `release-*` branches will run full CI. pull_request: branches: - main - 'release-*' # This is the CI that runs for PRs-to-merge. merge_group: push: branches: # Right now merge queues can't be used with wildcards in branch protections # so full CI runs both on PRs to release branches as well as merges to # release branches. Note that the merge to a release branch may produce a # tag at the end of CI if successful and the tag will trigger the artifact # uploads as well as publication to crates.io. - 'release-*' # Allow manually triggering this request via a button or another workflow. workflow_dispatch: defaults: run: shell: bash # Cancel any in-flight jobs for the same PR/branch so there's only one active # at a time concurrency: group: ${{ github.workflow }}-${{ github.ref }}2 cancel-in-progress: true jobs: # Check Code style quickly by running `rustfmt` over all code rustfmt: name: Rustfmt runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: rustup component add rustfmt - run: cargo fmt --all -- --check # Quick JS formatting/linting checks for the little bits of JS we have for the # `wasmtime explore` UI. check_js: name: Check JS runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm install working-directory: ./crates/explorer - run: npm run lint working-directory: ./crates/explorer - run: npm run fmt-check working-directory: ./crates/explorer # Check Code style quickly by running `clang-format` over all the C/C++ code # # Note that `wasmtime-platform.h` is excluded here as it's auto-generated. clangformat: name: Clang format runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: submodules: true - run: | git ls-files '*.h' '*.c' '*.cpp' '*.hh' '*.cc' | \ grep -v wasmtime-platform.h | \ grep -v wasm.h | \ xargs clang-format-18 --dry-run --Werror --verbose # Make sure our `clangformat.sh` helper script keeps running and stays # in-sync with the previous check. - run: crates/c-api/clangformat.sh - run: git diff --exit-code # Lint dependency graph for security advisories, duplicate versions, and # incompatible licences cargo_deny: name: Cargo deny needs: determine if: needs.determine.outputs.audit runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: | set -e curl --retry 5 --retry-all-errors -L -o cargo-deny.tar.gz https://github.com/EmbarkStudios/cargo-deny/releases/download/0.18.2/cargo-deny-0.18.2-x86_64-unknown-linux-musl.tar.gz tar xzf cargo-deny.tar.gz rm cargo-deny.tar.gz mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny echo `pwd` >> $GITHUB_PATH - run: cargo deny check bans licenses # Ensure dependencies are vetted. See https://mozilla.github.io/cargo-vet/ # # Note that this step, on PRs only, is allowed to fail. This is then followed # up with the `cargo_vet_failure_for_prs` step below. The intention is to # avoid causing this check to fail PRs while still enabling it to fail the # merge queue checks. That way PRs can enter the merge queue when this step is # failing if `main` has picked up `cargo vet` entries in the meantime for the # failures. cargo_vet: name: Cargo vet needs: determine if: github.repository == 'bytecodealliance/wasmtime' && needs.determine.outputs.audit runs-on: ubuntu-latest outputs: outcome: ${{ steps.vet.outcome }} steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - uses: ./.github/actions/install-cargo-vet - id: vet run: cargo vet --locked continue-on-error: ${{ github.event_name == 'pull_request' }} # Double-check that if versions are bumped that `cargo vet` still works. # This is intended to weed out mistakes such as #9115 from happening again. - run: rustc scripts/publish.rs && ./publish bump-patch && cargo vet name: Ensure `cargo vet` works if versions are bumped cargo_vet_failure_for_prs: name: Cargo vet failed on a Pull Request needs: - determine - cargo_vet if: | needs.determine.outputs.audit && github.event_name == 'pull_request' && needs.cargo_vet.outputs.outcome == 'failure' runs-on: ubuntu-latest steps: # NB: this message ideally would link back to the previous step, but I'm not # sure how to easily do that. - run: | echo 'failed to run "cargo vet", see previous `Cargo vet` step' echo 'exiting with a nonzero status now to alert PR authors' echo 'note, though, that this PR can still enter the merge queue' echo '' echo 'See https://docs.wasmtime.dev/contributing-coding-guidelines.html#cargo-vet-for-contributors' echo 'for more information about the vetting process for Wasmtime' exit 1 # This job is a dependency of many of the jobs below. This calculates what's # actually being run for this workflow. For example: # # * Pushes to branches, which is currently both pushes to merge queue branches # as well as release branches, perform full CI. # * PRs to release branches (not `main`) run full CI. # * PRs to `main` will only run a few smoke tests above plus some elements of # the test matrix. The test matrix here is determined dynamically by the # `./ci/build-test-matrix.js` script given the commits that happened and # the files modified. determine: name: Determine CI jobs to run runs-on: ubuntu-latest outputs: run-full: ${{ steps.calculate.outputs.run-full }} test-matrix: ${{ steps.calculate.outputs.test-matrix }} build-matrix: ${{ steps.calculate.outputs.build-matrix }} test-capi: ${{ steps.calculate.outputs.test-capi }} test-nightly: ${{ steps.calculate.outputs.test-nightly }} test-miri: ${{ steps.calculate.outputs.test-miri }} audit: ${{ steps.calculate.outputs.audit }} preview1-adapter: ${{ steps.calculate.outputs.preview1-adapter }} run-dwarf: ${{ steps.calculate.outputs.run-dwarf }} platform-checks: ${{ steps.calculate.outputs.platform-checks }} steps: - uses: actions/checkout@v4 - id: calculate env: GH_TOKEN: ${{ github.token }} run: | touch commits.log names.log # Note that CI doesn't run on pushes to `main`, only pushes to merge # queue branches and release branches, so this only runs full CI in # those locations. if [ "${{ github.event_name }}" != "pull_request" ]; then run_full=true else pr=${{ github.event.number }} gh pr view $pr --json commits | tee commits.log gh pr diff $pr --name-only | tee names.log || echo "failed to get files" if [ "${{ github.base_ref }}" != "main" ]; then run_full=true elif grep -q 'prtest:full' commits.log; then run_full=true elif grep -q 'prtest:debug' commits.log; then echo run-dwarf=true >> $GITHUB_OUTPUT elif grep -q 'prtest:platform-checks' commits.log; then echo platform-checks=true >> $GITHUB_OUTPUT elif grep -q 'prtest:miri' commits.log; then echo test-miri=true >> $GITHUB_OUTPUT elif grep -q 'prtest:capi' commits.log; then echo test-capi=true >> $GITHUB_OUTPUT fi if grep -q crates.c-api names.log; then echo test-capi=true >> $GITHUB_OUTPUT fi if grep -q fuzz names.log; then echo test-nightly=true >> $GITHUB_OUTPUT fi if grep -q sys.custom names.log; then echo test-nightly=true >> $GITHUB_OUTPUT fi if grep -q Cargo.lock names.log; then echo audit=true >> $GITHUB_OUTPUT fi if grep -q supply-chain names.log; then echo audit=true >> $GITHUB_OUTPUT fi if grep -q component-adapter names.log; then echo preview1-adapter=true >> $GITHUB_OUTPUT fi if grep -q debug names.log; then echo run-dwarf=true >> $GITHUB_OUTPUT fi if grep -q pulley names.log; then echo test-nightly=true >> $GITHUB_OUTPUT fi fi matrix="$(node ./ci/build-test-matrix.js ./commits.log ./names.log $run_full)" echo "test-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT echo "$matrix" matrix="$(node ./ci/build-build-matrix.js)" echo "build-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT if [ "$run_full" = "true" ]; then echo run-full=true >> $GITHUB_OUTPUT echo test-capi=true >> $GITHUB_OUTPUT echo test-nightly=true >> $GITHUB_OUTPUT echo test-miri=true >> $GITHUB_OUTPUT echo audit=true >> $GITHUB_OUTPUT echo preview1-adapter=true >> $GITHUB_OUTPUT echo run-dwarf=true >> $GITHUB_OUTPUT echo platform-checks=true >> $GITHUB_OUTPUT fi # Build all documentation of Wasmtime, including the C API documentation, # mdbook documentation, etc. This produces a `gh-pages` artifact which is what # gets uploaded to the `gh-pages` branch later on. doc: needs: determine if: needs.determine.outputs.run-full name: Doc build runs-on: ubuntu-latest env: MDBOOK_VERSION: 0.4.37 MDBOOK_LANGTABS_VERSION: 0.1.1 RUSTDOCFLAGS: -Dwarnings --cfg docsrs OPENVINO_SKIP_LINKING: 1 steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust with: toolchain: wasmtime-ci-pinned-nightly # Build C API documentation - run: | curl --retry 5 --retry-all-errors -o doxygen.tar.gz -L https://github.com/doxygen/doxygen/releases/download/Release_1_9_3/doxygen-1.9.3.linux.bin.tar.gz tar xzf doxygen.tar.gz rm doxygen.tar.gz - run: echo "`pwd`/doxygen-1.9.3/bin" >> $GITHUB_PATH - run: cmake -S crates/c-api -B target/c-api - run: cmake --build target/c-api --target doc # install mdbook, build the docs, and test the docs - uses: actions/cache@v4 with: path: ${{ runner.tool_cache }}/mdbook key: cargo-mdbook-${{ env.MDBOOK_VERSION }}-langtabs-${{ env.MDBOOK_LANGTABS_VERSION }} - run: | echo "${{ runner.tool_cache }}/mdbook/bin" >> $GITHUB_PATH cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.MDBOOK_VERSION }} mdbook --locked cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.MDBOOK_LANGTABS_VERSION }} mdbook-langtabs --locked - run: (cd docs && mdbook build) # Build Rust API documentation. # # Enable extra features in crates as well to ensure they're documented - run: | cargo doc --no-deps --workspace \ --exclude wasmtime-cli \ --exclude test-programs \ --exclude cranelift-codegen-meta \ --exclude wasmtime-wasi-nn \ --exclude wasmtime-fuzzing \ --exclude wasm-spec-interpreter \ --exclude calculator \ --all-features - run: cargo doc --package cranelift-codegen-meta --document-private-items # Assemble the documentation, and always upload it as an artifact for # inspection on PRs and such. - run: | mv docs/book gh-pages mv crates/c-api/html gh-pages/c-api mv target/doc gh-pages/api tar czf gh-pages.tar.gz gh-pages - uses: actions/upload-artifact@v4 with: name: gh-pages path: gh-pages.tar.gz # Checks of various feature combinations and whether things compile. The goal # here isn't to run tests, mostly just serve as a double-check that Rust code # compiles and is likely to work everywhere else. micro_checks: name: Check ${{matrix.name}} strategy: fail-fast: ${{ github.event_name != 'pull_request' }} matrix: include: - name: wasmtime checks: | -p wasmtime --no-default-features -p wasmtime --no-default-features --features wat -p wasmtime --no-default-features --features profiling -p wasmtime --no-default-features --features cache -p wasmtime --no-default-features --features async -p wasmtime --no-default-features --features std -p wasmtime --no-default-features --features pooling-allocator -p wasmtime --no-default-features --features cranelift -p wasmtime --no-default-features --features component-model -p wasmtime --no-default-features --features component-model-async -p wasmtime --no-default-features --features runtime,component-model -p wasmtime --no-default-features --features cranelift,wat,async,std,cache -p wasmtime --no-default-features --features winch -p wasmtime --no-default-features --features wmemcheck -p wasmtime --no-default-features --features wmemcheck,cranelift,runtime -p wasmtime --no-default-features --features demangle -p wasmtime --no-default-features --features addr2line -p wasmtime --no-default-features --features gc -p wasmtime --no-default-features --features runtime,gc -p wasmtime --no-default-features --features cranelift,gc -p wasmtime --no-default-features --features gc-drc -p wasmtime --no-default-features --features runtime,gc-drc -p wasmtime --no-default-features --features cranelift,gc-drc -p wasmtime --no-default-features --features gc-null -p wasmtime --no-default-features --features runtime,gc-null -p wasmtime --no-default-features --features cranelift,gc-null -p wasmtime --no-default-features --features runtime -p wasmtime --no-default-features --features threads -p wasmtime --no-default-features --features runtime,threads -p wasmtime --no-default-features --features cranelift,threads -p wasmtime --no-default-features --features stack-switching -p wasmtime --no-default-features --features cranelift,stack-switching -p wasmtime --no-default-features --features runtime,stack-switching -p wasmtime --no-default-features --features debug -p wasmtime --no-default-features --features debug,gc -p wasmtime --no-default-features --features runtime,cache -p wasmtime --features incremental-cache -p wasmtime --features profile-pulley -p wasmtime --all-features - name: wasmtime-fiber checks: | -p wasmtime-internal-fiber --no-default-features -p wasmtime-internal-fiber --no-default-features --features std -p wasmtime-internal-fiber --all-features - name: wasmtime-cli checks: | -p wasmtime-cli --no-default-features -p wasmtime-cli --no-default-features --features pooling-allocator -p wasmtime-cli --no-default-features --features run -p wasmtime-cli --no-default-features --features run,component-model -p wasmtime-cli --no-default-features --features run,pooling-allocator -p wasmtime-cli --no-default-features --features compile -p wasmtime-cli --no-default-features --features compile,cranelift -p wasmtime-cli --no-default-features --features compile,cranelift,component-model -p wasmtime-cli --no-default-features --features objdump -p wasmtime-cli --no-default-features --features wizer -p wasmtime-cli --all-features -p wasmtime-cli --features component-model - name: cranelift-codegen checks: | -p cranelift-codegen --benches -p cranelift-codegen --no-default-features --features std,unwind,pulley - name: cranelift-entity checks: | -p cranelift-entity --no-default-features -p cranelift-entity --no-default-features --features enable-serde - name: wasmtime-bench-api checks: | -p wasmtime-bench-api - name: wasmtime-c-api checks: | -p wasmtime-c-api --no-default-features -p wasmtime-c-api --no-default-features --features wat -p wasmtime-c-api --no-default-features --features wasi - name: wasmtime-wasi-http checks: | -p wasmtime-wasi-http --no-default-features -p wasmtime-wasi-http --no-default-features --features p3 -p wasmtime-wasi-http --no-default-features --features p3 --all-targets - name: wasmtime-wasi checks: | -p wasmtime-wasi --no-default-features -p wasmtime-wasi --no-default-features --features p0 -p wasmtime-wasi --no-default-features --features p1 -p wasmtime-wasi --no-default-features --features p2 -p wasmtime-wasi --no-default-features --features p3 - name: wasmtime-wizer checks: | -p wasmtime-wizer --no-default-features -p wasmtime-wizer --no-default-features --features wasmtime -p wasmtime-wizer --no-default-features --features wasmprinter -p wasmtime-wizer --no-default-features --features component-model -p wasmtime-wizer --no-default-features --features rayon -p wasmtime-wizer --no-default-features --all-features runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust # Run the check. - run: | checks=$(cat < cargo check -p wasmtime --no-default-features --features runtime,component-model && cargo check -p wasmtime --no-default-features --features runtime,gc,component-model,async,debug-builtins && cargo check -p cranelift-control --no-default-features && cargo check -p cranelift-assembler-x64 --lib && cargo check -p pulley-interpreter --features encode,decode,disas,interp && cargo check -p wasmtime-wasi-io --no-default-features # Use `cross` for illumos to have a C compiler/linker available. - target: x86_64-unknown-illumos os: ubuntu-latest cross: true test: cross build - target: wasm32-wasip1 os: ubuntu-latest test: cargo build --no-default-features --features compile,cranelift,all-arch - target: aarch64-apple-ios os: macos-latest test: cargo build env: IPHONEOS_DEPLOYMENT_TARGET: 13.0 # Test that when Cranelift has no support for an architecture, even a # 64-bit one, that Wasmtime still compiles. Note that this is also # intended to test various fallbacks in the codebase where we have no # support at all for a particular architecture. In theory if someone # adds powerpc64 support to Wasmtime this should get switched to some # other architecture. - target: powerpc64le-unknown-linux-gnu os: ubuntu-latest test: cargo build apt_packages: gcc-powerpc64le-linux-gnu env: CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER: powerpc64le-linux-gnu-gcc # A no_std target without 64-bit atomics - target: riscv32imac-unknown-none-elf os: ubuntu-latest test: cargo check -p wasmtime --no-default-features --features runtime,gc,component-model,async env: ${{ matrix.env || fromJSON('{}') }} steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: rustup target add ${{ matrix.target }} - name: Install cross run: | curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash cargo binstall --no-confirm cross if: ${{ matrix.cross }} - name: Install apt packages if: ${{ matrix.apt_packages }} run: sudo apt-get update && sudo apt-get install -y ${{ matrix.apt_packages }} - run: ${{ matrix.test }} env: CARGO_BUILD_TARGET: ${{ matrix.target }} # Run tests that require a nightly compiler, such as building fuzz targets. test_nightly: needs: determine if: needs.determine.outputs.test-nightly name: Nightly tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust with: # This is pinned to match the version of Rust used on OSS-Fuzz to build # Wasmtime. Do not change this `toolchain` version. toolchain: wasmtime-ci-oss-fuzz-pin # Check that `pulley-interpreter` works with tail calls enabled. - run: cargo test -p pulley-interpreter --all-features env: RUSTFLAGS: "--cfg pulley_tail_calls" - run: cargo check -p pulley-interpreter --all-features env: RUSTFLAGS: "--cfg pulley_disable_interp_simd" - run: cargo test -p pulley-interpreter --all-features --release env: RUSTFLAGS: "--cfg pulley_assume_llvm_makes_tail_calls" # Run OOM tests with `Arc::try_new` usage enabled. - run: cargo test -p wasmtime-fuzzing --test oom env: RUSTFLAGS: "--cfg arc_try_new" # Ensure that fuzzers still build. # # Install the OCaml packages necessary for fuzz targets that use the # `wasm-spec-interpreter`. - run: cargo install cargo-fuzz --vers "^0.11" --locked - run: sudo apt-get update && sudo apt install -y ocaml-nox ocamlbuild ocaml-findlib libzarith-ocaml-dev - run: cargo fetch working-directory: ./fuzz - run: cargo fuzz check --dev - run: cargo fuzz check --dev --fuzz-dir ./cranelift/isle/fuzz - run: cargo fuzz check --dev --fuzz-dir ./crates/environ/fuzz --features component-model - run: cargo fuzz check --dev --fuzz-dir ./cranelift/assembler-x64/fuzz - run: cargo fuzz check --dev --fuzz-dir ./crates/wizer/fuzz # Perform all tests of the c-api test_capi: needs: determine name: Test C-API ${{ matrix.name }} runs-on: ${{ matrix.os }} if: needs.determine.outputs.test-capi strategy: fail-fast: ${{ github.event_name != 'pull_request' }} matrix: include: # This configuration will build C/C++ tests, examples, and Rust tests. # Everything is linked against the C shared library to speed up # linking, and this is intended to be the "main set of tests". # # Run this on windows/mac/linux - os: ubuntu-24.04 # Only run the "plugins" example on Linux flags: -DBUILD_SHARED_LIBS=ON -DBUILD_TESTS=ON -DBUILD_RUST_EXAMPLES=ON -DBUILD_RUST_PLUGINS_EXAMPLE=ON name: Linux - os: macos-15 flags: -DBUILD_SHARED_LIBS=ON -DBUILD_TESTS=ON -DBUILD_RUST_EXAMPLES=ON name: macOS - os: windows-2025 # Note that dynamic linking is disabled here because I don't want to # have to deal with figuring out how to get `wasmtime.dll` onto # `PATH` for various tests. flags: -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTS=ON -DBUILD_RUST_EXAMPLES=ON name: Windows # This tests using static linking for examples but skips building the # Rust examples as well as C/C++ tests. Intended to be a faster build # which mostly just tests static linking. - os: ubuntu-24.04 flags: -DBUILD_SHARED_LIBS=OFF -DBUILD_RUST_EXAMPLES=OFF name: Linux (static linking) # Run tests with ASAN for leak checking primarily. - os: ubuntu-24.04 flags: -DCMAKE_C_FLAGS=-fsanitize=address -DCMAKE_CXX_FLAGS=-fsanitize=address -DBUILD_SHARED_LIBS=ON -DBUILD_TESTS=ON name: Linux (ASAN) steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: rustup target add wasm32-wasip2 - uses: ./.github/actions/install-plugins-prerequisites if: runner.os == 'Linux' - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # An ode to MinGW: man you're a pain to work around sometimes - run: rm /usr/bin/link if: runner.os == 'Windows' - run: cmake -G Ninja -Sexamples -DCMAKE_BUILD_TYPE=Debug -Bexamples/build ${{ matrix.flags }} - run: ninja -C examples/build - run: ninja -C examples/build test env: CTEST_OUTPUT_ON_FAILURE: 1 CTEST_PARALLEL_LEVEL: 4 # Perform all tests (debug mode) for `wasmtime`. # # Note that the full matrix for what may run here is defined within # `./ci/build-test-matrix.js` and the execution of the `determine` step will # calculate whether the tests are actually run as part of PRs and such. test: needs: determine name: ${{ matrix.name }} runs-on: ${{ matrix.os }} env: QEMU_BUILD_VERSION: 10.0.3 SDE_BUILD_VERSION: 9.58.0-2025-06-16 strategy: fail-fast: ${{ github.event_name != 'pull_request' }} matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }} steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust with: toolchain: ${{ matrix.rust }} # Install targets in order to build various tests throughout the repo - run: rustup target add wasm32-wasip1 wasm32-unknown-unknown ${{ matrix.target }} - run: echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV if: matrix.target != '' # Fix an ICE for now in gcc when compiling zstd with debuginfo (??) - run: echo CFLAGS=-g0 >> $GITHUB_ENV if: matrix.target == 'x86_64-pc-windows-gnu' # Update binutils if MinGW due to https://github.com/rust-lang/rust/issues/112368 - run: C:/msys64/usr/bin/pacman.exe -S --needed mingw-w64-x86_64-gcc --noconfirm if: matrix.target == 'x86_64-pc-windows-gnu' - shell: pwsh run: echo "C:\msys64\mingw64\bin" >> $Env:GITHUB_PATH if: matrix.target == 'x86_64-pc-windows-gnu' - run: cargo fetch --locked - name: Install cross-compilation tools run: | set -ex sudo apt-get update sudo apt-get install -y ${{ matrix.gcc_package }} # Configure Cargo for cross compilation and tell it how it can run # cross executables upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g') echo CARGO_TARGET_${upcase}_LINKER=${{ matrix.gcc }} >> $GITHUB_ENV if: matrix.gcc != '' - uses: actions/cache@v4 with: path: ${{ runner.tool_cache }}/qemu key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patchcpuinfo if: matrix.qemu != '' - uses: actions/cache@v4 with: path: ${{ runner.tool_cache }}/sde key: sde-${{ env.SDE_BUILD_VERSION }} if: matrix.sde != '' - name: Install qemu run: | set -ex upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g') echo CARGO_TARGET_${upcase}_RUNNER=${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} >> $GITHUB_ENV # QEMU emulation is not always the speediest, so total testing time # goes down if we build the libs in release mode when running tests. echo CARGO_PROFILE_DEV_OPT_LEVEL=2 >> $GITHUB_ENV # See comments in the source for why we enable this during QEMU # emulation. echo WASMTIME_TEST_NO_HOG_MEMORY=1 >> $GITHUB_ENV # See if qemu is already in the cache if [ -f ${{ runner.tool_cache }}/qemu/built ]; then exit 0 fi # Install build dependencies of QEMU itself. sudo apt-get install -y libglib2.0-dev ninja-build # Download and build qemu from source since the most recent release is # way faster at arm emulation than the current version github actions' # ubuntu image uses. Disable as much as we can to get it to build # quickly. curl --retry 5 --retry-all-errors -o qemu.tar.xz https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz tar xJf qemu.tar.xz rm qemu.tar.xz cd qemu-$QEMU_BUILD_VERSION ./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache}}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs ninja -C build install touch ${{ runner.tool_cache }}/qemu/built if: matrix.qemu != '' - name: Install Intel SDE run: | set -ex # Set up SDE as runner for x86_64 targets echo "CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER=${{ runner.tool_cache }}/sde/sde64 -future --" >> $GITHUB_ENV # SDE emulation is very slow, so use release mode for better performance echo CARGO_PROFILE_DEV_OPT_LEVEL=2 >> $GITHUB_ENV # Enable environment variable to indicate SDE is being used echo WASMTIME_TEST_SDE=1 >> $GITHUB_ENV # Generic variable for skipping tests that are problematic under SDE (performance, compatibility, etc.) echo WASMTIME_TEST_NO_SDE=1 >> $GITHUB_ENV # Similar to QEMU, reduce memory usage during SDE emulation echo WASMTIME_TEST_NO_HOG_MEMORY=1 >> $GITHUB_ENV # See if SDE is already in the cache if [ -f ${{ runner.tool_cache }}/sde/sde64 ]; then exit 0 fi curl --retry 5 --retry-all-errors -o sde.tar.xz \ https://downloadmirror.intel.com/859732/sde-external-${{ env.SDE_BUILD_VERSION }}-lin.tar.xz mkdir -p ${{ runner.tool_cache }}/sde tar xJf sde.tar.xz --strip-components=1 -C ${{ runner.tool_cache }}/sde rm sde.tar.xz chmod +x ${{ runner.tool_cache }}/sde/sde64 if: matrix.sde != '' - name: Configure ASAN run: | echo CARGO_PROFILE_DEV_OPT_LEVEL=2 >> $GITHUB_ENV echo CARGO_PROFILE_TEST_OPT_LEVEL=2 >> $GITHUB_ENV echo RUSTFLAGS=-Zsanitizer=address >> $GITHUB_ENV echo RUSTDOCFLAGS="-Zsanitizer=address -Copt-level=2 -Ccodegen-units=16" >> $GITHUB_ENV if: ${{ contains(matrix.name, 'ASAN') }} # Record some CPU details; this is helpful information if tests fail due # to CPU-specific features. - name: CPU information run: lscpu if: runner.os == 'Linux' - name: CPU information run: sysctl hw if: runner.os == 'macOS' - name: CPU information run: Get-WmiObject Win32_Processor shell: pwsh if: runner.os == 'Windows' # Since MPK (PKU) is not present on some GitHub runners, we check if it is # available before force-enabling it. This occasional testing is better than # none at all; ideally we would test in a system-mode QEMU VM. - name: Force-run with MPK enabled, if available if: ${{ contains(matrix.name, 'MPK') }} run: | if cargo run --example mpk-available; then echo "::notice::This CI run will force-enable MPK; this ensures tests conditioned with the \`WASMTIME_TEST_FORCE_MPK\` environment variable will run with MPK-protected memory pool stripes." echo WASMTIME_TEST_FORCE_MPK=1 >> $GITHUB_ENV else echo "::warning::This CI run will not test MPK; it has been detected as not available on this machine (\`cargo run --example mpk-available\`)." fi # Install VTune, see `cli_tests::profile_with_vtune`. - name: Install VTune if: matrix.filter == 'linux-x64' && contains(matrix.bucket, 'wasmtime-cli') uses: abrown/install-vtune-action@v3 # Build and test all features. # # Note that this uses a different shell, notably not `bash` on Windows. In # the past `bash` would add more items to `PATH` on Windows which would # interfere and cause the `gcc.exe` executable to fail and exit with 1 and # no output. It's believed that `bash` adds things like `/usr/bin` to PATH # which is the wrong DLL or something like that. - run: python3 ./ci/run-tests.py --locked ${{ matrix.bucket }} if: runner.os == 'Windows' shell: pwsh - run: python3 ./ci/run-tests.py --locked ${{ matrix.bucket }} if: runner.os != 'Windows' # Test `wasmtime-wasi-nn` in its own job, as not all of its backends are # compatible with all targets, and each must be tested separately anyways. test_wasi_nn: strategy: matrix: feature: ["openvino", "onnx-download"] os: ["ubuntu-24.04", "windows-2025"] include: - os: windows-2025 feature: winml name: Test wasi-nn (${{ matrix.feature }}, ${{ matrix.os }}) runs-on: ${{ matrix.os }} needs: determine if: needs.determine.outputs.run-full steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust # Install OpenVINO - uses: abrown/install-openvino-action@v10 if: runner.arch == 'X64' # Install WinML for testing wasi-nn WinML backend. WinML is only available # on Windows clients and Windows Server with desktop experience enabled. # GitHub Actions Window Server image doesn't have desktop experience # enabled, so we download the standalone library from ONNX Runtime project. - uses: nuget/setup-nuget@v2 if: (runner.os == 'Windows') && (matrix.feature == 'winml') - run: nuget install Microsoft.AI.MachineLearning if: (runner.os == 'Windows') && (matrix.feature == 'winml') # Install Rust targets. - run: rustup target add wasm32-wasip1 # Run the tests! - run: cargo test -p wasmtime-wasi-nn --features ${{ matrix.feature }} # Test `wasmtime-wasi-tls-nativetls` & `wasmtime-wasi-tls-openssl` in their # own job. This is because they depends on OpenSSL, which is not easily # available on all platforms. # # The Windows base image has OpenSSL installed by default, but not in a way # that is automatically discoverable by `openssl-sys`. We need to configure # the OPENSSL_DIR & OPENSSL_LIB_DIR paths manually. # Additionally, the GH actions Windows image does not ship with a CA cert # bundle, so we use the one from cUrl. test_wasi_tls: name: Test wasi-tls using native-tls & openssl providers needs: determine if: needs.determine.outputs.run-full runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - name: Configure OpenSSL (Windows) if: runner.os == 'Windows' shell: pwsh run: | mkdir "C:\Program Files\OpenSSL\certs" $sslCertFile = "C:\Program Files\OpenSSL\certs\cacert.pem" $opensslDir = "C:\Program Files\OpenSSL" $opensslLibDir = "C:\Program Files\OpenSSL\lib\VC\x64\MD" curl.exe -o $sslCertFile https://curl.se/ca/cacert.pem "SSL_CERT_FILE=$sslCertFile" | Out-File -FilePath $env:GITHUB_ENV -Append "OPENSSL_DIR=$opensslDir" | Out-File -FilePath $env:GITHUB_ENV -Append "OPENSSL_LIB_DIR=$opensslLibDir" | Out-File -FilePath $env:GITHUB_ENV -Append - run: cargo test -p wasmtime-wasi-tls-openssl - run: cargo test -p wasmtime-wasi-tls-nativetls # Test the `wasmtime-fuzzing` crate. Split out from the main tests because # `--all-features` brings in OCaml, which is a pain to get setup for all # targets. test_fuzzing: needs: determine if: needs.determine.outputs.run-full name: Test wasmtime-fuzzing runs-on: 'ubuntu-latest' steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust # Run the tests - run: | cargo test -p wasmtime-fuzzing -p wasm-spec-interpreter # Test debug (DWARF) related functionality. test_debug_dwarf: needs: determine if: needs.determine.outputs.run-dwarf name: Test DWARF debugging runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: | rustup target add wasm32-wasip1 wasm32-unknown-unknown cd /tmp curl --retry 5 --retry-all-errors -OL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-30/wasi-sdk-30.0-x86_64-linux.tar.gz tar -xzf wasi-sdk-30.0-x86_64-linux.tar.gz mv wasi-sdk-30.0-x86_64-linux wasi-sdk - run: | sudo apt-get update && sudo apt-get install -y gdb lldb-18 llvm # workaround for https://bugs.launchpad.net/ubuntu/+source/llvm-defaults/+bug/1972855 sudo mkdir -p /usr/lib/local/lib/python3.10/dist-packages/lldb sudo ln -s /usr/lib/llvm-15/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/ # Only testing release since it is more likely to expose issues with our low-level symbol handling. cargo test --release --test all -- --ignored --test-threads 1 native_debug:: env: LLDB: lldb-18 WASI_SDK_PATH: /tmp/wasi-sdk build-preview1-component-adapter: name: Build wasi-preview1-component-adapter needs: determine if: needs.determine.outputs.preview1-adapter runs-on: ubuntu-latest permissions: deployments: write contents: write steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: rustup target add wasm32-wasip1 wasm32-unknown-unknown - name: Install wasm-tools run: | curl --retry 5 --retry-all-errors -o wasm-tools.tar.gz -L https://github.com/bytecodealliance/wasm-tools/releases/download/wasm-tools-1.0.27/wasm-tools-1.0.27-x86_64-linux.tar.gz tar xfz wasm-tools.tar.gz rm wasm-tools.tar.gz echo `pwd`/wasm-tools-1.0.27-x86_64-linux >> $GITHUB_PATH - run: ./ci/build-wasi-preview1-component-adapter.sh env: VERSION: ${{ github.sha }} - uses: actions/upload-artifact@v4 with: name: bins-wasi-preview1-component-adapter path: target/wasm32-unknown-unknown/release/wasi_snapshot_preview1.*.wasm build-preview1-component-adapter-provider: name: Build wasi-preview1-component-adapter-provider needs: build-preview1-component-adapter runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - uses: ./.github/actions/build-adapter-provider with: run-id: ${{ github.run_id }} # Verify the "min platform" example still works. test-min-platform-example: name: Test the min-platform example needs: determine if: needs.determine.outputs.run-full runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: cargo install cbindgen@0.29.0 --locked - run: rustup target add x86_64-unknown-none - run: rustup target add wasm32-wasip2 - run: ./build.sh x86_64-unknown-none working-directory: ./examples/min-platform # Afterwards make sure the generated header file is up to date by ensuring # that the regeneration process didn't change anything in-tree. - run: git diff --exit-code # Test some other feature combinations - run: ./build.sh x86_64-unknown-none working-directory: ./examples/min-platform env: WASMTIME_SIGNALS_BASED_TRAPS: 1 - run: ./build.sh x86_64-unknown-none working-directory: ./examples/min-platform env: WASMTIME_SIGNALS_BASED_TRAPS: 1 MIN_PLATFORM_TEST_DISABLE_WASI: 1 # Add the `wasmtime-platform.h` file as a release artifact - uses: actions/upload-artifact@v4 with: name: wasmtime-platform-header path: examples/min-platform/embedding/wasmtime-platform.h bench: needs: determine if: needs.determine.outputs.run-full name: Run benchmarks runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: rustup target add wasm32-wasip1 - run: cargo test --benches --release # Verify that cranelift's code generation is deterministic meta_deterministic_check: needs: determine if: needs.determine.outputs.run-full name: Meta deterministic check runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: cd cranelift/codegen && cargo build --features all-arch - run: ci/ensure_deterministic_build.sh verify-publish: needs: determine if: github.repository == 'bytecodealliance/wasmtime' && needs.determine.outputs.run-full runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust - run: | cd ${{ runner.tool_cache }} curl --retry 5 --retry-all-errors -L -o sccache.tar.gz \ https://github.com/mozilla/sccache/releases/download/0.2.13/sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz tar xzf sccache.tar.gz rm sccache.tar.gz echo "`pwd`/sccache-0.2.13-x86_64-unknown-linux-musl" >> $GITHUB_PATH echo RUSTC_WRAPPER=sccache >> $GITHUB_ENV - run: rustc scripts/publish.rs # Make sure the tree is publish-able as-is - run: ./publish verify # Make sure we can bump version numbers for the next release - run: ./publish bump # Run a subset of tests under MIRI on CI to help check the `unsafe` code in # Wasmtime to make sure it's at least not obviously incorrect for basic usage. # Note that this doesn't run the full test suite since MIRI can't actually run # WebAssembly itself at this time (aka it doesn't support a JIT). There are a # number of annotations throughout the code which gates some tests on MIRI not # being run. # # Note that `cargo nextest` is used here additionally to get parallel test # execution by default to help cut down on the time in CI. miri: strategy: matrix: include: - crate: "wasmtime" - crate: "wasmtime-cli" - crate: "wasmtime-environ --all-features" - crate: "pulley-interpreter --all-features" - crate: "wasmtime-internal-core" - crate: "wasmtime-internal-core --all-features" - script: ./ci/miri-provenance-test.sh - script: ./ci/miri-wast.sh ./tests/spec_testsuite/table.wast needs: determine if: needs.determine.outputs.test-miri && github.repository == 'bytecodealliance/wasmtime' name: Miri runs-on: ubuntu-latest env: CARGO_NEXTEST_VERSION: 0.9.88 MIRIFLAGS: -Zmiri-permissive-provenance steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust with: toolchain: wasmtime-ci-pinned-nightly - run: rustup component add rust-src miri - uses: actions/cache@v4 with: path: ${{ runner.tool_cache }}/cargo-nextest key: cargo-nextest-bin-${{ env.CARGO_NEXTEST_VERSION }} - run: echo "${{ runner.tool_cache }}/cargo-nextest/bin" >> $GITHUB_PATH - run: cargo install --root ${{ runner.tool_cache }}/cargo-nextest --version ${{ env.CARGO_NEXTEST_VERSION }} cargo-nextest --locked - run: | cargo miri nextest run -j4 --no-fail-fast -p ${{ matrix.crate }} if: ${{ matrix.crate }} - run: ${{ matrix.script }} if: ${{ matrix.script }} # Perform release builds of `wasmtime` and `libwasmtime.so`. Builds a variety # of platforms and architectures and then uploads the release artifacts to # this workflow run's list of artifacts. # # Note that the full matrix is computed by `ci/build-build-matrix.js`. build: needs: determine if: needs.determine.outputs.run-full name: Release build for ${{ matrix.build }} runs-on: ${{ matrix.os }} strategy: fail-fast: ${{ github.event_name != 'pull_request' }} matrix: ${{ fromJson(needs.determine.outputs.build-matrix) }} env: ${{ matrix.env || fromJSON('{}') }} steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-ninja - uses: ./.github/actions/install-rust with: toolchain: ${{ matrix.rust }} - run: | rustup component add rust-src rustup target add ${{ matrix.target }} # On one builder produce the source tarball since there's no need to produce # it everywhere - run: ./ci/build-src-tarball.sh if: matrix.build == 'x86_64-linux' - uses: ./.github/actions/android-ndk if: contains(matrix.target, 'android') with: target: ${{ matrix.target }} - run: ./ci/build-release-artifacts.sh "${{ matrix.build }}" "${{ matrix.target }}" # Assemble release artifacts appropriate for this platform, then upload them # unconditionally to this workflow's files so we have a copy of them. - run: ./ci/build-tarballs.sh "${{ matrix.build }}" "${{ matrix.target }}" - uses: actions/upload-artifact@v4 with: name: bins-${{ matrix.build }} path: dist # This is a "join node" which depends on all prior workflows. The merge queue, # for example, gates on this to ensure that everything has executed # successfully. # # Note that this is required currently for odd reasons with github. Notably # the set of checks to enter the merge queue and leave the merge queue must # be the same which means that the "build" step for example shows as skipped # for PRs but expands to many different steps for merge-queue-based PRs. That # means that for that step there's no single name to gate on, so it's required # to have a "join" node here which joins everything. # # Note that this currently always runs to always report a status, even on # cancellation and even if dependency steps fail. Each dependency tries to # cancel the whole run if it fails, so if a test matrix entry fails, for # example, it cancels the build matrix entries too. This step then tries to # fail on cancellation to ensure that the dependency failures are propagated # correctly. ci-status: name: Record the result of testing and building steps runs-on: ubuntu-latest needs: - test - test_capi - test_debug_dwarf - test_fuzzing - test_wasi_nn - test_nightly - build - rustfmt - clangformat - cargo_deny - cargo_vet - doc - micro_checks - special_tests - test_wasi_tls - clippy - monolith_checks - platform_checks - bench - meta_deterministic_check - verify-publish - determine - miri - build-preview1-component-adapter - build-preview1-component-adapter-provider - test-min-platform-example - check_js if: always() steps: # Calculate the exit status of the whole CI workflow. # If all dependent jobs were successful, this exits with 0 (and the # outcome job continues successfully). If a some dependent job has # failed, this exits with 1. - name: calculate the correct exit status run: jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}' # The purpose of this jobs is to watch for changes on the `release-*` # branches of this repository and look for the term # "automatically-tag-and-release-this-commit" within merged PRs/commits. Once # that term is found the current version of `Cargo.toml`, the `wasmtime-cli` # Cargo.toml, is created as a tag and the tag is pushed to the repo. # Currently the tag is created through the GitHub API with an access token to # ensure that CI is further triggered for the tag itself which performs the # full release process. # # Note that this depends on the `ci-status` step above which is the "join" # point of this workflow for when everything succeeds. the purpose of that is # so that the tag is only created after the aftifacts have been uploaded for # this workflow as the `publish-artifacts.yml` workflow will download these # artifacts and then publish them to the tag. push-tag: runs-on: ubuntu-latest needs: ci-status if: | always() && needs.ci-status.result == 'success' && github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release-') && github.repository == 'bytecodealliance/wasmtime' steps: - uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 - name: Test if tag is needed run: | git log ${{ github.event.before }}...${{ github.event.after }} | tee main.log version=$(grep '^version =' Cargo.toml | head -n 1 | sed 's/.*"\(.*\)"/\1/') echo "version: $version" echo "version=$version" >> $GITHUB_OUTPUT echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT if grep -q "automatically-tag-and-release-this-commit" main.log; then echo push-tag echo "push_tag=yes" >> $GITHUB_OUTPUT else echo no-push-tag echo "push_tag=no" >> $GITHUB_OUTPUT fi id: tag - name: Push the tag run: | git_refs_url=$(jq .repository.git_refs_url $GITHUB_EVENT_PATH | tr -d '"' | sed 's/{\/sha}//g') curl -iX POST $git_refs_url \ -H "Authorization: token ${{ secrets.PERSONAL_ACCESS_TOKEN }}" \ -d @- << EOF { "ref": "refs/tags/v${{ steps.tag.outputs.version }}", "sha": "${{ steps.tag.outputs.sha }}" } EOF if: steps.tag.outputs.push_tag == 'yes' # File an issue on the repo if this run failed and was triggered via # `workflow_dispatch`, which mostly means that # `.github/workflows/trigger-release-branch-ci.yml` will file issues on # failure so we get to see a notification when a build fails for a historical # release branch. file-issue-on-error: name: File an issue if this build failed and was cron-triggered runs-on: ubuntu-latest needs: ci-status if: | always() && needs.ci-status.result != 'success' && github.event_name == 'workflow_dispatch' permissions: issues: write steps: - uses: actions/github-script@v7 with: script: | github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: `Failed CI build for ${context.ref}`, body: `See https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, })