Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 45 additions & 11 deletions peps/pep-0803.rst
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,20 @@ The tag ``abi3t`` is chosen to reflect the fact that this ABI is similar to
uses the letter ``t`` in existing, version-specific ABI tags like ``cp314t``).


Filename tag
------------

On systems that use the ``abi3`` tag in filenames, a new filename tag
(``abi3t``) is added so that older stable ABI extensions
(:samp:`{name}.abi3.so`) can be installed in the same directory as ones that
support Stable ABI for free-threaded Python (:samp:`{name}.abi3t.so`).

There can only be one ABI tag in a filename (there is no concept of "compressed
tag sets like in wheel tags), so extensions that are compatible with both ABIs
at once need to use *one* of the tags -- the new one (``abi3t``), which
is currently unused.


Specification
=============

Expand Down Expand Up @@ -461,14 +475,34 @@ and may be removed in future CPython versions,
if the internal object layout needs to change.


The ``abi3t`` wheel tag
-----------------------
The ``abi3t`` wheel and filename tags
-------------------------------------

Wheels that use a stable ABI compatible with free-threading CPython builds
should use a new `ABI tag`_: ``abi3t``.

.. _ABI tag: https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/#abi-tag

On systems where filenames of Stable ABI extensions end with ``.abi3.so``,
extensions that support free-threading should instead use ``abi3t.so``.
This includes extensions compatible with *both* ``abi3`` and ``abi3t``.

On these systems, all builds of CPython -- GIL-enabled and free-threaded --
will load extensions with the ``abi3t`` tag.
Free-threaded builds will -- unlike in 3.14 -- *not* load extensions
with the ``abi3`` tag.
If files are present with both tags, GIL-enabled builds will prefer
"their" ``*.abi3.so`` over ``*.abi3t.so``.

Put another way, ``importlib.machinery.EXTENSION_SUFFIXES`` will be
(for ``x86_64-linux-gnu`` builds of CPython):

* ``python3.15``:
``['.cpython-315-x86_64-linux-gnu.so', '.abi3.so', '.abi3t.so', '.so']``
* ``python3.15t``:
``['.cpython-315-x86_64-linux-gnu.so', '.abi3t.so', '.so']``


Recommendations for installers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -504,6 +538,13 @@ In the above, :samp:`{v}` stands for a the lowest Python version with which
the extension should be compatible, in :c:func:`Py_PACK_VERSION` format.
In the cases above, this version must be set to 3.15 or higher.

In both cases, if a resulting extension's *filename* would use the ``abi3``
tag (that is, :samp:`{modulename}.abi3.so` on Linux, macOS, and similar),
the ``abi3t`` tag should be used instead (that is,
:samp:`{modulename}.abi3t.so` on those systems).
If this tag is not used, there should be no change. (This is always the case
on Windows, where the filename should remain :samp:`{name}.pyd`.)

.. _compressed tag set: https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/#compressed-tag-sets

The version of the Stable ABI, both ``abi3`` and ``abi3t``, is indicated by
Expand Down Expand Up @@ -783,15 +824,8 @@ Naming this ``abi4``
Instead of ``abi3t``, we could “bump the version” and use ``abi4`` instead.
The difference is largely cosmetic.

However, one thing this PEP does not propose is changing the *filename*
tag: extensions will be named with the extensions like ``.abi3.so``.
Changing this while keeping compatibility with GIL-enabled builds would be
an unnecessary technical change.

Using ``abi3.abi4`` in wheel tags but only ``.abi3`` in filenames would
look more inconsistent than ``abi3.abi3t`` and ``.abi3``.

If we added an ``abi4`` tag, the ``Py_LIMITED_API`` value would either need to:
If we added an ``abi4`` tag, the value of the opt-in macro (``Py_TARGET_ABI4``
or ``Py_LIMITED_API`` or some such) would either need to:

* change to start with ``4`` to match ``abi4``, but no longer correspond
to ``PY_VERSION_HEX`` (making it harder to generate and check), or
Expand Down
Loading