diff --git a/.github/workflows/release_pypi.yml b/.github/workflows/release_pypi.yml index fdcb8749b..919269ab6 100644 --- a/.github/workflows/release_pypi.yml +++ b/.github/workflows/release_pypi.yml @@ -69,6 +69,13 @@ jobs: # below; the in-container CCACHE_DIR is set in the Build Wheels # step's env: block (and forwarded via environment-pass). echo "HOST_CCACHE_DIR=${HOME}/.ccache" >> "$GITHUB_ENV" + # Reset the "first wheel build" marker once per run (after the cache is + # restored, before cibuildwheel). tools/validate_ccache_stats.py allows + # zero cache hits only for the first python-version build of a run; this + # ensures a marker carried over inside the cached CCACHE_DIR can't mask a + # genuine cache-miss failure on later runs. + mkdir -p "${HOME}/.ccache" + rm -f "${HOME}/.ccache/.cytnx_first_wheel_build_done" - name: Build Wheels uses: pypa/cibuildwheel@v3.3.0 diff --git a/tools/validate_ccache_stats.py b/tools/validate_ccache_stats.py index 68a951577..84bc30a0c 100644 --- a/tools/validate_ccache_stats.py +++ b/tools/validate_ccache_stats.py @@ -82,5 +82,24 @@ def to_num(v: str) -> float: # Reset counters so the next Python-version build observes fresh, per-build stats. subprocess.check_call(['ccache', '--zero-stats']) +# cibuildwheel runs this script once per Python-version build. The very first +# build of a run compiles the C++ sources from a cold cache, so zero hits is +# expected; later versions reuse those object files and must hit the cache. +# A marker file inside CCACHE_DIR (shared across the per-version build +# containers via the bind mount) lets us tell the first build apart. The CI +# workflow removes this marker once per run before invoking cibuildwheel, so a +# marker carried over inside the cached CCACHE_DIR never masks a real failure. +ccache_dir = os.getenv('CCACHE_DIR') +first_build_marker = pathlib.Path(ccache_dir) / '.cytnx_first_wheel_build_done' if ccache_dir else None +is_first_build = first_build_marker is not None and not first_build_marker.exists() +if first_build_marker is not None: + first_build_marker.parent.mkdir(parents=True, exist_ok=True) + first_build_marker.touch() + if total <= 0: - raise SystemExit('No ccache hits detected for this python-version build.') + if is_first_build: + print('ccache_first_build_no_hits_ok') + print('No ccache hits detected, but this is the first python-version build ' + 'of the cibuildwheel run (cold cache); skipping hit enforcement.') + else: + raise SystemExit('No ccache hits detected for this python-version build.')