Skip to content

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

@oberstet

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 cpy314uv 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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions