fix(build): isolated zig compile caches to stop concurrent corruption
zig 0.14's cache corrupts under concurrent `zig cc` (ziglang/zig#18763): with ~60 cc-compiling cargo build scripts running in parallel, cache manifests end up referencing evicted objects ("failed to open .../scanner.o: FileNotFound") and kill the build. Patch the hermetic wrapper via single_version_override so compile-only steps (-c/-E/-S) get private throwaway caches under the system tmp dir — cold vs warm is ~25ms for compiles, measured — while links keep the shared cache for compiler-rt/crt reuse (~6s cold, 25ms warm) under zig's per-artifact locking.
This commit is contained in:
@@ -23,6 +23,15 @@ bazel_dep(name = "platforms", version = "1.1.0")
|
|||||||
bazel_dep(name = "rules_rust", version = "0.71.3")
|
bazel_dep(name = "rules_rust", version = "0.71.3")
|
||||||
bazel_dep(name = "hermetic_cc_toolchain", version = "4.2.0")
|
bazel_dep(name = "hermetic_cc_toolchain", version = "4.2.0")
|
||||||
|
|
||||||
|
# zig 0.14's cache corrupts under concurrent `zig cc` (ziglang/zig#18763);
|
||||||
|
# the patch gives compile-only steps private throwaway caches while links
|
||||||
|
# keep the shared cache. See the patch header for measurements.
|
||||||
|
single_version_override(
|
||||||
|
module_name = "hermetic_cc_toolchain",
|
||||||
|
patch_strip = 1,
|
||||||
|
patches = ["//bazel/patches:hermetic_cc_toolchain-isolated-compile-cache.patch"],
|
||||||
|
)
|
||||||
|
|
||||||
# --- Rust toolchains ----------------------------------------------------------
|
# --- Rust toolchains ----------------------------------------------------------
|
||||||
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
|
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
|
||||||
rust.toolchain(
|
rust.toolchain(
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Module override patches (see MODULE.bazel single_version_override entries).
|
||||||
|
exports_files(glob(["*.patch"]))
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
Isolate zig's cache for compile-only invocations (ziglang/zig#18763).
|
||||||
|
|
||||||
|
Concurrent `zig cc` processes sharing one cache dir corrupt it under load
|
||||||
|
(cache manifests referencing evicted objects: "failed to open .../scanner.o:
|
||||||
|
FileNotFound"). This repo drives ~60 cc-compiling cargo build scripts in
|
||||||
|
parallel through the wrapper, which reproduces the corruption reliably on CI.
|
||||||
|
|
||||||
|
Compile/preprocess steps gain nothing from the cache (~25ms cold vs warm,
|
||||||
|
measured) — give each process a private throwaway cache under the system tmp
|
||||||
|
dir. Link steps keep the shared cache: they are the ones that benefit
|
||||||
|
(compiler-rt/crt, ~6s cold vs 25ms warm), zig's per-artifact locking is the
|
||||||
|
battle-tested path for concurrent artifact builds, and after first warm they
|
||||||
|
are pure readers.
|
||||||
|
|
||||||
|
--- a/toolchain/zig-wrapper.zig
|
||||||
|
+++ b/toolchain/zig-wrapper.zig
|
||||||
|
@@ -252,6 +252,32 @@ fn parseArgs(
|
||||||
|
if (run_mode == RunMode.cc)
|
||||||
|
try resolveColonLibraries(arena, cwd, &args);
|
||||||
|
|
||||||
|
+ // Compile-only steps (-c/-E/-S) get a private throwaway cache: concurrent
|
||||||
|
+ // zig processes sharing one cache corrupt it (ziglang/zig#18763), and the
|
||||||
|
+ // cache is worthless for plain compiles. Links keep the shared cache for
|
||||||
|
+ // compiler-rt/crt reuse; zig's per-artifact locking covers those.
|
||||||
|
+ if (run_mode == RunMode.cc) {
|
||||||
|
+ var compile_only = false;
|
||||||
|
+ for (args.items) |a| {
|
||||||
|
+ if (mem.eql(u8, a, "-c") or mem.eql(u8, a, "-E") or mem.eql(u8, a, "-S")) {
|
||||||
|
+ compile_only = true;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (compile_only and builtin.os.tag != .windows) {
|
||||||
|
+ const tmp_root = env.get("TMPDIR") orelse "/tmp";
|
||||||
|
+ var rnd: [8]u8 = undefined;
|
||||||
|
+ std.crypto.random.bytes(&rnd);
|
||||||
|
+ const iso = try std.fmt.allocPrint(
|
||||||
|
+ arena,
|
||||||
|
+ "{s}{s}zig-pp-{}",
|
||||||
|
+ .{ tmp_root, sep, std.fmt.fmtSliceHexLower(&rnd) },
|
||||||
|
+ );
|
||||||
|
+ try env.put("ZIG_LOCAL_CACHE_DIR", iso);
|
||||||
|
+ try env.put("ZIG_GLOBAL_CACHE_DIR", iso);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// 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.
|
||||||
Reference in New Issue
Block a user