Skip to content
Open
Show file tree
Hide file tree
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
11 changes: 11 additions & 0 deletions Doc/c-api/module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`:
Expand All @@ -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`.
Expand Down
270 changes: 173 additions & 97 deletions Doc/c-api/stable.rst

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions Doc/c-api/structures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Doc/data/stable_abi.dat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 33 additions & 10 deletions Doc/tools/extensions/c_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand All @@ -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


Expand Down Expand Up @@ -378,6 +373,33 @@ def run(self) -> list[nodes.Node]:
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

Expand Down Expand Up @@ -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)
Expand Down
36 changes: 36 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement :pep:`803` -- ``abi3t``: Stable ABI for Free-Threaded Builds.
19 changes: 14 additions & 5 deletions Misc/stable_abi.toml
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -46,15 +46,24 @@
# - '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:
Expand Down Expand Up @@ -107,10 +116,10 @@
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'
Expand Down
2 changes: 0 additions & 2 deletions Tools/check-c-api-docs/ignored_c_api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading