]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-146636: PEP 803: Reference documentation (GH-148013)
authorPetr Viktorin <encukou@gmail.com>
Thu, 16 Apr 2026 12:17:44 +0000 (14:17 +0200)
committerGitHub <noreply@github.com>
Thu, 16 Apr 2026 12:17:44 +0000 (14:17 +0200)
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Doc/c-api/module.rst
Doc/c-api/stable.rst
Doc/c-api/structures.rst
Doc/data/stable_abi.dat
Doc/tools/extensions/c_annotations.py
Doc/whatsnew/3.15.rst
Misc/NEWS.d/next/C_API/2026-04-03-11-06-20.gh-issue-146636.zR6Jsn.rst [new file with mode: 0644]
Misc/stable_abi.toml
Tools/check-c-api-docs/ignored_c_api.txt

index 8b967c285ac865c842aab7563b4599912508fc0c..a66a1bfd7f8489de641d1064fbf9c12e333ad994 100644 (file)
@@ -685,6 +685,12 @@ remove it.
    Usually, there is only one variable of this type for each extension module
    defined this way.
 
+   The struct, including all members, is part of the
+   :ref:`Stable ABI <stable-abi>` for non-free-threaded builds (``abi3``).
+   In the Stable ABI for free-threaded builds (``abi3t``),
+   this struct is opaque, and unusable in practice; see :ref:`pymoduledef_slot`
+   for a replacement.
+
    .. c:member:: PyModuleDef_Base m_base
 
       Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`:
@@ -695,6 +701,11 @@ remove it.
 
          The type of :c:member:`!PyModuleDef.m_base`.
 
+         The struct is part of the :ref:`Stable ABI <stable-abi>` for
+         non-free-threaded builds (``abi3``).
+         In the Stable ABI for Free-Threaded Builds
+         (``abi3t``), this struct is opaque, and unusable in practice.
+
       .. c:macro:: PyModuleDef_HEAD_INIT
 
          The required initial value for :c:member:`!PyModuleDef.m_base`.
index fe2cb89f999a84801107b4822cccc7156956f2c8..fe92f72f8ebd01a20dd01841ae7b175f1002f403 100644 (file)
@@ -51,145 +51,212 @@ It is generally intended for specialized, low-level tools like debuggers.
 Projects that use this API are expected to follow
 CPython development and spend extra effort adjusting to changes.
 
+.. _stable-abi:
 .. _stable-application-binary-interface:
 
-Stable Application Binary Interface
-===================================
+Stable Application Binary Interfaces
+====================================
 
-For simplicity, this document talks about *extensions*, but the Limited API
-and Stable ABI work the same way for all uses of the API – for example,
-embedding Python.
+Python's :dfn:`Stable ABI` allows extensions to be compatible with multiple
+versions of Python, without recompilation.
 
-.. _limited-c-api:
+.. note::
 
-Limited C API
--------------
+   For simplicity, this document talks about *extensions*, but Stable ABI
+   works the same way for all uses of the API – for example, embedding Python.
 
-Python 3.2 introduced the *Limited API*, a subset of Python's C API.
-Extensions that only use the Limited API can be
-compiled once and be loaded on multiple versions of Python.
-Contents of the Limited API are :ref:`listed below <limited-api-list>`.
+There are two Stable ABIs:
 
-.. c:macro:: Py_LIMITED_API
+- ``abi3``, introduced in Python 3.2, is compatible with
+  **non**-:term:`free-threaded <free-threaded build>` builds of CPython.
 
-   Define this macro before including ``Python.h`` to opt in to only use
-   the Limited API, and to select the Limited API version.
+- ``abi3t``, introduced in Python 3.15, is compatible with
+  :term:`free-threaded <free-threaded build>` builds of CPython.
+  It has stricter API limitations than ``abi3``.
 
-   Define ``Py_LIMITED_API`` to the value of :c:macro:`PY_VERSION_HEX`
-   corresponding to the lowest Python version your extension supports.
-   The extension will be ABI-compatible with all Python 3 releases
-   from the specified one onward, and can use Limited API introduced up to that
-   version.
+   .. versionadded:: next
 
-   Rather than using the ``PY_VERSION_HEX`` macro directly, hardcode a minimum
-   minor version (e.g. ``0x030A0000`` for Python 3.10) for stability when
-   compiling with future Python versions.
+      ``abi3t`` was added in :pep:`803`
 
-   You can also define ``Py_LIMITED_API`` to ``3``. This works the same as
-   ``0x03020000`` (Python 3.2, the version that introduced Limited API).
+It is possible for an extension to be compiled for *both* ``abi3`` and
+``abi3t`` at the same time; the result will be compatible with
+both free-threaded and non-free-threaded builds of Python.
+Currently, this has no downsides compared to compiling for ``abi3t`` only.
 
-.. c:macro:: Py_TARGET_ABI3T
+Each Stable ABI is versioned using the first two numbers of the Python version.
+For example, Stable ABI 3.14 corresponds to Python 3.14.
+An extension compiled for Stable ABI 3.x is ABI-compatible with Python 3.x
+and above.
 
-   Define this macro before including ``Python.h`` to opt in to only use
-   the Limited API for :term:`free-threaded builds <free-threaded build>`,
-   and to select the Limited API version.
+Extensions that target a stable ABI must only use a limited subset of
+the C API. This subset is known as the :dfn:`Limited API`; its contents
+are :ref:`listed below <limited-api-list>`.
 
-   .. seealso:: :pep:`803`
+On Windows, extensions that use a Stable ABI should be linked against
+``python3.dll`` rather than a version-specific library such as
+``python39.dll``.
+This library only exposes the relevant symbols.
 
-   .. versionadded:: 3.15
+On some platforms, Python will look for and load shared library files named
+with the ``abi3`` or ``abi3t`` tag (for example, ``mymodule.abi3.so``).
+:term:`Free-threaded <free-threaded build>` interpreters only recognize the
+``abi3t`` tag, while non-free-threaded ones will prefer ``abi3`` but fall back
+to ``abi3t``.
+Thus, extensions compatible with both ABIs should use the ``abi3t`` tag.
+
+Python does not necessarily check that extensions it loads
+have compatible ABI.
+Extension authors are encouraged to add a check using the :c:macro:`Py_mod_abi`
+slot or the :c:func:`PyABIInfo_Check` function, but the user
+(or their packaging tool) is ultimately responsible for ensuring that,
+for example, extensions built for Stable ABI 3.10 are not installed for lower
+versions of Python.
 
+All functions in Stable ABI are present as functions in Python's shared
+library, not solely as macros.
+This makes them usable are usable from languages that don't use the C
+preprocessor, including Python's :py:mod:`ctypes`.
 
-.. _stable-abi:
 
-Stable ABI
-----------
+.. _abi3-compiling:
 
-To enable this, Python provides a *Stable ABI*: a set of symbols that will
-remain ABI-compatible across Python 3.x versions.
+Compiling for Stable ABI
+------------------------
 
 .. note::
 
-   The Stable ABI prevents ABI issues, like linker errors due to missing
-   symbols or data corruption due to changes in structure layouts or function
-   signatures.
-   However, other changes in Python can change the *behavior* of extensions.
-   See Python's Backwards Compatibility Policy (:pep:`387`) for details.
+   Build tools (such as, for example, meson-python, scikit-build-core,
+   or Setuptools) often have a mechanism for setting macros and synchronizing
+   them with extension filenames and other metadata.
+   Prefer using such a mechanism, if it exists, over defining the
+   macros manually.
 
-The Stable ABI contains symbols exposed in the :ref:`Limited API
-<limited-c-api>`, but also other ones – for example, functions necessary to
-support older versions of the Limited API.
+   The rest of this section is mainly relevant for tool authors, and for
+   people who compile extensions manually.
 
-On Windows, extensions that use the Stable ABI should be linked against
-``python3.dll`` rather than a version-specific library such as
-``python39.dll``.
+   .. seealso:: `list of recommended tools`_ in the Python Packaging User Guide
 
-On some platforms, Python will look for and load shared library files named
-with the ``abi3`` tag (e.g. ``mymodule.abi3.so``).
-It does not check if such extensions conform to a Stable ABI.
-The user (or their packaging tools) need to ensure that, for example,
-extensions built with the 3.10+ Limited API are not installed for lower
-versions of Python.
+      .. _list of recommended tools: https://packaging.python.org/en/latest/guides/tool-recommendations/#build-backends-for-extension-modules
 
-All functions in the Stable ABI are present as functions in Python's shared
-library, not solely as macros. This makes them usable from languages that don't
-use the C preprocessor.
+To compile for a Stable ABI, define one or both of the following macros
+to the lowest Python version your extension should support, in
+:c:macro:`Py_PACK_VERSION` format.
+Typically, you should choose a specific value rather than the version of
+the Python headers you are compiling against.
 
+The macros must be defined before including ``Python.h``.
+Since :c:macro:`Py_PACK_VERSION` is not available at this point, you
+will need to use the numeric value directly.
+For reference, the values for a few recent Python versions are:
 
-Limited API Scope and Performance
----------------------------------
+.. version-hex-cheatsheet::
 
-The goal for the Limited API is to allow everything that is possible with the
+When one of the macros is defined, ``Python.h`` will only expose API that is
+compatible with the given Stable ABI -- that is, the
+:ref:`Limited API <limited-api-list>` plus some definitions that need to be
+visible to the compiler but should not be used directly.
+When both are defined, ``Python.h`` will only expose API compatible with
+both Stable ABIs.
+
+.. c:macro:: Py_LIMITED_API
+
+   Target ``abi3``, that is,
+   non-:term:`free-threaded builds <free-threaded build>` of CPython.
+   See :ref:`above <abi3-compiling>` for common information.
+
+.. c:macro:: Py_TARGET_ABI3T
+
+   Target ``abi3t``, that is,
+   :term:`free-threaded builds <free-threaded build>` of CPython.
+   See :ref:`above <abi3-compiling>` for common information.
+
+   .. versionadded:: next
+
+Both macros specify a target ABI; the different naming style is due to
+backwards compatibility.
+
+.. admonition:: Historical note
+
+   You can also define ``Py_LIMITED_API`` as ``3``. This works the same as
+   ``0x03020000`` (Python 3.2, the version that introduced Stable ABI).
+
+When both are defined, ``Python.h`` may, or may not, redefine
+:c:macro:`!Py_LIMITED_API` to match :c:macro:`!Py_TARGET_ABI3T`.
+
+On a :term:`free-threaded build` -- that is, when
+:c:macro:`Py_GIL_DISABLED` is defined -- :c:macro:`!Py_TARGET_ABI3T`
+defaults to the value of :c:macro:`!Py_LIMITED_API`.
+This means that there are two ways to build for both ``abi3`` and ``abi3t``:
+
+- define both :c:macro:`!Py_LIMITED_API` and :c:macro:`!Py_TARGET_ABI3T`, or
+- define only :c:macro:`!Py_LIMITED_API` and:
+
+  - on Windows, define :c:macro:`!Py_GIL_DISABLED`;
+  - on other systems, use the headers of free-threaded build of Python.
+
+
+.. _limited-api-scope-and-performance:
+
+Stable ABI Scope and Performance
+--------------------------------
+
+The goal for Stable ABI is to allow everything that is possible with the
 full C API, but possibly with a performance penalty.
+Generally, compatibility with Stable ABI will require some changes to an
+extension's source code.
 
-For example, while :c:func:`PyList_GetItem` is available, its “unsafe” macro
+For example, while :c:func:`PyList_GetItem` is available, its "unsafe" macro
 variant :c:func:`PyList_GET_ITEM` is not.
 The macro can be faster because it can rely on version-specific implementation
 details of the list object.
 
-Without ``Py_LIMITED_API`` defined, some C API functions are inlined or
-replaced by macros.
-Defining ``Py_LIMITED_API`` disables this inlining, allowing stability as
+For another example, when *not* compiling for Stable ABI, some C API
+functions are inlined or replaced by macros.
+Compiling for Stable ABI disables this inlining, allowing stability as
 Python's data structures are improved, but possibly reducing performance.
 
-By leaving out the ``Py_LIMITED_API`` definition, it is possible to compile
-a Limited API extension with a version-specific ABI. This can improve
-performance for that Python version, but will limit compatibility.
-Compiling with ``Py_LIMITED_API`` will then yield an extension that can be
-distributed where a version-specific one is not available – for example,
-for prereleases of an upcoming Python version.
+By leaving out the :c:macro:`!Py_LIMITED_API` or :c:macro:`!Py_TARGET_ABI3T`
+definition, it is possible to compile Stable-ABI-compatible source
+for a version-specific ABI.
+A potentially faster version-specific extension can then be distributed
+alongside a version compiled for Stable ABI -- a slower but more compatible
+fallback.
 
 
-Limited API Caveats
--------------------
+.. _limited-api-caveats:
 
-Note that compiling with ``Py_LIMITED_API`` is *not* a complete guarantee that
-code conforms to the :ref:`Limited API <limited-c-api>` or the :ref:`Stable ABI
-<stable-abi>`. ``Py_LIMITED_API`` only covers definitions, but an API also
-includes other issues, such as expected semantics.
+Stable ABI Caveats
+------------------
 
-One issue that ``Py_LIMITED_API`` does not guard against is calling a function
-with arguments that are invalid in a lower Python version.
+Note that compiling for Stable ABI is *not* a complete guarantee that code will
+be compatible with the expected Python versions.
+Stable ABI prevents *ABI* issues, like linker errors due to missing
+symbols or data corruption due to changes in structure layouts or function
+signatures.
+However, other changes in Python can change the *behavior* of extensions.
+
+One issue that the :c:macro:`Py_TARGET_ABI3T` and :c:macro:`Py_LIMITED_API`
+macros do not guard against is calling a function with arguments that are
+invalid in a lower Python version.
 For example, consider a function that starts accepting ``NULL`` for an
 argument. In Python 3.9, ``NULL`` now selects a default behavior, but in
 Python 3.8, the argument will be used directly, causing a ``NULL`` dereference
 and crash. A similar argument works for fields of structs.
 
-Another issue is that some struct fields are currently not hidden when
-``Py_LIMITED_API`` is defined, even though they're part of the Limited API.
-
 For these reasons, we recommend testing an extension with *all* minor Python
-versions it supports, and preferably to build with the *lowest* such version.
+versions it supports.
 
 We also recommend reviewing documentation of all used API to check
 if it is explicitly part of the Limited API. Even with ``Py_LIMITED_API``
 defined, a few private declarations are exposed for technical reasons (or
 even unintentionally, as bugs).
 
-Also note that the Limited API is not necessarily stable: compiling with
-``Py_LIMITED_API`` with Python 3.8 means that the extension will
-run with Python 3.12, but it will not necessarily *compile* with Python 3.12.
-In particular, parts of the Limited API may be deprecated and removed,
-provided that the Stable ABI stays stable.
+Also note that while compiling with ``Py_LIMITED_API`` 3.8 means that the
+extension should *load* on Python 3.12, and *compile* with Python 3.12,
+the same source will not necessarily compile with ``Py_LIMITED_API``
+set to 3.12.
+In general, parts of the Limited API may be deprecated and removed,
+provided that Stable ABI stays stable.
 
 
 .. _stable-abi-platform:
@@ -199,12 +266,12 @@ Platform Considerations
 
 ABI stability depends not only on Python, but also on the compiler used,
 lower-level libraries and compiler options. For the purposes of
-the :ref:`Stable ABI <stable-abi>`, these details define a “platform”. They
+the :ref:`Stable ABIs <stable-abi>`, these details define a “platform”. They
 usually depend on the OS type and processor architecture
 
 It is the responsibility of each particular distributor of Python
 to ensure that all Python versions on a particular platform are built
-in a way that does not break the Stable ABI.
+in a way that does not break the Stable ABIs, or the version-specific ABIs.
 This is the case with Windows and macOS releases from ``python.org`` and many
 third-party distributors.
 
@@ -312,7 +379,7 @@ The full API is described below for advanced use cases.
 
          .. c:macro:: PyABIInfo_STABLE
 
-            Specifies that the stable ABI is used.
+            Specifies that Stable ABI is used.
 
          .. c:macro:: PyABIInfo_INTERNAL
 
@@ -323,15 +390,22 @@ The full API is described below for advanced use cases.
 
          .. c:macro:: PyABIInfo_FREETHREADED
 
-            Specifies ABI compatible with free-threading builds of CPython.
+            Specifies ABI compatible with :term:`free-threaded builds
+            <free-threaded build>` of CPython.
             (That is, ones compiled with :option:`--disable-gil`; with ``t``
             in :py:data:`sys.abiflags`)
 
          .. c:macro:: PyABIInfo_GIL
 
-            Specifies ABI compatible with non-free-threading builds of CPython
+            Specifies ABI compatible with non-free-threaded builds of CPython
             (ones compiled *without* :option:`--disable-gil`).
 
+         .. c:macro:: PyABIInfo_FREETHREADING_AGNOSTIC
+
+            Specifies ABI compatible with both free-threaded and
+            non-free-threaded builds of CPython, that is, both
+            ``abi3`` and ``abi3t``.
+
    .. c:member:: uint32_t build_version
 
       The version of the Python headers used to build the code, in the format
@@ -345,10 +419,11 @@ The full API is described below for advanced use cases.
 
       The ABI version.
 
-      For the Stable ABI, this field should be the value of
-      :c:macro:`Py_LIMITED_API`
-      (except if :c:macro:`Py_LIMITED_API` is ``3``; use
-      :c:expr:`Py_PACK_VERSION(3, 2)` in that case).
+      For Stable ABI, this field should be the value of
+      :c:macro:`Py_LIMITED_API` or :c:macro:`Py_TARGET_ABI3T`.
+      If both are defined, use the smaller value.
+      (If :c:macro:`Py_LIMITED_API` is ``3``; use
+      :c:expr:`Py_PACK_VERSION(3, 2)` instead of ``3``.)
 
       Otherwise, it should be set to :c:macro:`PY_VERSION_HEX`.
 
@@ -365,12 +440,13 @@ The full API is described below for advanced use cases.
    .. versionadded:: 3.15
 
 
+.. _limited-c-api:
 .. _limited-api-list:
 
 Contents of Limited API
 =======================
 
-
-Currently, the :ref:`Limited API <limited-c-api>` includes the following items:
+This is the definitive list of :ref:`Limited API <limited-c-api>` for
+Python |version|:
 
 .. limited-api-list::
index c0d2663adefc6b5898db2ef4511b7f6f4ca1ce93..aeca412610317fef39d6e1b55c319075b17f0ee0 100644 (file)
@@ -33,6 +33,13 @@ under :ref:`reference counting <countingrefs>`.
    The members must not be accessed directly; instead use macros such as
    :c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE`.
 
+   In the :ref:`Stable ABI <stable-abi>` for Free-Threaded Builds (``abi3t``),
+   this struct is opaque; its size and layout may change between
+   Python versions.
+   In Stable ABI for non-free-threaded builds (``abi3``), the
+   :c:member:`!ob_refcnt` and :c:member:`!ob_type` fields are available,
+   but using them directly is discouraged.
+
    .. c:member:: Py_ssize_t ob_refcnt
 
       The object's reference count, as returned by :c:macro:`Py_REFCNT`.
@@ -72,6 +79,19 @@ under :ref:`reference counting <countingrefs>`.
    instead use macros such as :c:macro:`Py_SIZE`, :c:macro:`Py_REFCNT` and
    :c:macro:`Py_TYPE`.
 
+   In the :ref:`Stable ABI <stable-abi>` for Free-Threaded Builds (``abi3t``),
+   this struct is opaque; its size and layout may change between
+   Python versions.
+   In Stable ABI for non-free-threaded builds (``abi3``), the
+   :c:member:`!ob_base` and :c:member:`!ob_size` fields are available,
+   but using them directly is discouraged.
+
+   .. c:member:: PyObject ob_base
+
+      Common object header.
+      Typically, this field is not accessed directly; instead
+      :c:type:`!PyVarObject` can be cast to :c:type:`PyObject`.
+
    .. c:member:: Py_ssize_t ob_size
 
       A size field, whose contents should be considered an object's internal
index 4a7fbdf60bfb431cc9c474fe83d443247ff581d4..4ae5e999f0bf21db3f8caa04590467c168617e18 100644 (file)
@@ -470,8 +470,8 @@ func,PyMemoryView_GetContiguous,3.2,,
 data,PyMemoryView_Type,3.2,,
 type,PyMethodDef,3.2,,full-abi
 data,PyMethodDescr_Type,3.2,,
-type,PyModuleDef,3.2,,full-abi
-type,PyModuleDef_Base,3.2,,full-abi
+type,PyModuleDef,3.2,,abi3t-opaque
+type,PyModuleDef_Base,3.2,,abi3t-opaque
 func,PyModuleDef_Init,3.5,,
 type,PyModuleDef_Slot,3.5,,full-abi
 data,PyModuleDef_Type,3.5,,
index 724dea625c4e21345ac281edbfe659b21978a278..1409c77aed9c6bc17c2ab639bcc0788ad0bfcb67 100644 (file)
@@ -249,18 +249,17 @@ def _stable_abi_annotation(
         reftype="ref",
         refexplicit="False",
     )
-    struct_abi_kind = record.struct_abi_kind
-    if struct_abi_kind in {"opaque", "members"}:
-        ref_node += nodes.Text(sphinx_gettext("Limited API"))
-    else:
-        ref_node += nodes.Text(sphinx_gettext("Stable ABI"))
+    ref_node += nodes.Text(sphinx_gettext("Stable ABI"))
     emph_node += ref_node
+    struct_abi_kind = record.struct_abi_kind
     if struct_abi_kind == "opaque":
         emph_node += nodes.Text(" " + sphinx_gettext("(as an opaque struct)"))
     elif struct_abi_kind == "full-abi":
         emph_node += nodes.Text(
             " " + sphinx_gettext("(including all members)")
         )
+    elif struct_abi_kind in {"members", "abi3t-opaque"}:
+        emph_node += nodes.Text(" " + sphinx_gettext("(see below)"))
     if record.ifdef_note:
         emph_node += nodes.Text(f" {record.ifdef_note}")
     if stable_added == "3.2":
@@ -271,11 +270,7 @@ def _stable_abi_annotation(
             " " + sphinx_gettext("since version %s") % stable_added
         )
     emph_node += nodes.Text(".")
-    if struct_abi_kind == "members":
-        msg = " " + sphinx_gettext(
-            "(Only some members are part of the stable ABI.)"
-        )
-        emph_node += nodes.Text(msg)
+
     return emph_node
 
 
@@ -378,6 +373,33 @@ class LimitedAPIList(SphinxDirective):
         return [node]
 
 
+class VersionHexCheatsheet(SphinxDirective):
+    """Show results of Py_PACK_VERSION(3, x) for a few relevant Python versions
+
+    This is useful for defining version before Python.h is included.
+    It should auto-update with the version being documented, so it must be an
+    extension.
+    """
+
+    has_content = False
+    required_arguments = 0
+    optional_arguments = 0
+    final_argument_whitespace = True
+
+    def run(self) -> list[nodes.Node]:
+        content = [
+            ".. code-block:: c",
+            "",
+        ]
+        current_minor = int(self.config.version.removeprefix('3.'))
+        for minor in range(current_minor - 5, current_minor + 1):
+            value = (3 << 24) | (minor << 16)
+            content.append(f'    {value:#x}  /* Py_PACK_VERSION(3.{minor}) */')
+        node = nodes.paragraph()
+        self.state.nested_parse(StringList(content), 0, node)
+        return [node]
+
+
 class CorrespondingTypeSlot(SphinxDirective):
     """Type slot annotations
 
@@ -443,6 +465,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
     app.add_config_value("stable_abi_file", "", "env", types={str})
     app.add_config_value("threadsafety_file", "", "env", types={str})
     app.add_directive("limited-api-list", LimitedAPIList)
+    app.add_directive("version-hex-cheatsheet", VersionHexCheatsheet)
     app.add_directive("corresponding-type-slot", CorrespondingTypeSlot)
     app.connect("builder-inited", init_annotations)
     app.connect("doctree-read", add_annotations)
index ed07afd2277cc031f7cf1e740a44ce10554f45f9..7ea7c901eceb191535ba51ba6dcc4b1f38728a7f 100644 (file)
@@ -82,6 +82,7 @@ Summary -- Release highlights
   <whatsnew315-typeform>`
 * :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object
   <whatsnew315-pybyteswriter>`
+* :pep:`803`: :ref:`Stable ABI for Free-Threaded Builds <whatsnew315-abi3t>`
 * :ref:`The JIT compiler has been significantly upgraded <whatsnew315-jit>`
 * :ref:`Improved error messages <whatsnew315-improved-error-messages>`
 * :ref:`The official Windows 64-bit binaries now use the tail-calling interpreter
@@ -381,6 +382,41 @@ agen() for x in a)``.
 
 (Contributed by Adam Hartz in :gh:`143055`.)
 
+.. _whatsnew315-abi3t:
+
+:pep:`803`: ``abi3t`` -- Stable ABI for Free-Threaded Builds
+------------------------------------------------------------
+
+C extensions that target the :ref:`Stable ABI <stable-abi>` can now be
+compiled for the new *Stable ABI for Free-Threaded Builds* (also known
+as ``abi3t``), which makes them compatible with
+:term:`free-threaded builds <free-threaded build>` of CPython.
+This usually requires some non-trivial changes to the source code;
+specifically:
+
+- Switching to API introduced in :pep:`697` (Python 3.12), such as
+  negative :c:member:`~PyType_Spec.basicsize` and
+  :c:func:`PyObject_GetTypeData`, rather than making :c:type:`PyObject`
+  part of the instance struct; and
+- Switching from a ``PyInit_`` function to a new export hook,
+  :c:func:`PyModExport_* <PyModExport_modulename>`, introduced for this
+  purpose in :pep:`793`.
+
+Note that Stable ABI does not offer all the functionality that CPython
+has to offer.
+Extensions that cannot switch to ``abi3t`` should continue to build for
+the existing Stable ABI (``abi3``) and the version-specific ABI for
+free-threading (``cp315t``) separately.
+
+Stable ABI for Free-Threaded Builds should typically
+be selected in a build tool (such as, for example, Setuptools, meson-python,
+scikit-build-core, or Maturin).
+At the time of writing, these tools did **not** support ``abi3t``.
+If this is the case for your tool, compile for ``cp315t`` separately.
+If not using a build tool -- or when writing such a tool -- you can select
+``abi3t`` by setting the macro :c:macro:`!Py_TARGET_ABI3T` as discussed
+in :ref:`abi3-compiling`.
+
 
 .. _whatsnew315-improved-error-messages:
 
diff --git a/Misc/NEWS.d/next/C_API/2026-04-03-11-06-20.gh-issue-146636.zR6Jsn.rst b/Misc/NEWS.d/next/C_API/2026-04-03-11-06-20.gh-issue-146636.zR6Jsn.rst
new file mode 100644 (file)
index 0000000..7f84a6f
--- /dev/null
@@ -0,0 +1 @@
+Implement :pep:`803` -- ``abi3t``: Stable ABI for Free-Threaded Builds.
index 606a0a88d26cf269a6a4a6b64adb0451d8992540..101737a27829c9c5f6e34240488af74c7564e868 100644 (file)
@@ -1,4 +1,4 @@
-# This file lists the contents of the Limited API and Stable ABI.
+# This file lists the contents of Limited API and Stable ABI.
 # Please append new items at the end.
 
 # The syntax of this file is not fixed.
 #   - 'opaque': No members are part of the ABI, nor is the size. The Limited
 #     API only handles these via pointers. The C definition should be
 #     incomplete (opaque).
-#   - 'members': Only specific members are part of the stable ABI.
-#     The struct's size may change, so it can't be used in arrays.
+#   - 'abi3t-opaque': 'full-abi' in abi3; 'opaque' in abi3t.
+#     For docs, the generated annotation refers to details that need to
+#     be added to the ReST file manually.
+#   - 'members':
+#     - 'opaque' in abi3t.
+#     - In abi3, only specific members are part of the stable ABI.
+#       The struct's size may change, so it can't be used in arrays.
 #     Do not add new structs of this kind without an extremely good reason.
+#     For docs, the generated annotation refers to details that need to
+#     be added to the ReST file manually.
 # - members: For `struct` with struct_abi_kind = 'members', a list of the
 #   exposed members.
 # - doc: for `feature_macro`, the blurb added in documentation
 # - windows: for `feature_macro`, this macro is defined on Windows.
 #   (This info is used to generate the DLL manifest and needs to be available
 #   on all platforms.)
+# - abi3t_opaque: In abi3t, this struct is opaque (as if `struct_abi_kind`
+#   was 'opaque' and `members` was missing).
 
 # Removing items from this file is generally not allowed, and additions should
 # be considered with that in mind. See the devguide for exact rules:
     struct_abi_kind = 'full-abi'
 [struct.PyModuleDef_Base]
     added = '3.2'
-    struct_abi_kind = 'full-abi'
+    struct_abi_kind = 'abi3t-opaque'
 [struct.PyModuleDef]
     added = '3.2'
-    struct_abi_kind = 'full-abi'
+    struct_abi_kind = 'abi3t-opaque'
 [struct.PyStructSequence_Field]
     added = '3.2'
     struct_abi_kind = 'full-abi'
index f3a3612b84947a16119b953c11de756deba8cc82..dfec0524cfe016deca1e8eea6ec235c1c06fb430 100644 (file)
@@ -18,8 +18,6 @@ Py_HasFileSystemDefaultEncoding
 Py_UTF8Mode
 # pyhash.h
 Py_HASH_EXTERNAL
-# modsupport.h
-PyABIInfo_FREETHREADING_AGNOSTIC
 # object.h
 Py_INVALID_SIZE
 # pyexpat.h