fix(build): wx 'zlib.h not found' CI flake — self-heal zlib port + deterministic cache touch

Two fixes for the intermittent wx-build failure on CI (zipstrm.cpp: fatal
error: 'zlib.h' file not found, surviving the serial retry):

- build-wx-wasm.sh: --with-zlib=sys resolves to the Emscripten zlib PORT,
  which only `embuilder build zlib` installs — and that ran only in the
  configure branch. A pre-configured build dir (CI cache) + fresh emsdk
  therefore died on any recompile of a zlib-using TU. Ensure the port
  before every make; --force because embuilder stamps the port on libz.a
  alone, so a half-populated cache would no-op.

- wasm-build.yml: the cache-restore `touch {} +` stamped files ns-apart in
  readdir order; GNU make 4.x compares ns mtimes, so objects touched before
  a generated header they depend on (wx/setup.h, pcre2.h via .deps/*.d)
  recompiled — a random subset per run, which is what made the failure
  flaky. Use one shared timestamp instead: equal mtimes = up to date.

Reproduced + validated locally (remove sysroot zlib.h + one .o → exact CI
failure; with fix, self-heals in 0.5s; Linux make ns/equal-mtime behavior
verified in a container).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeiSRRScdaox5jBueJNcyG
This commit is contained in:
Viktor Vaczi 2026-07-02 09:59:32 +02:00
commit f49d536f95
2 changed files with 22 additions and 1 deletions

View file

@ -263,9 +263,14 @@ jobs:
path: build-wasm/wxwidgets path: build-wasm/wxwidgets
key: wx-${{ runner.os }}-${{ steps.keys.outputs.wx }}-${{ hashFiles('scripts/build-wx-wasm.sh','scripts/common/versions.sh') }} key: wx-${{ runner.os }}-${{ steps.keys.outputs.wx }}-${{ hashFiles('scripts/build-wx-wasm.sh','scripts/common/versions.sh') }}
# One shared timestamp, not per-file "now": plain `touch {} +` stamps each file
# a few ns apart in readdir order, and GNU make 4.x compares ns mtimes — so any
# object touched before a generated header it depends on (wx/setup.h, pcre2.h
# via .deps/*.d) looks stale and a random subset recompiles every cache-hit run.
# Equal mtimes read as up to date.
- name: Mark restored wx objects current - name: Mark restored wx objects current
if: inputs.run_tests && steps.wx-cache.outputs.cache-hit == 'true' if: inputs.run_tests && steps.wx-cache.outputs.cache-hit == 'true'
run: find build-wasm/wxwidgets -exec touch {} + run: find build-wasm/wxwidgets -exec touch -d "@$(date +%s)" {} +
- name: Build wxWidgets (wxUniversal WASM) - name: Build wxWidgets (wxUniversal WASM)
if: inputs.run_tests if: inputs.run_tests

View file

@ -190,6 +190,22 @@ if [ $NEEDS_CONFIGURE -eq 1 ]; then
emmake make -C 3rdparty/pcre emmake make -C 3rdparty/pcre
fi fi
# Ensure the Emscripten zlib port exists before compiling. We configure with
# --with-zlib=sys, which resolves zlib.h/libz.a to the emsdk cache sysroot —
# populated only by `embuilder build zlib` in the configure branch above. When
# the build dir arrives pre-configured (e.g. CI restores build-wasm/wxwidgets
# from cache onto a runner with a freshly installed emsdk), configure is
# skipped and any recompile of a zlib-using TU (zipstrm.cpp, zstream.cpp, ...)
# fails with "'zlib.h' file not found" — deterministically, so the serial
# retry below can't clear it.
EM_CACHE_SYSROOT="$(em-config CACHE)/sysroot"
if [ ! -f "$EM_CACHE_SYSROOT/include/zlib.h" ]; then
echo "Emscripten zlib port missing from $EM_CACHE_SYSROOT; building it..."
# --force: embuilder stamps the port as built on libz.a alone, so a
# half-populated cache (lib present, headers gone) would no-op without it.
embuilder build zlib --force
fi
# Build wxWidgets # Build wxWidgets
kw_stage wxwidgets-compile kw_stage wxwidgets-compile
echo "" echo ""