Skip to content

[FEATURE] Publish CPython 3.14 wheels for both free-threaded (no-GIL) and regular (GIL) builds on all platforms #1875

Description

@oberstet

Summary

The release wheel matrix should publish CPython 3.14 native (NVX) binary wheels
for both ABI variants — regular/GIL (cp314) and free-threaded/no-GIL
(cp314t, PEP 703) — across all four supported platforms (macOS arm64,
Linux x86_64, Linux aarch64, Windows amd64).

Today neither is done consistently: regular cp314 ships on three of four
platforms but is missing on Linux aarch64, where a cp314t (free-threaded)
wheel was published instead — accidentally, and on that one platform only. No
platform ships a deliberate free-threaded wheel.

This was discovered during the 26.6.1 pre-tag review. 26.6.1 ships as-is (the
affected cell falls back to an sdist build, which works); this issue tracks doing
it properly for the next release.

Current behaviour (as of 26.6.1)

The release fileset is 5 interpreters × 4 platforms = 20 NVX wheels, all GIL,
with one wrong cell:

interp macOS arm64 Linux x86_64 Linux aarch64 Win amd64
cp311 ✅ ✅ ✅ ✅
cp312 ✅ ✅ ✅ ✅
cp313 ✅ ✅ ✅ ✅
cp314 ✅ ✅ ❌ → cp314t ✅
pypy311 ✅ ✅ ✅ ✅

Evidence — published asset on release master-202606171850:

autobahn-26.6.1-cp314-cp314-macosx_15_0_arm64.whl
autobahn-26.6.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
autobahn-26.6.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl   # <- cp314t, not cp314
autobahn-26.6.1-cp314-cp314-win_amd64.whl

Impact

Why CI did not catch it

The strict release-fileset check (.cicd/actions/check-release-fileset) requires
the target cpy314-linux-aarch64-manylinux_2_28 (.github/workflows/release.yml:856),
and matches the ABI tag by substring. Because cp314 is a substring of
cp314t, the wrong-ABI wheel satisfied the target and the manifest went green.

Likely root cause

justfile:79 maps the build token cpy314 → uv python install cpython-3.14.
On the aarch64 manylinux build container that request appears to have resolved to
the free-threaded interpreter, while x86_64 / macOS / Windows resolved to the
GIL build. To confirm, inspect the wheels-arm64 CI log for the cp314 aarch64 job
(what uv actually installed). The fix is to pin the interpreter ABI explicitly
per build target rather than relying on cpython-3.14 resolving to the GIL build.

Proposed goal

Publish, for CPython 3.14, on every platform (macOS arm64, Linux x86_64,
Linux aarch64, Windows amd64):

  • cp314 — regular / GIL (NVX native wheel)
  • cp314t — free-threaded / no-GIL (NVX native wheel)

i.e. add a deliberate, symmetric free-threaded variant rather than the current
accidental, single-platform one. (Whether to also add cp313t is an open
question — see Notes.)

Tasks / acceptance criteria

  • Pin the GIL CPython 3.14 interpreter explicitly for all cpy314 build
    targets so aarch64 again produces cp314-cp314 (not cp314t). Confirm
    against the aarch64 CI log first.
  • Add a free-threaded build token (e.g. cpy314t → an explicit
    uv python install spec for the free-threaded 3.14) to the build matrix in
    justfile (ENVS / the cpy314) mapping at justfile:79) and the wheel
    workflows (wheels-arm64.yml and the x86_64/macOS/Windows wheel jobs).
  • Build cp314t NVX wheels on all four platforms; verify the resulting ABI
    tag is cp314t on each.
  • Wire the new artifacts through release.yml (artifact outputs + download
    steps), mirroring how [BUG] PyPI missing cp312 and cpy314 wheels for manylinux aarch64 #1848 plumbed cp312/cp314.
  • Add cpy314t-* targets to all four platform manifests in release.yml,
    and tighten the fileset ABI matching so cp314 and cp314t are
    distinct
    (exact ABI-tag match, not substring) — the
    check-release-fileset README already distinguishes cpy314 vs cpy314t
    target types, so the infra supports it.
  • Resulting stable fileset publishes both cp314 and cp314t for all four
    platforms (24 → 24 GIL + 4 free-threaded, depending on final scope).

Notes / caveats

  • Building a cp314t wheel ≠ free-threading-safe. Under a free-threaded
    interpreter, a C/CFFI extension that does not declare free-threading support
    causes the runtime to re-enable the GIL (with a warning) at import. So a
    cp314t wheel that merely compiles may not deliver real no-GIL parallelism, and
    publishing one is an implicit claim of thread-safety. Before shipping cp314t:
    assess NVX (CFFI) and the relevant pure-Python paths for free-threading
    correctness, and declare free-threading support appropriately (verify what
    CFFI exposes for this on 3.14). This may warrant its own sub-issue.
  • Toolchain availability: confirm uv / python-build-standalone provides a
    free-threaded 3.14 for each target (notably Windows amd64 and the manylinux
    aarch64 container) before committing to "all platforms".
  • PyPy / earlier CPython: free-threading does not apply to PyPy or to
    cp311–cp313 in this scope. Whether to also ship cp313t (free-threading was
    experimental in 3.13) is left open.

References


This analysis was produced with AI assistance (Claude Code) and requires human review before filing. Which I did.

Checklist

  • I have searched existing issues to avoid duplicates
  • I have described the problem clearly
  • I have provided use cases
  • I have considered alternatives
  • I have assessed impact and breaking changes

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions