From 52bd191b34c7e9044b82cda51f92e0df51693855 Mon Sep 17 00:00:00 2001 From: can1357 Date: Thu, 30 Jul 2026 07:20:27 +0200 Subject: [PATCH] build: optimized Bazel repository and toolchain caching for CI - Pin Rust toolchain component checksums in MODULE.bazel to enable Bazel's repo contents cache. - Opt MSVC LLVM tools, XWin sysroot, and Zig repositories into reproducible repo metadata caching. - Extend GitHub Actions cache paths to include the Bazel repository download and contents cache. --- .github/actions/bazel-cache/action.yml | 14 ++++++- .github/actions/bazel-natives/action.yml | 5 ++- MODULE.bazel | 39 +++++++++++++++++++ ..._cc_toolchain-isolated-compile-cache.patch | 27 ++++++++++++- bazel/toolchains/msvc/llvm.bzl | 6 +++ bazel/toolchains/msvc/sysroot.bzl | 8 ++++ 6 files changed, 95 insertions(+), 4 deletions(-) diff --git a/.github/actions/bazel-cache/action.yml b/.github/actions/bazel-cache/action.yml index 0d40424b0..6247e2c9f 100644 --- a/.github/actions/bazel-cache/action.yml +++ b/.github/actions/bazel-cache/action.yml @@ -77,7 +77,14 @@ runs: if: steps.backend.outputs.remote != 'true' uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: - path: ~/.cache/omp-bazel-disk + # Both caches ride one archive: the action cache AND the repository + # cache (downloads + extracted repo contents at repo/contents, which + # reproducible repo rules reuse across output bases). Without the + # repo half, every hosted job re-downloaded and re-extracted the + # rust/LLVM/zig toolchains. Save sites must list the same paths. + path: | + ~/.cache/omp-bazel-disk + ~/.cache/omp-bazel-repo key: ${{ steps.backend.outputs.cache-key }} # Order matters: exact key, same-config prefix, then any archive for # this scope+os+arch. The bare fallback is what keeps release version @@ -130,7 +137,10 @@ runs: # generations wrote would otherwise ride along forever; drop # anything untouched for 14 days (tar preserves mtimes across # the actions/cache round trip, so age survives restores). - find "$HOME/.cache/omp-bazel-disk" -type f -mtime +14 -delete 2>/dev/null || true + # Covers the repo download/contents cache too — bazel's own + # contents-cache GC only runs on idle servers, which short-lived + # CI invocations never have. + find "$HOME/.cache/omp-bazel-disk" "$HOME/.cache/omp-bazel-repo" -type f -mtime +14 -delete 2>/dev/null || true { echo "common --config=ci" echo "common --disk_cache=$HOME/.cache/omp-bazel-disk" diff --git a/.github/actions/bazel-natives/action.yml b/.github/actions/bazel-natives/action.yml index 8dfbf9457..408548d1e 100644 --- a/.github/actions/bazel-natives/action.yml +++ b/.github/actions/bazel-natives/action.yml @@ -43,5 +43,8 @@ runs: if: steps.cache.outputs.save-needed == 'true' uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: - path: ~/.cache/omp-bazel-disk + # Must mirror the restore path list in the bazel-cache action. + path: | + ~/.cache/omp-bazel-disk + ~/.cache/omp-bazel-repo key: ${{ steps.cache.outputs.cache-key }} \ No newline at end of file diff --git a/MODULE.bazel b/MODULE.bazel index 7846ae953..74c8ed707 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -37,6 +37,45 @@ rust = use_extension("@rules_rust//rust:extensions.bzl", "rust") rust.toolchain( edition = "2024", versions = ["nightly/2026-04-29"], + # Pinned archive checksums for every toolchain component. Not (only) a + # supply-chain nicety: rules_rust marks a toolchain-tools repo as + # reproducible — and therefore eligible for Bazel's repo contents cache — + # only when every sha256 it needs was predeclared here (repositories.bzl: + # `reproducible = sha256s == dict(ctx.attr.sha256s)`). Without these, + # every fresh output base (= every ephemeral CI pod) re-downloaded and + # re-extracted ~5 rustc toolchains (~20 s each). Regenerate after a + # version bump: for each `-nightly-` below, take the value + # from https://static.rust-lang.org/dist//.tar.xz.sha256. + sha256s = { + "2026-04-29/cargo-nightly-aarch64-apple-darwin.tar.xz": "9165010618ad581a90bd3e74a36cab092e6f509c8e7ffdcfe00293257cafabb7", + "2026-04-29/cargo-nightly-aarch64-unknown-linux-gnu.tar.xz": "f9b463c3eadaf040b5028590c3d3072c8b0893f9863ed25138dfc54c254388e1", + "2026-04-29/cargo-nightly-x86_64-apple-darwin.tar.xz": "03cf3edb1d0b9564fd466553092ccec5c37be729c35df1d77f7c5a9206801638", + "2026-04-29/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "0ae6ed5a9e262d082003d5804cd7fc6977057cfa3df721451e356347962f391f", + "2026-04-29/clippy-nightly-aarch64-apple-darwin.tar.xz": "84b933f8a2837c81adca3e3a44fed971ec0de27673e2c56f122f6d2b35ef9371", + "2026-04-29/clippy-nightly-aarch64-unknown-linux-gnu.tar.xz": "827c90b264a716475e85f51bd1999344af14648882cdd5a6d517a73c7e4c02c4", + "2026-04-29/clippy-nightly-x86_64-apple-darwin.tar.xz": "2c749f10bb18c752323b489e056c55f2e6e04ff3939d16444f4f0d960463d2d2", + "2026-04-29/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "36a9409a58b3ac16ce9823d4e705055cad8144dd7f18464c028e3a06ae5d87c8", + "2026-04-29/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "c6a5cfd0c6133e1fae913a624bef2387a1b9c1e2e75316f9d9b6872a592a8b2c", + "2026-04-29/llvm-tools-nightly-aarch64-unknown-linux-gnu.tar.xz": "7e51dc58df2d0d9e263d629e6b149785bb61b716e267cc841556a4641ed52a50", + "2026-04-29/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "ab6cd3bae1c979fd807982b8c39e911227f9344dab5051d45f612b440dad13ff", + "2026-04-29/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "0fb4bed6714359d9505b870c8bd67c722266c5a3894f66523bc231b9c479db31", + "2026-04-29/rust-src-nightly.tar.xz": "2a9c5ae7696a808e30fc5169ddfea20d69571a11997f142944c022a0d30af48b", + "2026-04-29/rust-std-nightly-aarch64-apple-darwin.tar.xz": "cd9e231f3e343b4ed5cff5c384c813cecba13fca94ef767fa8dc4aa0ff58a171", + "2026-04-29/rust-std-nightly-aarch64-unknown-linux-gnu.tar.xz": "80dceec313e144e3cfc5d67326826d85c664e762a27b53fea018a96d537a2942", + "2026-04-29/rust-std-nightly-aarch64-unknown-linux-musl.tar.xz": "9d5cb99d5678b2310bd69b2b654e9dcbbc3c5a50f9b66d03a21745cff4444927", + "2026-04-29/rust-std-nightly-x86_64-apple-darwin.tar.xz": "4992887472dfdea66a7f96c85b81104b543974204f91722742bbe5453bce8ec1", + "2026-04-29/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "890d91c1b86e482aaee32d793b366ee3889a9326143cd7f82a2b7507a4f4d592", + "2026-04-29/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "09774060c01c82005a2ae4e4b46a899c5e6157d6cc7188dfbb750c0a0f7c52cf", + "2026-04-29/rust-std-nightly-x86_64-unknown-linux-musl.tar.xz": "de5936933a2994ebff227b62fe41fca5707496d13da33563f2bfee3049e7b122", + "2026-04-29/rustc-nightly-aarch64-apple-darwin.tar.xz": "61fc2a3fd11637fbe9f961319aa16d84615d2a033de46909742000448290c687", + "2026-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "d8c9d9117a0499b6891e4622c55c7be9568e6b0cbed4f53540e51459ab514633", + "2026-04-29/rustc-nightly-x86_64-apple-darwin.tar.xz": "66efb8a2fb4155cd010bafda3382f643d87f337b646542f7830eda36cf1571a4", + "2026-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "b0db9dc4957c0f12ff8be0a30d22b411d4e2a7f434d747d767156be80d782f1d", + "2026-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "56dcf5ac72bcf663687273b0b9cdf953537081f38a4592d3577e9a6502707b4b", + "2026-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "b495726b0f311dcb53a8cf5325c61ef321f110a3739247536bc87109d428a3cc", + "2026-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9c64403758b4b631b60057f6ed4a93b02f19286a59a60f8ea235b4f7d4e1ba4c", + "2026-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "397e4ead440f29a1fc10903388a377f5607a1d404c29dc3e3a979d2bc813a801", + }, extra_target_triples = [ "x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", diff --git a/bazel/patches/hermetic_cc_toolchain-isolated-compile-cache.patch b/bazel/patches/hermetic_cc_toolchain-isolated-compile-cache.patch index 52ac68089..5b14de212 100644 --- a/bazel/patches/hermetic_cc_toolchain-isolated-compile-cache.patch +++ b/bazel/patches/hermetic_cc_toolchain-isolated-compile-cache.patch @@ -12,9 +12,18 @@ dir. Link steps keep the shared cache: they are the ones that benefit battle-tested path for concurrent artifact builds, and after first warm they are pure readers. +Also opt @zig_config into Bazel's repo contents cache (repo_metadata, +bazel >= 8.3): the fetch is deterministic given the pinned zig archive and +wrapper source, and re-running it cost ~20 s of wrapper compilation on every +fresh output base — every job on ephemeral CI pods. + +Note: bazel's own patch parser (unlike GNU patch) requires the `diff --git` +separator line before each file section of a multi-file patch. + +diff --git a/toolchain/zig-wrapper.zig b/toolchain/zig-wrapper.zig --- a/toolchain/zig-wrapper.zig +++ b/toolchain/zig-wrapper.zig -@@ -252,6 +252,32 @@ fn parseArgs( +@@ -267,6 +267,32 @@ if (run_mode == RunMode.cc) try resolveColonLibraries(arena, cwd, &args); @@ -47,3 +56,19 @@ are pure readers. // Add -target as the last parameter. The wrapper should overwrite // the target specified by other tools calling the wrapper. // Some tools might pass LLVM target triple, which are rejected by zig. +diff --git a/toolchain/defs.bzl b/toolchain/defs.bzl +--- a/toolchain/defs.bzl ++++ b/toolchain/defs.bzl +@@ -278,6 +278,12 @@ + ) + repository_ctx.symlink("tools/zig-wrapper{}".format(exe), tool_path) + ++ # omp: opt into the repo contents cache — the fetch is deterministic ++ # given the pinned zig archive and the wrapper source above. ++ if hasattr(repository_ctx, "repo_metadata"): ++ return repository_ctx.repo_metadata(reproducible = True) ++ return None ++ + zig_repository = repository_rule( + attrs = { + "version": attr.string(), diff --git a/bazel/toolchains/msvc/llvm.bzl b/bazel/toolchains/msvc/llvm.bzl index 35172658c..1a2f9a43e 100644 --- a/bazel/toolchains/msvc/llvm.bzl +++ b/bazel/toolchains/msvc/llvm.bzl @@ -120,6 +120,12 @@ def _llvm_msvc_tools_impl(rctx): rctx.file("BUILD.bazel", _BUILD.format(version = _LLVM_VERSION, host = key), executable = False) + # Opt into the repo contents cache: the fetch is a pure function of the + # pinned URL+sha256 and the deterministic prune above, and the ~172 s + # extraction of the 2 GiB archive was the single largest cost of every + # fresh output base on ephemeral CI pods (profiled: run 30510579596). + return rctx.repo_metadata(reproducible = True) + llvm_msvc_tools_repository = repository_rule( implementation = _llvm_msvc_tools_impl, doc = "Pruned LLVM release binaries (clang-cl/lld-link/llvm-lib/llvm-rc) for the exec host.", diff --git a/bazel/toolchains/msvc/sysroot.bzl b/bazel/toolchains/msvc/sysroot.bzl index 0a6fa8503..486ef1c39 100644 --- a/bazel/toolchains/msvc/sysroot.bzl +++ b/bazel/toolchains/msvc/sysroot.bzl @@ -161,6 +161,14 @@ def _xwin_sysroot_impl(rctx): executable = False, ) + # Opt into the repo contents cache. The splat is channel-stable, not + # bit-reproducible forever (see the module docstring) — caching freezes a + # known-good splat, which also keeps remote action keys stable across + # pods until this file changes or the cache entry ages out (14 d GC). + # OMP_XWIN_CACHE_DIR is a predeclared input (environ attr), so kata and + # dev fetches key separate entries. + return rctx.repo_metadata(reproducible = True) + xwin_sysroot_repository = repository_rule( implementation = _xwin_sysroot_impl, doc = "MSVC CRT + Windows SDK sysroot splatted by a pinned xwin release.",