diff --git a/.audit/oberstet_fix_1875.md b/.audit/oberstet_fix_1875.md new file mode 100644 index 000000000..a5248ed64 --- /dev/null +++ b/.audit/oberstet_fix_1875.md @@ -0,0 +1,8 @@ +- [ ] I did **not** use any AI-assistance tools to help create this pull request. +- [x] I **did** use AI-assistance tools to *help* create this pull request. +- [x] I have read, understood and followed the projects' [AI Policy](https://github.com/crossbario/autobahn-python/blob/main/AI_POLICY.md) when creating code, documentation etc. for this pull request. + +Submitted by: @oberstet +Date: 2026-07-01 +Related issue(s): #1875 +Branch: oberstet:fix_1875 diff --git a/.cicd b/.cicd index f77ca2b6a..f9a9a7e2e 160000 --- a/.cicd +++ b/.cicd @@ -1 +1 @@ -Subproject commit f77ca2b6a3ac1399bcd24c3ccc674cc68e85273f +Subproject commit f9a9a7e2eb85aa176dd4cf233955deabdd39a2cc diff --git a/docs/changelog.rst b/docs/changelog.rst index ef11b2707..1b4aa6bc1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,6 +17,8 @@ Changelog * Add CalVer / PEP 440 version-management ``just`` recipes (``file-version``, ``bump-dev``, ``bump-next``, ``prep-release``) mirroring Crossbar.io, and document the versioning policy in ``CONTRIBUTING.md`` (#1894) * Add ``ruff check --select ANN,UP,TCH`` (annotation presence, ``pyupgrade`` modern syntax, ``TYPE_CHECKING`` imports) to the ``just check-typing`` recipe so annotation/style regressions are caught in the ``quality-checks`` CI job. The existing gaps in ``src/autobahn/`` are ratcheted via an explicit ``--ignore`` allowlist to be removed module-by-module (#1839); all other ``UP``/``TC`` rules are enforced immediately, and generated code is excluded. The annotation rules are scoped to this recipe via the command line rather than the global ``[tool.ruff.lint]`` select, so the repo-wide ``check-format`` gate is unaffected (#1840) +* Fix the aarch64 CPython 3.14 wheel shipping the free-threaded ABI (``cp314t``) in the GIL ``cp314`` slot (26.6.x). Root cause: manylinux images pre-install both the GIL and free-threaded 3.14 under ``/opt/python`` and prepend them to ``PATH``, and ``uv`` resolved ``cpython-3.14`` to the free-threaded interpreter (first on ``PATH``). The ``create`` recipe now drops free-threaded ``…t/bin`` dirs from ``PATH`` for GIL envs so ``uv`` selects the GIL build. As defence-in-depth, ``just build`` also asserts (via ``_check-venv-abi``) that the interpreter's GIL/free-threaded status matches the env and aborts on mismatch, so a wrong-ABI wheel can never be published. A reserved ``cpy314t`` env spec (``cpython-3.14t``) is added for a future free-threaded wheel variant (#1875) +* Bump the ``.cicd`` (wamp-cicd) submodule to include exact CPython ABI-tag matching in the shared ``check-release-fileset`` release-gate action, so a wrong-ABI wheel (e.g. ``cp314t`` in the ``cp314`` slot) is also rejected at release-fileset validation, not only by the build-time guard above (wamp-cicd #11, completes #1875) 26.6.2 ------ diff --git a/justfile b/justfile index c47dd0bc9..110e01090 100644 --- a/justfile +++ b/justfile @@ -81,6 +81,7 @@ _get-spec short_name: set -e case {{short_name}} in cpy314) echo "cpython-3.14";; # cpython-3.14.0b3-linux-x86_64-gnu + cpy314t) echo "cpython-3.14t";; # CPython 3.14 free-threaded (no-GIL); reserved for #1875 Part 2 cpy313) echo "cpython-3.13";; # cpython-3.13.5-linux-x86_64-gnu cpy312) echo "cpython-3.12";; # cpython-3.12.11-linux-x86_64-gnu cpy311) echo "cpython-3.11";; # cpython-3.11.13-linux-x86_64-gnu @@ -88,6 +89,29 @@ _get-spec short_name: *) echo "Unknown environment: {{short_name}}" >&2; exit 1;; esac +# Assert the venv interpreter's ABI (GIL vs free-threaded) matches the env name, so a wheel +# is never published with the wrong ABI tag -- e.g. a free-threaded cp314t wheel in the GIL +# cp314 slot, which shipped on aarch64 in 26.6.1 when an older uv resolved `cpython-3.14` to +# the free-threaded interpreter (autobahn #1875 / zlmdb #124). The wheel ABI tag is fixed by +# the building interpreter, so checking the interpreter catches the mismatch at build time. +_check-venv-abi venv: + #!/usr/bin/env bash + set -e + VENV_NAME="{{ venv }}" + VENV_PYTHON=$(just --quiet _get-venv-python "${VENV_NAME}") + case "${VENV_NAME}" in + pypy*) echo "==> ABI check skipped for '${VENV_NAME}' (PyPy)"; exit 0 ;; + *t) EXPECT_FT=1 ;; # e.g. cpy314t -> free-threaded (no-GIL) + *) EXPECT_FT=0 ;; # e.g. cpy314 -> GIL + esac + ACTUAL_FT=$(${VENV_PYTHON} -c "import sysconfig; print(1 if sysconfig.get_config_var('Py_GIL_DISABLED') else 0)") + if [ "${ACTUAL_FT}" != "${EXPECT_FT}" ]; then + echo "ERROR: interpreter ABI mismatch for '${VENV_NAME}': Py_GIL_DISABLED=${ACTUAL_FT}, expected free-threaded=${EXPECT_FT}." >&2 + echo " Building would emit a wrong-ABI wheel (e.g. cp314t in the cp314 slot). Aborting." >&2 + exit 1 + fi + echo "==> ABI check OK: '${VENV_NAME}' interpreter free-threaded=${ACTUAL_FT} (expected ${EXPECT_FT})" + # uv python install pypy-3.11-linux-aarch64-gnu --preview --verbose # file /home/oberstet/.local/share/uv/python/pypy-3.11.11-linux-aarch64-gnu/bin/pypy3.11 # /home/oberstet/.local/share/uv/python/pypy-3.11.11-linux-aarch64-gnu/bin/pypy3.11: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=150f642a07dc36d3e465beaa0109e70da76ca67e, for GNU/Linux 3.7.0, stripped @@ -256,9 +280,18 @@ create venv="": # Get the Python spec just-in-time PYTHON_SPEC=$(just --quiet _get-spec "${VENV_NAME}") + # For a GIL env, drop free-threaded CPython dirs (…t/bin, e.g. cp314t) that + # manylinux images pre-install on PATH ahead of the GIL build, so uv does not + # resolve e.g. cpy314 to a free-threaded cp314t interpreter (#1875). The dedicated + # cpy314t env is used to build free-threaded wheels. No-op off manylinux. + CREATE_PATH="${PATH}" + if [[ "${VENV_NAME}" != *t ]]; then + CREATE_PATH="$(printf '%s' "${PATH}" | tr ':' '\n' | grep -vE '/opt/python/[^/]*t/bin$' | paste -sd: -)" + fi + echo "==> Creating Python virtual environment '${VENV_NAME}' using ${PYTHON_SPEC} in ${VENV_PATH}..." mkdir -p "{{ VENV_DIR }}" - uv venv --seed --python "${PYTHON_SPEC}" "${VENV_PATH}" + PATH="${CREATE_PATH}" uv venv --seed --python "${PYTHON_SPEC}" "${VENV_PATH}" echo "==> Successfully created venv '${VENV_NAME}'." else echo "==> Python virtual environment '${VENV_NAME}' already exists in ${VENV_PATH}." @@ -1673,6 +1706,11 @@ build venv="": (install-build-tools venv) fi VENV_PATH="{{ VENV_DIR }}/${VENV_NAME}" VENV_PYTHON=$(just --quiet _get-venv-python "${VENV_NAME}") + + # Fail fast if the interpreter ABI doesn't match the env (autobahn #1875 / zlmdb #124): + # prevents publishing e.g. a free-threaded cp314t wheel in the GIL cp314 slot. + just _check-venv-abi "${VENV_NAME}" + echo "==> Building wheel package..." # Build the wheel with NVX acceleration