1name: CI 2on: 3 # Run CI for PRs to `main` and to release branches. 4 # 5 # Note that PRs to `main` will run a subset of tests and PRs to the 6 # `release-*` branches will run full CI. 7 pull_request: 8 branches: 9 - main 10 - 'release-*' 11 12 # Run full CI on the `main` branch once a day to prime the GitHub Actions 13 # caches used by PRs and the merge queue. 14 schedule: 15 - cron: '13 4 * * *' 16 17 # This is the CI that runs for PRs-to-merge. 18 merge_group: 19 20 push: 21 branches: 22 # Right now merge queues can't be used with wildcards in branch protections 23 # so full CI runs both on PRs to release branches as well as merges to 24 # release branches. Note that the merge to a release branch may produce a 25 # tag at the end of CI if successful and the tag will trigger the artifact 26 # uploads as well as publication to crates.io. 27 - 'release-*' 28 29defaults: 30 run: 31 shell: bash 32 33# Cancel any in-flight jobs for the same PR/branch so there's only one active 34# at a time 35concurrency: 36 group: ${{ github.workflow }}-${{ github.ref }} 37 cancel-in-progress: true 38 39jobs: 40 # Check Code style quickly by running `rustfmt` over all code 41 rustfmt: 42 name: Rustfmt 43 runs-on: ubuntu-latest 44 steps: 45 - uses: actions/checkout@v4 46 with: 47 submodules: true 48 - uses: ./.github/actions/install-rust 49 - run: rustup component add rustfmt 50 - run: cargo fmt --all -- --check 51 52 # common logic to cancel the entire run if this job fails 53 - run: gh run cancel ${{ github.run_id }} 54 if: failure() && github.event_name != 'pull_request' 55 env: 56 GH_TOKEN: ${{ github.token }} 57 58 # Check Code style quickly by running `clang-format` over all the C/C++ code 59 # 60 # Note that `wasmtime-platform.h` is excluded here as it's auto-generated. 61 clangformat: 62 name: Clang format 63 runs-on: ubuntu-latest 64 steps: 65 - uses: actions/checkout@v4 66 with: 67 submodules: true 68 - run: | 69 git ls-files '*.h' '*.c' '*.cpp' | \ 70 grep -v wasmtime-platform.h | \ 71 grep -v wasm.h | \ 72 xargs clang-format-15 --dry-run --Werror --verbose 73 74 # common logic to cancel the entire run if this job fails 75 - run: gh run cancel ${{ github.run_id }} 76 if: failure() && github.event_name != 'pull_request' 77 env: 78 GH_TOKEN: ${{ github.token }} 79 80 # Lint dependency graph for security advisories, duplicate versions, and 81 # incompatible licences 82 cargo_deny: 83 name: Cargo deny 84 needs: determine 85 if: needs.determine.outputs.audit 86 runs-on: ubuntu-latest 87 steps: 88 - uses: actions/checkout@v4 89 with: 90 submodules: true 91 - uses: ./.github/actions/install-rust 92 - run: | 93 set -e 94 curl -L https://github.com/EmbarkStudios/cargo-deny/releases/download/0.14.5/cargo-deny-0.14.5-x86_64-unknown-linux-musl.tar.gz | tar xzf - 95 mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny 96 echo `pwd` >> $GITHUB_PATH 97 - run: cargo deny check bans licenses 98 99 # common logic to cancel the entire run if this job fails 100 - run: gh run cancel ${{ github.run_id }} 101 if: failure() && github.event_name != 'pull_request' 102 env: 103 GH_TOKEN: ${{ github.token }} 104 105 # Ensure dependencies are vetted. See https://mozilla.github.io/cargo-vet/ 106 # 107 # Note that this step, on PRs only, is allowed to fail. This is then followed 108 # up with the `cargo_vet_failure_for_prs` step below. The intention is to 109 # avoid causing this check to fail PRs while still enabling it to fail the 110 # merge queue checks. That way PRs can enter the merge queue when this step is 111 # failing if `main` has picked up `cargo vet` entries in the meantime for the 112 # failures. 113 cargo_vet: 114 name: Cargo vet 115 needs: determine 116 if: needs.determine.outputs.audit 117 runs-on: ubuntu-latest 118 outputs: 119 outcome: ${{ steps.vet.outcome }} 120 steps: 121 - uses: actions/checkout@v4 122 with: 123 submodules: true 124 - uses: ./.github/actions/install-rust 125 - uses: ./.github/actions/install-cargo-vet 126 - id: vet 127 run: cargo vet --locked 128 continue-on-error: ${{ github.event_name == 'pull_request' }} 129 130 # common logic to cancel the entire run if this job fails 131 - run: gh run cancel ${{ github.run_id }} 132 if: failure() && github.event_name != 'pull_request' 133 env: 134 GH_TOKEN: ${{ github.token }} 135 136 cargo_vet_failure_for_prs: 137 name: Cargo vet failed on a Pull Request 138 needs: 139 - determine 140 - cargo_vet 141 if: | 142 needs.determine.outputs.audit 143 && github.event_name == 'pull_request' 144 && needs.cargo_vet.outputs.outcome == 'failure' 145 runs-on: ubuntu-latest 146 steps: 147 # NB: this message ideally would link back to the previous step, but I'm not 148 # sure how to easily do that. 149 - run: | 150 echo 'failed to run "cargo vet", see previous `Cargo vet` step' 151 echo 'exiting with a nonzero status now to alert PR authors' 152 echo 'note, though, that this PR can still enter the merge queue' 153 echo '' 154 echo 'See https://docs.wasmtime.dev/contributing-coding-guidelines.html#cargo-vet-for-contributors' 155 echo 'for more information about the vetting process for Wasmtime' 156 exit 1 157 158 # This job is a dependency of many of the jobs below. This calculates what's 159 # actually being run for this workflow. For example: 160 # 161 # * Pushes to branches, which is currently both pushes to merge queue branches 162 # as well as release branches, perform full CI. 163 # * PRs to release branches (not `main`) run full CI. 164 # * PRs to `main` will only run a few smoke tests above plus some elements of 165 # the test matrix. The test matrix here is determined dynamically by the 166 # `./ci/build-test-matrix.js` script given the commits that happened and 167 # the files modified. 168 determine: 169 name: Determine CI jobs to run 170 runs-on: ubuntu-latest 171 outputs: 172 run-full: ${{ steps.calculate.outputs.run-full }} 173 test-matrix: ${{ steps.calculate.outputs.test-matrix }} 174 build-matrix: ${{ steps.calculate.outputs.build-matrix }} 175 test-capi: ${{ steps.calculate.outputs.test-capi }} 176 test-nightly: ${{ steps.calculate.outputs.test-nightly }} 177 audit: ${{ steps.calculate.outputs.audit }} 178 preview1-adapter: ${{ steps.calculate.outputs.preview1-adapter }} 179 steps: 180 - uses: actions/checkout@v4 181 - id: calculate 182 env: 183 GH_TOKEN: ${{ github.token }} 184 run: | 185 touch commits.log names.log 186 # Note that CI doesn't run on pushes to `main`, only pushes to merge 187 # queue branches and release branches, so this only runs full CI in 188 # those locations. 189 if [ "${{ github.event_name }}" != "pull_request" ]; then 190 run_full=true 191 else 192 pr=${{ github.event.number }} 193 gh pr view $pr --json commits | tee commits.log 194 gh pr diff $pr --name-only | tee names.log || echo "failed to get files" 195 if [ "${{ github.base_ref }}" != "main" ]; then 196 run_full=true 197 elif grep -q 'prtest:full' commits.log; then 198 run_full=true 199 fi 200 if grep -q crates.c-api names.log; then 201 echo test-capi=true >> $GITHUB_OUTPUT 202 fi 203 if grep -q fuzz names.log; then 204 echo test-nightly=true >> $GITHUB_OUTPUT 205 fi 206 if grep -q sys.custom names.log; then 207 echo test-nightly=true >> $GITHUB_OUTPUT 208 fi 209 if grep -q Cargo.lock names.log; then 210 echo audit=true >> $GITHUB_OUTPUT 211 fi 212 if grep -q supply-chain names.log; then 213 echo audit=true >> $GITHUB_OUTPUT 214 fi 215 if grep -q component-adapter names.log; then 216 echo preview1-adapter=true >> $GITHUB_OUTPUT 217 fi 218 fi 219 matrix="$(node ./ci/build-test-matrix.js ./commits.log ./names.log $run_full)" 220 echo "test-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT 221 echo "$matrix" 222 223 matrix="$(node ./ci/build-build-matrix.js)" 224 echo "build-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT 225 226 if [ "$run_full" = "true" ]; then 227 echo run-full=true >> $GITHUB_OUTPUT 228 echo test-capi=true >> $GITHUB_OUTPUT 229 echo test-nightly=true >> $GITHUB_OUTPUT 230 echo audit=true >> $GITHUB_OUTPUT 231 echo preview1-adapter=true >> $GITHUB_OUTPUT 232 fi 233 234 # Build all documentation of Wasmtime, including the C API documentation, 235 # mdbook documentation, etc. This produces a `gh-pages` artifact which is what 236 # gets uploaded to the `gh-pages` branch later on. 237 doc: 238 needs: determine 239 if: needs.determine.outputs.run-full 240 name: Doc build 241 runs-on: ubuntu-latest 242 env: 243 CARGO_MDBOOK_VERSION: 0.4.37 244 RUSTDOCFLAGS: -Dbroken_intra_doc_links --cfg docsrs 245 OPENVINO_SKIP_LINKING: 1 246 steps: 247 - uses: actions/checkout@v4 248 with: 249 submodules: true 250 - uses: ./.github/actions/install-rust 251 with: 252 toolchain: wasmtime-ci-pinned-nightly 253 254 # Build C API documentation 255 - run: curl -L https://sourceforge.net/projects/doxygen/files/rel-1.9.3/doxygen-1.9.3.linux.bin.tar.gz/download | tar xzf - 256 - run: echo "`pwd`/doxygen-1.9.3/bin" >> $GITHUB_PATH 257 - run: cd crates/c-api && doxygen doxygen.conf 258 259 # install mdbook, build the docs, and test the docs 260 - uses: actions/cache@v4 261 with: 262 path: ${{ runner.tool_cache }}/mdbook 263 key: cargo-mdbook-bin-${{ env.CARGO_MDBOOK_VERSION }} 264 - run: | 265 echo "${{ runner.tool_cache }}/mdbook/bin" >> $GITHUB_PATH 266 cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.CARGO_MDBOOK_VERSION }} mdbook --locked 267 - run: (cd docs && mdbook build) 268 - run: cargo build -p wasi-common --features wasmtime/wat,wasmtime/cranelift 269 - run: (cd docs && mdbook test -L ../target/debug/deps) 270 271 # Build Rust API documentation. 272 # We pass in the `component-model` feature 273 # to match the docs.rs metadata in 274 # crates/wasmtime/Cargo.toml. 275 - run: | 276 cargo doc --no-deps --workspace \ 277 --exclude wasmtime-cli \ 278 --exclude test-programs \ 279 --exclude wasi-http-tests \ 280 --exclude cranelift-codegen-meta \ 281 --features component-model 282 - run: cargo doc --package cranelift-codegen-meta --document-private-items 283 284 # Assemble the documentation, and always upload it as an artifact for 285 # inspection on PRs and such. 286 - run: | 287 mv docs/book gh-pages 288 mv crates/c-api/html gh-pages/c-api 289 mv target/doc gh-pages/api 290 tar czf gh-pages.tar.gz gh-pages 291 - uses: actions/upload-artifact@v4 292 with: 293 name: gh-pages 294 path: gh-pages.tar.gz 295 296 # common logic to cancel the entire run if this job fails 297 - run: gh run cancel ${{ github.run_id }} 298 if: failure() && github.event_name != 'pull_request' 299 env: 300 GH_TOKEN: ${{ github.token }} 301 302 # Checks of various feature combinations and whether things compile. The goal 303 # here isn't to run tests, mostly just serve as a double-check that Rust code 304 # compiles and is likely to work everywhere else. 305 micro_checks: 306 needs: determine 307 name: Check ${{matrix.name}} 308 strategy: 309 fail-fast: true 310 matrix: 311 include: 312 - name: wasmtime 313 checks: | 314 -p wasmtime --no-default-features 315 -p wasmtime --no-default-features --features wat 316 -p wasmtime --no-default-features --features profiling 317 -p wasmtime --no-default-features --features cache 318 -p wasmtime --no-default-features --features async 319 -p wasmtime --no-default-features --features pooling-allocator 320 -p wasmtime --no-default-features --features cranelift 321 -p wasmtime --no-default-features --features component-model 322 -p wasmtime --no-default-features --features runtime,component-model 323 -p wasmtime --no-default-features --features cranelift,wat,async,cache 324 -p wasmtime --no-default-features --features winch 325 -p wasmtime --no-default-features --features wmemcheck 326 -p wasmtime --no-default-features --features wmemcheck,cranelift,runtime 327 -p wasmtime --no-default-features --features demangle 328 -p wasmtime --no-default-features --features addr2line 329 -p wasmtime --no-default-features --features gc 330 -p wasmtime --no-default-features --features runtime,gc 331 -p wasmtime --no-default-features --features cranelift,gc 332 -p wasmtime --no-default-features --features runtime 333 -p wasmtime --no-default-features --features threads 334 -p wasmtime --no-default-features --features runtime,threads 335 -p wasmtime --no-default-features --features cranelift,threads 336 -p wasmtime --features incremental-cache 337 -p wasmtime --all-features 338 339 - name: wasmtime-cli 340 checks: | 341 -p wasmtime-cli --no-default-features 342 -p wasmtime-cli --no-default-features --features run 343 -p wasmtime-cli --no-default-features --features run,component-model 344 -p wasmtime-cli --no-default-features --features compile 345 -p wasmtime-cli --no-default-features --features compile,cranelift 346 -p wasmtime-cli --no-default-features --features compile,cranelift,component-model 347 -p wasmtime-cli --all-features 348 -p wasmtime-cli --features component-model 349 350 - name: cranelift-codegen benches 351 checks: | 352 --benches -p cranelift-codegen 353 354 - name: wasmtime-bench-api 355 checks: | 356 -p wasmtime-bench-api 357 358 - name: wasmtime-c-api 359 checks: | 360 -p wasmtime-c-api --no-default-features 361 -p wasmtime-c-api --no-default-features --features wat 362 -p wasmtime-c-api --no-default-features --features wasi 363 runs-on: ubuntu-latest 364 steps: 365 - uses: actions/checkout@v4 366 with: 367 submodules: true 368 - uses: ./.github/actions/install-rust 369 370 # Run the check. 371 - run: | 372 checks=$(cat <<END 373 ${{ matrix.checks }} 374 END 375 ) 376 echo "$checks" | xargs -I CHECK sh -c 'echo "=== cargo check CHECK ==="; cargo check CHECK' 377 378 # Common logic to cancel the entire run if this job fails. 379 - run: gh run cancel ${{ github.run_id }} 380 if: failure() && github.event_name != 'pull_request' 381 env: 382 GH_TOKEN: ${{ github.token }} 383 384 # Similar to `micro_checks` but where we need to install some more state 385 # (e.g. Android NDK) and we haven't factored support for those things out into 386 # a parallel jobs yet. 387 monolith_checks: 388 needs: determine 389 name: Monolith Checks 390 runs-on: ubuntu-latest 391 env: 392 CARGO_NDK_VERSION: 2.12.2 393 steps: 394 - uses: actions/checkout@v4 395 with: 396 submodules: true 397 - uses: ./.github/actions/install-rust 398 399 # Checks for no_std support, ensure that crates can build on a no_std 400 # target 401 - run: rustup target add x86_64-unknown-none 402 - run: cargo check -p wasmtime --no-default-features --features runtime,gc,component-model 403 env: 404 CARGO_BUILD_TARGET: x86_64-unknown-none 405 406 # Check that wasmtime compiles with panic=abort since there's some `#[cfg]` 407 # for specifically panic=abort there. 408 - run: cargo check -p wasmtime 409 env: 410 RUSTFLAGS: -Cpanic=abort 411 412 # Check a few builds of the cranelift backend 413 # - only x86 backend support, 414 # - only arm64 backend support, 415 # - no debug_assertions. 416 - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/arm64 417 - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/x86 418 - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util 419 env: 420 CARGO_PROFILE_DEV_DEBUG_ASSERTIONS: false 421 422 # Check whether `wasmtime` cross-compiles to x86_64-unknown-freebsd 423 # TODO: We aren't building with default features since the `ittapi` crate fails to compile on freebsd. 424 - run: rustup target add x86_64-unknown-freebsd 425 - run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache --target x86_64-unknown-freebsd 426 427 # Run clippy configuration 428 - run: rustup component add clippy 429 - run: cargo clippy --workspace 430 431 # Re-vendor all WIT files and ensure that they're all up-to-date by ensuring 432 # that there's no git changes. 433 - name: Re-vendor WIT 434 run: ./ci/vendor-wit.sh 435 - run: git diff --exit-code 436 437 # Re-vendor the C API and make sure it's up-to-date. 438 - name: Re-vendor WIT 439 run: ./ci/vendor-c-api-headers.sh 440 - run: git diff --exit-code 441 442 # common logic to cancel the entire run if this job fails 443 - run: gh run cancel ${{ github.run_id }} 444 if: failure() && github.event_name != 'pull_request' 445 env: 446 GH_TOKEN: ${{ github.token }} 447 448 # Check whether `wasmtime` cross-compiles to aarch64-pc-windows-msvc 449 # We don't build nor test it because it lacks trap handling. 450 # Tracking issue: https://github.com/bytecodealliance/wasmtime/issues/4992 451 checks_winarm64: 452 needs: determine 453 if: needs.determine.outputs.run-full 454 name: Check Windows ARM64 455 runs-on: windows-latest 456 steps: 457 - uses: actions/checkout@v4 458 with: 459 submodules: true 460 - uses: ./.github/actions/install-rust 461 - run: rustup target add aarch64-pc-windows-msvc 462 - run: cargo check -p wasmtime --target aarch64-pc-windows-msvc 463 464 # common logic to cancel the entire run if this job fails 465 - run: gh run cancel ${{ github.run_id }} 466 if: failure() && github.event_name != 'pull_request' 467 env: 468 GH_TOKEN: ${{ github.token }} 469 470 # Run tests that require a nightly compiler, such as building fuzz targets. 471 test_nightly: 472 needs: determine 473 if: needs.determine.outputs.test-nightly 474 name: Nightly tests 475 runs-on: ubuntu-latest 476 steps: 477 - uses: actions/checkout@v4 478 with: 479 submodules: true 480 # Note that nightly is pinned here to insulate us from breakage that might 481 # happen upstream. This is periodically updated through a PR. 482 - uses: ./.github/actions/install-rust 483 with: 484 toolchain: wasmtime-ci-pinned-nightly 485 486 # Ensure that fuzzers still build. 487 # 488 # Install the OCaml packages necessary for fuzz targets that use the 489 # `wasm-spec-interpreter`. 490 - run: cargo install cargo-fuzz --vers "^0.11" --locked 491 - run: sudo apt-get update && sudo apt install -y ocaml-nox ocamlbuild ocaml-findlib libzarith-ocaml-dev 492 - run: cargo fetch 493 working-directory: ./fuzz 494 - run: cargo fuzz build --dev -s none 495 - run: cargo fuzz build --dev -s none --fuzz-dir ./cranelift/isle/fuzz 496 - run: cargo fuzz build --dev -s none --fuzz-dir ./crates/environ/fuzz --features component-model 497 498 # common logic to cancel the entire run if this job fails 499 - run: gh run cancel ${{ github.run_id }} 500 if: failure() && github.event_name != 'pull_request' 501 env: 502 GH_TOKEN: ${{ github.token }} 503 504 # Perform all tests of the c-api 505 test_capi: 506 needs: determine 507 name: Test C-API ${{ matrix.os }} 508 runs-on: ${{ matrix.os }} 509 if: needs.determine.outputs.test-capi 510 511 strategy: 512 fail-fast: true 513 matrix: 514 os: [ubuntu-latest, macos-latest, windows-latest] 515 516 steps: 517 - uses: actions/checkout@v4 518 with: 519 submodules: true 520 - uses: ./.github/actions/install-rust 521 522 # Build and test the C API with example C programs along with the example 523 # Rust programs. Note that this only executes if the `determine` step told 524 # us to test the capi which is off-by-default for PRs. 525 - run: cmake -Sexamples -Bexamples/build -DBUILD_SHARED_LIBS=OFF 526 - run: cmake --build examples/build --config Debug 527 - run: cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target RUN_TESTS 528 env: 529 RUST_BACKTRACE: 1 530 if: matrix.os == 'windows-latest' 531 - run: cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target test 532 env: 533 RUST_BACKTRACE: 1 534 if: matrix.os != 'windows-latest' 535 536 # Perform all tests (debug mode) for `wasmtime`. 537 # 538 # Note that the full matrix for what may run here is defined within 539 # `./ci/build-test-matrix.js` and the execution of the `determine` step will 540 # calculate whether the tests are actually run as part of PRs and such. 541 test: 542 needs: determine 543 name: ${{ matrix.name }} 544 runs-on: ${{ matrix.os }} 545 env: 546 QEMU_BUILD_VERSION: 8.1.5 547 strategy: 548 fail-fast: ${{ github.event_name != 'pull_request' }} 549 matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }} 550 steps: 551 - uses: actions/checkout@v4 552 with: 553 submodules: true 554 - uses: ./.github/actions/install-rust 555 with: 556 toolchain: ${{ matrix.rust }} 557 558 # Install targets in order to build various tests throughout the repo 559 - run: rustup target add wasm32-wasi wasm32-unknown-unknown ${{ matrix.target }} 560 - run: echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV 561 if: matrix.target != '' 562 563 # Fix an ICE for now in gcc when compiling zstd with debuginfo (??) 564 - run: echo CFLAGS=-g0 >> $GITHUB_ENV 565 if: matrix.target == 'x86_64-pc-windows-gnu' 566 567 # Update binutils if MinGW due to https://github.com/rust-lang/rust/issues/112368 568 - run: C:/msys64/usr/bin/pacman.exe -S --needed mingw-w64-x86_64-gcc --noconfirm 569 if: matrix.target == 'x86_64-pc-windows-gnu' 570 - shell: pwsh 571 run: echo "C:\msys64\mingw64\bin" >> $Env:GITHUB_PATH 572 if: matrix.target == 'x86_64-pc-windows-gnu' 573 574 - run: cargo fetch --locked 575 576 - uses: actions/cache@v4 577 with: 578 path: ${{ runner.tool_cache }}/qemu 579 key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patchcpuinfo 580 if: matrix.target != '' && matrix.os == 'ubuntu-latest' 581 - name: Install cross-compilation tools 582 run: | 583 set -ex 584 sudo apt-get update 585 sudo apt-get install -y ${{ matrix.gcc_package }} ninja-build 586 587 # Configure Cargo for cross compilation and tell it how it can run 588 # cross executables 589 upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g') 590 echo CARGO_TARGET_${upcase}_RUNNER=${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} >> $GITHUB_ENV 591 echo CARGO_TARGET_${upcase}_LINKER=${{ matrix.gcc }} >> $GITHUB_ENV 592 593 # QEMU emulation is not always the speediest, so total testing time 594 # goes down if we build the libs in release mode when running tests. 595 echo CARGO_PROFILE_DEV_OPT_LEVEL=2 >> $GITHUB_ENV 596 597 # See comments in the source for why we enable this during QEMU 598 # emulation. 599 echo WASMTIME_TEST_NO_HOG_MEMORY=1 >> $GITHUB_ENV 600 601 # See if qemu is already in the cache 602 if [ -f ${{ runner.tool_cache }}/qemu/built ]; then 603 exit 0 604 fi 605 606 # Download and build qemu from source since the most recent release is 607 # way faster at arm emulation than the current version github actions' 608 # ubuntu image uses. Disable as much as we can to get it to build 609 # quickly. 610 curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf - 611 cd qemu-$QEMU_BUILD_VERSION 612 ./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache}}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs 613 ninja -C build install 614 touch ${{ runner.tool_cache }}/qemu/built 615 if: matrix.gcc != '' 616 617 # Record some CPU details; this is helpful information if tests fail due 618 # to CPU-specific features. 619 - name: CPU information 620 run: lscpu 621 if: matrix.os == 'ubuntu-latest' 622 - name: CPU information 623 run: sysctl hw 624 if: contains(matrix.os, 'macos') 625 - name: CPU information 626 run: wmic cpu list /format:list 627 shell: pwsh 628 if: matrix.os == 'windows-latest' 629 630 # Since MPK (PKU) is not present on some GitHub runners, we check if it is 631 # available before force-enabling it. This occasional testing is better than 632 # none at all; ideally we would test in a system-mode QEMU VM. 633 - name: Force-run with MPK enabled, if available 634 if: ${{ contains(matrix.name, 'MPK') }} 635 run: | 636 if cargo run --example mpk-available; then 637 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." 638 echo WASMTIME_TEST_FORCE_MPK=1 >> $GITHUB_ENV 639 else 640 echo "::warning::This CI run will not test MPK; it has been detected as not available on this machine (\`cargo run --example mpk-available\`)." 641 fi 642 643 # Build and test all features 644 - run: ./ci/run-tests.sh --locked ${{ matrix.bucket }} 645 env: 646 RUST_BACKTRACE: 1 647 648 # NB: the test job here is explicitly lacking in cancellation of this run if 649 # something goes wrong. These take the longest anyway and otherwise if 650 # Windows fails GitHub Actions will confusingly mark the failed Windows job 651 # as cancelled instead of failed. 652 653 # Test `wasmtime-wasi-nn` in its own job, as not all of its backends are 654 # compatible with all targets, and each must be tested separately anyways. 655 test_wasi_nn: 656 strategy: 657 matrix: 658 feature: ["openvino", "onnx"] 659 os: ["ubuntu-latest", "windows-latest"] 660 name: Test wasi-nn (${{ matrix.feature }}, ${{ matrix.os }}) 661 runs-on: ${{ matrix.os }} 662 needs: determine 663 if: needs.determine.outputs.run-full 664 steps: 665 - uses: actions/checkout@v4 666 with: 667 submodules: true 668 - uses: ./.github/actions/install-rust 669 670 # Install OpenVINO 671 - uses: abrown/install-openvino-action@v8 672 if: runner.arch == 'X64' 673 674 # Install Rust targets. 675 - run: rustup target add wasm32-wasi 676 677 # Run the tests! 678 - run: cargo test -p wasmtime-wasi-nn --features ${{ matrix.feature }} 679 env: 680 RUST_BACKTRACE: 1 681 682 # common logic to cancel the entire run if this job fails 683 - run: gh run cancel ${{ github.run_id }} 684 if: failure() && github.event_name != 'pull_request' 685 env: 686 GH_TOKEN: ${{ github.token }} 687 688 # Test the `wasmtime-fuzzing` crate. Split out from the main tests because 689 # `--all-features` brings in OCaml, which is a pain to get setup for all 690 # targets. 691 test_fuzzing: 692 needs: determine 693 if: needs.determine.outputs.run-full 694 name: Test wasmtime-fuzzing 695 runs-on: 'ubuntu-latest' 696 steps: 697 - uses: actions/checkout@v4 698 with: 699 submodules: true 700 - uses: ./.github/actions/install-rust 701 702 # Run the tests 703 - run: | 704 cargo test -p wasmtime-fuzzing -p wasm-spec-interpreter 705 env: 706 RUST_BACKTRACE: 1 707 708 # common logic to cancel the entire run if this job fails 709 - run: gh run cancel ${{ github.run_id }} 710 if: failure() && github.event_name != 'pull_request' 711 env: 712 GH_TOKEN: ${{ github.token }} 713 714 # Test debug (DWARF) related functionality. 715 test_debug_dwarf: 716 needs: determine 717 if: needs.determine.outputs.run-full 718 name: Test DWARF debugging 719 runs-on: 'ubuntu-latest' 720 steps: 721 - uses: actions/checkout@v4 722 with: 723 submodules: true 724 - uses: ./.github/actions/install-rust 725 - run: rustup target add wasm32-wasi wasm32-unknown-unknown 726 - run: | 727 sudo apt-get update && sudo apt-get install -y gdb lldb-15 llvm 728 # woraround for https://bugs.launchpad.net/ubuntu/+source/llvm-defaults/+bug/1972855 729 sudo mkdir -p /usr/lib/local/lib/python3.10/dist-packages/lldb 730 sudo ln -s /usr/lib/llvm-15/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/ 731 cargo test test_debug_dwarf -- --ignored --test-threads 1 732 env: 733 RUST_BACKTRACE: 1 734 LLDB: lldb-15 # override default version, 14 735 736 # common logic to cancel the entire run if this job fails 737 - run: gh run cancel ${{ github.run_id }} 738 if: failure() && github.event_name != 'pull_request' 739 env: 740 GH_TOKEN: ${{ github.token }} 741 742 build-preview1-component-adapter: 743 name: Build wasi-preview1-component-adapter 744 needs: determine 745 if: needs.determine.outputs.preview1-adapter 746 runs-on: ubuntu-latest 747 permissions: 748 deployments: write 749 contents: write 750 steps: 751 - uses: actions/checkout@v4 752 with: 753 submodules: true 754 - uses: ./.github/actions/install-rust 755 - run: rustup target add wasm32-wasi wasm32-unknown-unknown 756 757 - name: Install wasm-tools 758 run: | 759 curl -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 - 760 echo `pwd`/wasm-tools-1.0.27-x86_64-linux >> $GITHUB_PATH 761 762 - run: ./ci/build-wasi-preview1-component-adapter.sh 763 env: 764 VERSION: ${{ github.sha }} 765 766 - uses: actions/upload-artifact@v4 767 with: 768 name: bins-wasi-preview1-component-adapter 769 path: target/wasm32-unknown-unknown/release/wasi_snapshot_preview1.*.wasm 770 771 772 # common logic to cancel the entire run if this job fails 773 - run: gh run cancel ${{ github.run_id }} 774 if: failure() && github.event_name != 'pull_request' 775 env: 776 GH_TOKEN: ${{ github.token }} 777 778 # Verify the "min platform" example still works. 779 test-min-platform-example: 780 name: Test the min-platform example 781 needs: determine 782 if: needs.determine.outputs.run-full 783 runs-on: ubuntu-latest 784 steps: 785 - uses: actions/checkout@v4 786 with: 787 submodules: true 788 - uses: ./.github/actions/install-rust 789 - run: cargo install cbindgen --vers "^0.26" --locked 790 - run: rustup target add x86_64-unknown-none 791 - run: ./build.sh x86_64-unknown-none 792 working-directory: ./examples/min-platform 793 794 # Afterwards make sure the generated header file is up to date by ensuring 795 # that the regeneration process didn't change anything in-tree. 796 - run: git diff --exit-code 797 798 # Add the `wasmtime-platform.h` file as a release artifact 799 - uses: actions/upload-artifact@v4 800 with: 801 name: wasmtime-platform-header 802 path: examples/min-platform/embedding/wasmtime-platform.h 803 804 # common logic to cancel the entire run if this job fails 805 - run: gh run cancel ${{ github.run_id }} 806 if: failure() && github.event_name != 'pull_request' 807 env: 808 GH_TOKEN: ${{ github.token }} 809 810 811 build-wasmtime-target-wasm32: 812 name: Build wasmtime-target-wasm32 813 if: needs.determine.outputs.run-full 814 needs: determine 815 runs-on: ubuntu-latest 816 steps: 817 - uses: actions/checkout@v4 818 with: 819 submodules: true 820 - uses: ./.github/actions/install-rust 821 - run: rustup target add wasm32-wasi wasm32-unknown-unknown 822 - run: cargo build --target wasm32-wasi --no-default-features --features compile,cranelift,all-arch 823 env: 824 VERSION: ${{ github.sha }} 825 826 # common logic to cancel the entire run if this job fails 827 - run: gh run cancel ${{ github.run_id }} 828 if: failure() && github.event_name != 'pull_request' 829 env: 830 GH_TOKEN: ${{ github.token }} 831 832 833 bench: 834 needs: determine 835 if: needs.determine.outputs.run-full 836 name: Run benchmarks 837 runs-on: ubuntu-latest 838 steps: 839 - uses: actions/checkout@v4 840 with: 841 submodules: true 842 - uses: ./.github/actions/install-rust 843 - run: rustup target add wasm32-wasi 844 - run: cargo test --benches --release 845 846 # common logic to cancel the entire run if this job fails 847 - run: gh run cancel ${{ github.run_id }} 848 if: failure() && github.event_name != 'pull_request' 849 env: 850 GH_TOKEN: ${{ github.token }} 851 852 # Verify that cranelift's code generation is deterministic 853 meta_deterministic_check: 854 needs: determine 855 if: needs.determine.outputs.run-full 856 name: Meta deterministic check 857 runs-on: ubuntu-latest 858 steps: 859 - uses: actions/checkout@v4 860 with: 861 submodules: true 862 - uses: ./.github/actions/install-rust 863 - run: cd cranelift/codegen && cargo build --features all-arch 864 - run: ci/ensure_deterministic_build.sh 865 866 # common logic to cancel the entire run if this job fails 867 - run: gh run cancel ${{ github.run_id }} 868 if: failure() && github.event_name != 'pull_request' 869 env: 870 GH_TOKEN: ${{ github.token }} 871 872 verify-publish: 873 needs: determine 874 if: github.repository == 'bytecodealliance/wasmtime' && needs.determine.outputs.run-full 875 runs-on: ubuntu-latest 876 steps: 877 - uses: actions/checkout@v4 878 with: 879 submodules: true 880 - uses: ./.github/actions/install-rust 881 - run: | 882 cd ${{ runner.tool_cache }} 883 curl -L https://github.com/mozilla/sccache/releases/download/0.2.13/sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz | tar xzf - 884 echo "`pwd`/sccache-0.2.13-x86_64-unknown-linux-musl" >> $GITHUB_PATH 885 echo RUSTC_WRAPPER=sccache >> $GITHUB_ENV 886 - run: rustc scripts/publish.rs 887 # Make sure the tree is publish-able as-is 888 - run: ./publish verify 889 # Make sure we can bump version numbers for the next release 890 - run: ./publish bump 891 892 # common logic to cancel the entire run if this job fails 893 - run: gh run cancel ${{ github.run_id }} 894 if: failure() && github.event_name != 'pull_request' 895 env: 896 GH_TOKEN: ${{ github.token }} 897 898 # Run a subset of tests under MIRI on CI to help check the `unsafe` code in 899 # Wasmtime to make sure it's at least not obviously incorrect for basic usage. 900 # Note that this doesn't run the full test suite since MIRI can't actually run 901 # WebAssembly itself at this time (aka it doesn't support a JIT). There are a 902 # number of annotations throughout the code which gates some tests on MIRI not 903 # being run. 904 # 905 # Note that `cargo nextest` is used here additionally to get parallel test 906 # execution by default to help cut down on the time in CI. 907 miri: 908 strategy: 909 matrix: 910 crate: ["wasmtime", "wasmtime-cli", "wasmtime-environ"] 911 needs: determine 912 if: needs.determine.outputs.run-full && github.repository == 'bytecodealliance/wasmtime' 913 name: Miri 914 runs-on: ubuntu-latest 915 env: 916 CARGO_NEXTEST_VERSION: 0.9.67 917 steps: 918 - uses: actions/checkout@v4 919 with: 920 submodules: true 921 - uses: ./.github/actions/install-rust 922 with: 923 toolchain: wasmtime-ci-pinned-nightly 924 - run: rustup component add rust-src miri 925 - uses: actions/cache@v4 926 with: 927 path: ${{ runner.tool_cache }}/cargo-nextest 928 key: cargo-nextest-bin-${{ env.CARGO_NEXTEST_VERSION }} 929 - run: echo "${{ runner.tool_cache }}/cargo-nextest/bin" >> $GITHUB_PATH 930 - run: cargo install --root ${{ runner.tool_cache }}/cargo-nextest --version ${{ env.CARGO_NEXTEST_VERSION }} cargo-nextest --locked 931 - run: | 932 cargo miri nextest run -j4 --no-fail-fast -p ${{ matrix.crate }} 933 env: 934 MIRIFLAGS: -Zmiri-strict-provenance 935 936 # common logic to cancel the entire run if this job fails 937 - run: gh run cancel ${{ github.run_id }} 938 if: failure() && github.event_name != 'pull_request' 939 env: 940 GH_TOKEN: ${{ github.token }} 941 942 # Perform release builds of `wasmtime` and `libwasmtime.so`. Builds a variety 943 # of platforms and architectures and then uploads the release artifacts to 944 # this workflow run's list of artifacts. 945 # 946 # Note that the full matrix is computed by `ci/build-build-matrix.js`. 947 build: 948 needs: determine 949 if: needs.determine.outputs.run-full 950 name: Release build for ${{ matrix.build }} 951 runs-on: ${{ matrix.os }} 952 strategy: 953 fail-fast: ${{ github.event_name != 'pull_request' }} 954 matrix: ${{ fromJson(needs.determine.outputs.build-matrix) }} 955 steps: 956 - uses: actions/checkout@v4 957 with: 958 submodules: true 959 960 - uses: ./.github/actions/install-rust 961 with: 962 toolchain: ${{ matrix.rust }} 963 - run: | 964 rustup component add rust-src 965 rustup target add ${{ matrix.target }} 966 967 # On one builder produce the source tarball since there's no need to produce 968 # it everywhere 969 - run: ./ci/build-src-tarball.sh 970 if: matrix.build == 'x86_64-linux' 971 - uses: ./.github/actions/binary-compatible-builds 972 with: 973 name: ${{ matrix.build }} 974 975 - uses: ./.github/actions/android-ndk 976 if: contains(matrix.target, 'android') 977 with: 978 target: ${{ matrix.target }} 979 980 - run: $CENTOS ./ci/build-release-artifacts.sh "${{ matrix.build }}" "${{ matrix.target }}" 981 982 # Assemble release artifacts appropriate for this platform, then upload them 983 # unconditionally to this workflow's files so we have a copy of them. 984 - run: ./ci/build-tarballs.sh "${{ matrix.build }}" "${{ matrix.target }}" 985 986 - uses: actions/upload-artifact@v4 987 with: 988 name: bins-${{ matrix.build }} 989 path: dist 990 991 # common logic to cancel the entire run if this job fails 992 - run: gh run cancel ${{ github.run_id }} 993 if: failure() && github.event_name != 'pull_request' 994 env: 995 GH_TOKEN: ${{ github.token }} 996 997 # This is a "join node" which depends on all prior workflows. The merge queue, 998 # for example, gates on this to ensure that everything has executed 999 # successfully. 1000 # 1001 # Note that this is required currently for odd reasons with github. Notably 1002 # the set of checks to enter the merge queue and leave the merge queue must 1003 # be the same which means that the "build" step for example shows as skipped 1004 # for PRs but expands to many different steps for merge-queue-based PRs. That 1005 # means that for that step there's no single name to gate on, so it's required 1006 # to have a "join" node here which joins everything. 1007 # 1008 # Note that this currently always runs to always report a status, even on 1009 # cancellation and even if dependency steps fail. Each dependency tries to 1010 # cancel the whole run if it fails, so if a test matrix entry fails, for 1011 # example, it cancels the build matrix entries too. This step then tries to 1012 # fail on cancellation to ensure that the dependency failures are propagated 1013 # correctly. 1014 ci-status: 1015 name: Record the result of testing and building steps 1016 runs-on: ubuntu-latest 1017 needs: 1018 - test 1019 - test_capi 1020 - test_debug_dwarf 1021 - test_fuzzing 1022 - test_wasi_nn 1023 - test_nightly 1024 - build 1025 - rustfmt 1026 - clangformat 1027 - cargo_deny 1028 - cargo_vet 1029 - doc 1030 - micro_checks 1031 - monolith_checks 1032 - checks_winarm64 1033 - bench 1034 - meta_deterministic_check 1035 - verify-publish 1036 - determine 1037 - miri 1038 - build-preview1-component-adapter 1039 - build-wasmtime-target-wasm32 1040 - test-min-platform-example 1041 if: always() 1042 steps: 1043 - name: Successful test and build 1044 if: ${{ !(contains(needs.*.result, 'failure')) }} 1045 run: exit 0 1046 - name: Failing test and build 1047 if: ${{ contains(needs.*.result, 'failure') }} 1048 run: exit 1 1049 - name: Report failure on cancellation 1050 if: ${{ contains(needs.*.result, 'cancelled') || cancelled() }} 1051 run: exit 1 1052 1053 # The purpose of this jobs is to watch for changes on the `release-*` 1054 # branches of this repository and look for the term 1055 # "automatically-tag-and-release-this-commit" within merged PRs/commits. Once 1056 # that term is found the current version of `Cargo.toml`, the `wasmtime-cli` 1057 # Cargo.toml, is created as a tag and the tag is pushed to the repo. 1058 # Currently the tag is created through the GitHub API with an access token to 1059 # ensure that CI is further triggered for the tag itself which performs the 1060 # full release process. 1061 # 1062 # Note that this depends on the `ci-status` step above which is the "join" 1063 # point of this workflow for when everything succeeds. the purpose of that is 1064 # so that the tag is only created after the aftifacts have been uploaded for 1065 # this workflow as the `publish-artifacts.yml` workflow will download these 1066 # artifacts and then publish them to the tag. 1067 push-tag: 1068 runs-on: ubuntu-latest 1069 needs: ci-status 1070 if: | 1071 always() 1072 && needs.ci-status.result == 'success' 1073 && github.event_name == 'push' 1074 && startsWith(github.ref, 'refs/heads/release-') 1075 && github.repository == 'bytecodealliance/wasmtime' 1076 steps: 1077 - uses: actions/checkout@v4 1078 with: 1079 submodules: true 1080 fetch-depth: 0 1081 - name: Test if tag is needed 1082 run: | 1083 git log ${{ github.event.before }}...${{ github.event.after }} | tee main.log 1084 version=$(grep '^version =' Cargo.toml | head -n 1 | sed 's/.*"\(.*\)"/\1/') 1085 echo "version: $version" 1086 echo "version=$version" >> $GITHUB_OUTPUT 1087 echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT 1088 if grep -q "automatically-tag-and-release-this-commit" main.log; then 1089 echo push-tag 1090 echo "push_tag=yes" >> $GITHUB_OUTPUT 1091 else 1092 echo no-push-tag 1093 echo "push_tag=no" >> $GITHUB_OUTPUT 1094 fi 1095 id: tag 1096 - name: Push the tag 1097 run: | 1098 git_refs_url=$(jq .repository.git_refs_url $GITHUB_EVENT_PATH | tr -d '"' | sed 's/{\/sha}//g') 1099 curl -iX POST $git_refs_url \ 1100 -H "Authorization: token ${{ secrets.PERSONAL_ACCESS_TOKEN }}" \ 1101 -d @- << EOF 1102 { 1103 "ref": "refs/tags/v${{ steps.tag.outputs.version }}", 1104 "sha": "${{ steps.tag.outputs.sha }}" 1105 } 1106 EOF 1107 if: steps.tag.outputs.push_tag == 'yes' 1108