diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f1b8eb9f3a2..d24a7293669 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -8,6 +8,12 @@ on: schedule: - cron: '0 0 * * *' # This runs the workflow every day at 12:00 AM UTC workflow_dispatch: {} + # TEMPORARY (do not merge): runs this workflow against a PR through the + # copy-pr-bot mirror branch, so the wheel repair below can be verified + # before it is proposed on its own. Same trigger as ci.yml. + push: + branches: + - "pull-request/[0-9]+" env: PY_VER: "3.14" @@ -32,6 +38,9 @@ jobs: coverage-linux: name: Coverage (Linux) needs: [coverage-vars] + # TEMPORARY (do not merge): only Windows is under test here, and the Linux + # leg holds an A100 for half an hour. + if: ${{ !startsWith(github.ref, 'refs/heads/pull-request/') }} runs-on: "linux-amd64-gpu-a100-latest-1" permissions: id-token: write @@ -235,13 +244,64 @@ jobs: cd cuda_bindings ../.venv/Scripts/pip wheel -v --no-deps . -w ../wheels/ + # PIP_PRE is set so pip will consider the cuda-bindings wheel built one + # step ago: it carries a .devN version, which counts as a pre-release. + # The side effect is that PyPI's pre-releases become eligible too, and + # since cuda-bindings 13.4.0b1 was published on 2026-07-29 it outranks + # the local build for `cuda-bindings==13.*`. Its cydriver.pxd is + # generated from CTK 13.4 headers, where CUmemLocation has a `localized` + # field, while cuda.core here compiles against the 13.3.0 mini-CTK, where + # it does not -- and Cython generates a struct converter over every + # field, so the build fails on `error C2039`. Constraining the version + # keeps what PIP_PRE is for and drops what it lets in. + # + # The local segment is stripped because PEP 440 has a public `==` + # specifier ignore a candidate's local label: `==13.3.2.dev152` still + # selects 13.3.2.dev152+g0123456, and constraints files stay free of + # local versions. - name: Build cuda.core wheel run: | export PIP_FIND_LINKS="$(pwd)/wheels" export PIP_PRE=1 + bindings_whl="$(ls ./wheels/cuda_bindings-*.whl | head -1)" + bindings_ver="$(basename "$bindings_whl" | cut -d- -f2)" + echo "cuda-bindings==${bindings_ver%%+*}" > "$GITHUB_WORKSPACE/constraints.txt" + cat "$GITHUB_WORKSPACE/constraints.txt" + export PIP_CONSTRAINT="$GITHUB_WORKSPACE/constraints.txt" cd cuda_core ../.venv/Scripts/pip wheel -v --no-deps . -w ../wheels/ + # Every other Windows build repairs its wheels and this one never did. + # cibuildwheel runs each package's repair-wheel-command from + # pyproject.toml, which on Windows is delvewheel: it copies dependent + # DLLs into .libs under content-hashed names, rewrites the .pyd + # import tables to match, and registers the directory from the package + # __init__. A plain `pip wheel` never reads [tool.cibuildwheel], so + # these wheels imported a bare "MSVCP140.dll" and resolved it against + # whatever the test machine had in System32 -- 14.00.24215.1, from 2015, + # on the runner this job uses. + # + # That is fatal rather than cosmetic. _resource_handles.pyd, compiled by + # MSVC 14.44, imports only _Mtx_lock and _Mtx_unlock and never + # _Mtx_init_in_situ, because std::mutex has had a constexpr constructor + # since VS 2022 17.10. The 2015 runtime still expects that + # initialisation and dereferences a null handle on the first lock, which + # _stream.pyx takes while cuda.core is still importing: every Windows + # coverage run since 2026-03-17 died there, before collecting a test. + # + # --namespace-pkg cuda is required; `cuda` is a namespace package and + # delvewheel otherwise patches the wrong __init__. + - name: Repair the Windows wheels + run: | + .venv/Scripts/pip install delvewheel + mkdir -p wheels-repaired + for whl in ./wheels/cuda_bindings-*.whl ./wheels/cuda_core-*.whl; do + .venv/Scripts/delvewheel repair --namespace-pkg cuda \ + --exclude "torch_cpu.dll;torch_python.dll" \ + -w ./wheels-repaired "$whl" + done + mv -f ./wheels-repaired/*.whl ./wheels/ + - name: List wheel artifacts run: | echo "=== Windows wheel artifacts ===" @@ -393,7 +453,10 @@ jobs: name: Combine Coverage and Deploy needs: [coverage-linux, coverage-windows] runs-on: ubuntu-latest - if: always() + # TEMPORARY (do not merge): a PR run has no Linux half, so this would both + # fail on the missing .coverage.linux and publish a partial report to + # gh-pages. + if: ${{ always() && !startsWith(github.ref, 'refs/heads/pull-request/') }} permissions: id-token: write contents: write