Skip to content

Commit dcb2c59

Browse files
committed
ci: repair the coverage wheels the way every other build does
This build is the only one that ships .pyd files importing a bare "MSVCP140.dll". cibuildwheel runs each package's repair-wheel-command after building, which on Windows is delvewheel; a plain `pip wheel` never reads [tool.cibuildwheel], so nothing here was ever repaired. The import table is then resolved against whatever the test machine has in System32, and on that runner it is 14.00.24215.1, built in 2015. _resource_handles.pyd, compiled by MSVC 14.44, imports exactly _Mtx_lock and _Mtx_unlock from that DLL 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:422 takes while cuda.core is still importing. It is the only module in either package that locks a mutex at all, which is why bindings and pathfinder have always passed on the same machine. Vendoring the build machine's 14.51 makes the wheels independent of what the test machine carries -- the same thing the wheels on PyPI already do, where the vendored copy has the identical content hash. --namespace-pkg cuda is not optional: `cuda` is a namespace package, and delvewheel otherwise patches the wrong __init__ and the DLL directory is never registered.
1 parent cc9fce1 commit dcb2c59

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

.github/workflows/coverage.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,48 @@ jobs:
304304
cd cuda_core
305305
../.venv/Scripts/pip wheel -v --no-deps . -w ../wheels/
306306
307+
# The step every other Windows build does and this one never did.
308+
#
309+
# cibuildwheel runs `repair-wheel-command` out of each package's
310+
# pyproject.toml after building, which on Windows is delvewheel: it
311+
# copies the dependent DLLs into <package>.libs under content-hashed
312+
# names, rewrites the .pyd import tables to reference those names, and
313+
# adds an os.add_dll_directory call to the package __init__. A plain
314+
# `pip wheel` knows nothing about [tool.cibuildwheel], so this build has
315+
# always shipped .pyd files that import a bare "MSVCP140.dll" and
316+
# resolve it to whatever the test machine happens to have in System32 --
317+
# which on that runner is 14.00.24215.1, from 2015.
318+
#
319+
# _resource_handles.pyd, compiled by MSVC 14.44, takes only _Mtx_lock
320+
# and _Mtx_unlock from that DLL and never _Mtx_init_in_situ, because
321+
# std::mutex has had a constexpr constructor since VS 2022 17.10. The
322+
# 2015 runtime still expects that initialisation to have happened and
323+
# dereferences a null handle on the first lock, which _stream.pyx:422
324+
# takes during import.
325+
#
326+
# Vendoring 14.51 from this build machine removes the dependency on what
327+
# the test machine has. --namespace-pkg cuda is required: `cuda` is a
328+
# namespace package, and without it the add_dll_directory patch lands in
329+
# the wrong __init__.
330+
- name: Vendor the C++ runtime into the wheels
331+
run: |
332+
.venv/Scripts/pip install delvewheel
333+
mkdir -p wheels-repaired
334+
for whl in ./wheels/cuda_bindings-*.whl ./wheels/cuda_core-*.whl; do
335+
echo "=== repairing $whl ==="
336+
.venv/Scripts/delvewheel repair --namespace-pkg cuda \
337+
--exclude "torch_cpu.dll;torch_python.dll" \
338+
-w ./wheels-repaired "$whl"
339+
done
340+
# Replace the originals in place: everything downstream, including
341+
# the artifact the test job installs from, reads ./wheels.
342+
mv -f ./wheels-repaired/*.whl ./wheels/
343+
echo "=== what got vendored ==="
344+
for whl in ./wheels/cuda_bindings-*.whl ./wheels/cuda_core-*.whl; do
345+
echo "--- $whl"
346+
unzip -l "$whl" | grep -i "\.libs/" || echo " (nothing vendored)"
347+
done
348+
307349
- name: List wheel artifacts
308350
run: |
309351
echo "=== Windows wheel artifacts ==="

0 commit comments

Comments
 (0)