2121# while macOS installs it via brew in the workflow. Best-effort and inert-safe: any failure
2222# leaves sccache absent, so the build just proceeds uncached. The static musl binary runs in
2323# any x86_64 Linux container (the cross-compile host is always x86_64).
24+ #
25+ # SCCACHE_DL_VERSION is overridable per-job, so a container that crashes one sccache build can
26+ # try another without editing this script (the in-container panic that stalled phase 2 was on
27+ # v0.8.2; v0.16.0 is the latest release and the default). A wrong/unavailable version just fails
28+ # the `curl -f` and falls back to an uncached build, so bumping it can never red a build.
29+ SCCACHE_DL_VERSION=" ${SCCACHE_DL_VERSION:- 0.16.0} "
2430if [ " ${USE_CACHE:- true} " = " true" ] && [ -n " ${SCCACHE_WEBDAV_TOKEN:- }${SCCACHE_GHA_ENABLED:- } " ] \
2531 && ! command -v sccache > /dev/null 2>&1 \
2632 && [ " $( uname -s) " = " Linux" ] && [ " $( uname -m) " = " x86_64" ]; then
27- SCCACHE_REL=" sccache-v0.8.2 -x86_64-unknown-linux-musl"
33+ SCCACHE_REL=" sccache-v ${SCCACHE_DL_VERSION} -x86_64-unknown-linux-musl"
2834 echo " build.sh: fetching ${SCCACHE_REL} (no sccache on PATH)..."
2935 if curl -fsSL --proto =https --proto-redir =https \
30- " https://github.com/mozilla/sccache/releases/download/v0.8.2 /${SCCACHE_REL} .tar.gz" \
36+ " https://github.com/mozilla/sccache/releases/download/v ${SCCACHE_DL_VERSION} /${SCCACHE_REL} .tar.gz" \
3137 -o /tmp/sccache.tgz && tar -xzf /tmp/sccache.tgz -C /tmp; then
3238 export PATH=" /tmp/${SCCACHE_REL} :$PATH "
3339 echo " build.sh: sccache -> $( command -v sccache || echo ' still missing' ) "
@@ -36,14 +42,55 @@ if [ "${USE_CACHE:-true}" = "true" ] && [ -n "${SCCACHE_WEBDAV_TOKEN:-}${SCCACHE
3642 fi
3743fi
3844
45+ # Health-check before trusting sccache as the compiler launcher. Because sccache *is* the
46+ # launcher (cmake runs `sccache <compiler> ...` for every TU), a present-but-crashing sccache
47+ # fails every compile and reds the whole build — exactly the in-container panic that stalled
48+ # phase 2 (the static-musl binary panicked while wrapping the cross-compiler, failing ggml.c.o).
49+ # The probe runs the real compiler through sccache on a trivial TU; only if that succeeds is the
50+ # launcher enabled. On any failure it logs the captured output (the Rust panic backtrace, plus
51+ # the detached server's SCCACHE_ERROR_LOG when a job sets one) and the build runs WITHOUT the
52+ # cache — a clean, uncached -O3 build that still goes green. This closes the gap the old
53+ # absent-only guard left: it handled sccache *missing*, not sccache *crashing*.
54+ sccache_can_wrap_compiler () {
55+ probe_cc=" ${CC:- } "
56+ if [ -z " $probe_cc " ]; then
57+ for c in cc gcc clang; do
58+ if command -v " $c " > /dev/null 2>&1 ; then probe_cc=" $c " ; break ; fi
59+ done
60+ fi
61+ if [ -z " $probe_cc " ]; then
62+ echo " build.sh: sccache probe: no C compiler on PATH to probe; building uncached"
63+ return 1
64+ fi
65+ probe_dir=" $( mktemp -d 2> /dev/null || echo " /tmp/sccache-probe.$$ " ) "
66+ mkdir -p " $probe_dir " || return 1
67+ printf ' int main(void){return 0;}\n' > " $probe_dir /probe.c"
68+ probe_out=" $( sccache " $probe_cc " -c " $probe_dir /probe.c" -o " $probe_dir /probe.o" 2>&1 ) "
69+ probe_rc=$?
70+ rm -rf " $probe_dir "
71+ if [ " $probe_rc " -ne 0 ]; then
72+ echo " build.sh: sccache probe FAILED (rc=${probe_rc} ) wrapping '${probe_cc} ' — building WITHOUT cache."
73+ [ -n " $probe_out " ] && printf ' %s\n' " $probe_out " | sed ' s/^/build.sh: sccache-probe| /'
74+ if [ -n " ${SCCACHE_ERROR_LOG:- } " ] && [ -f " ${SCCACHE_ERROR_LOG} " ]; then
75+ echo " build.sh: --- detached server log (${SCCACHE_ERROR_LOG} ) ---"
76+ sed ' s/^/build.sh: sccache-srv| /' " ${SCCACHE_ERROR_LOG} " 2> /dev/null || true
77+ fi
78+ return 1
79+ fi
80+ echo " build.sh: sccache probe OK (wrapped '${probe_cc} ')"
81+ return 0
82+ }
83+
3984# Optional shared compiler cache: sccache fronting Depot Cache (WebDAV). Enabled only when
40- # USE_CACHE is true AND sccache + a cache token are present, so it stays inert before the
41- # DEPOT_TOKEN secret is configured and on fork PRs (secrets hidden) — those just compile
42- # normally. sccache is content-addressed, so a cache hit is bit-identical to a fresh -O3
43- # compile (release-safe), and it degrades to direct compilation if the cache is unreachable.
85+ # USE_CACHE is true AND sccache + a cache token are present AND the probe confirms sccache can
86+ # wrap the compiler — so it stays inert before the DEPOT_TOKEN secret is configured, on fork PRs
87+ # (secrets hidden), and when sccache would crash; all of those just compile normally. sccache is
88+ # content-addressed, so a cache hit is bit-identical to a fresh -O3 compile (release-safe), and
89+ # it degrades to direct compilation if the cache is unreachable.
4490LAUNCH=" "
4591if [ " ${USE_CACHE:- true} " = " true" ] && command -v sccache > /dev/null 2>&1 \
46- && [ -n " ${SCCACHE_WEBDAV_TOKEN:- }${SCCACHE_GHA_ENABLED:- } " ]; then
92+ && [ -n " ${SCCACHE_WEBDAV_TOKEN:- }${SCCACHE_GHA_ENABLED:- } " ] \
93+ && sccache_can_wrap_compiler; then
4794 LAUNCH=" -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache"
4895 echo " build.sh: sccache ON (endpoint=${SCCACHE_WEBDAV_ENDPOINT:- default} ), building with -j${JOBS} "
4996else
53100cmake -Bbuild $LAUNCH $@ || exit 1
54101cmake --build build --config Release -j" ${JOBS} " || exit 1
55102
56- if command -v sccache > /dev/null 2>&1 ; then
103+ # Only query stats when sccache was actually used as the launcher; if the probe rejected a
104+ # crashing sccache, re-invoking it here would just repeat the crash output (harmless but noisy).
105+ if [ -n " $LAUNCH " ] && command -v sccache > /dev/null 2>&1 ; then
57106 sccache --show-stats || true
58107fi
0 commit comments