| Python stable ABI (abi3, abi3t) | |
| ############################### | |
| CPython's `stable ABI <https://docs.python.org/3/c-api/stable.html>`_ lets | |
| one extension module run on every CPython release from the version it was | |
| built for. pybind11 supports it from CPython 3.12 on: define | |
| ``Py_LIMITED_API`` to ``0x030C0000`` (or a newer version) and ship one | |
| ``*.abi3.so`` / ``*.pyd`` per platform instead of one module per Python | |
| version. | |
| CPython 3.15 adds a second stable ABI, ``abi3t`` (:pep:`803`). An ``abi3t`` | |
| module loads on every free-threaded *and* GIL-enabled CPython from 3.15 on, so | |
| one ``*.abi3t.so`` per platform covers both builds. pybind11 supports it too: | |
| define ``Py_TARGET_ABI3T`` to ``0x030F0000`` (or a newer version). Headers of | |
| either build work. With free-threaded headers, ``Py_LIMITED_API`` alone also | |
| selects ``abi3t``, because free-threaded CPython has no ``abi3``. See `abi3t`_ | |
| below for what differs. | |
| Enabling it | |
| =========== | |
| With CMake, add ``STABLE_ABI`` to ``pybind11_add_module`` (CMake 3.26+ and | |
| the FindPython mode are required), or set ``PYBIND11_STABLE_ABI`` to make it | |
| the default for a build tree: | |
| .. code-block:: cmake | |
| pybind11_add_module(example STABLE_ABI example.cpp) | |
| ``PYBIND11_STABLE_ABI_VERSION`` (default ``3.12``, raised to ``3.15`` for | |
| ``abi3t``) selects the targeted version. On free-threaded Python the modules | |
| are always ``abi3t``. Set ``PYBIND11_ABI3T`` to ``ON`` to also build ``abi3t`` | |
| modules with GIL-enabled Python (plain CMake only; wheel builders tag the | |
| wheel from the build Python, see `Building wheels`_): | |
| .. code-block:: bash | |
| cmake -S . -B build -DPYBIND11_STABLE_ABI=ON -DPYBIND11_ABI3T=ON | |
| If your project calls ``find_package(Python)`` itself, add the | |
| ``Development.SABIModule`` component; pybind11 adds it only when it finds | |
| Python itself. | |
| ``PRECOMPILE`` can be combined with ``STABLE_ABI``; the precompiled library | |
| is then compiled against the limited API too, and one build tree cannot mix | |
| stable-ABI and regular precompiled modules. | |
| With scikit-build-core, set ``wheel.py-api = "cp312"`` in ``pyproject.toml`` | |
| (``"cp312.cp315t"`` to also get ``abi3t`` wheels from free-threaded Python; | |
| the pybind11 defaults produce the matching module in both cases). This only | |
| selects the wheel tag, and scikit-build-core ignores it when the build Python | |
| is too old or is not CPython, so enable ``STABLE_ABI`` from the variables it | |
| sets, before ``find_package(pybind11)`` (scikit-build-core 0.11+ sets | |
| ``SKBUILD_SABI_VERSION``; with older versions it is empty and pybind11 uses its | |
| default): | |
| .. code-block:: cmake | |
| if(SKBUILD_SABI_COMPONENT) | |
| set(PYBIND11_STABLE_ABI ON) | |
| set(PYBIND11_STABLE_ABI_VERSION "${SKBUILD_SABI_VERSION}" CACHE STRING "") | |
| endif() | |
| If your project calls ``find_package(Python)`` itself, add the component that | |
| scikit-build-core selects: | |
| .. code-block:: cmake | |
| find_package(Python REQUIRED COMPONENTS Interpreter Development.Module | |
| ${SKBUILD_SABI_COMPONENT}) | |
| With setuptools, pass ``py_limited_api=True`` (or a version such as | |
| ``"3.13"``) to ``Pybind11Extension``; the module is named ``*.abi3.so`` | |
| and ``Py_LIMITED_API`` is defined for you. Add a ``t`` (``"3.15t"``) for | |
| ``abi3t``, which is always used on free-threaded Python; ``Py_TARGET_ABI3T`` | |
| is then defined and the module is named ``*.abi3t*.so``. With GIL-enabled | |
| Python, use ``build_ext`` from ``pybind11.setup_helpers`` to get that name. | |
| Set the wheel tag with ``options={"bdist_wheel": {"py_limited_api": "cp312"}}`` | |
| in ``setup()``; ``bdist_wheel`` rejects ``"cp315t"``, so pass ``"cp315"`` and | |
| build on free-threaded Python to get the ``abi3.abi3t`` tag. | |
| With meson-python, set ``limited-api = true`` in ``[tool.meson-python]`` and | |
| pass ``limited_api: '3.12'`` to ``py.extension_module()``. Meson defines | |
| ``Py_LIMITED_API`` from that value, so use ``'3.15'`` when the build Python is | |
| free-threaded: | |
| .. code-block:: meson | |
| limited_api = py.get_variable('Py_GIL_DISABLED', 0).to_string() == '1' ? '3.15' : '3.12' | |
| With any other build system, define ``Py_LIMITED_API=0x030C0000`` for every | |
| translation unit, link no version-specific Python library (``python3.lib`` on | |
| Windows), and name the module ``<name>.abi3.so`` (``<name>.pyd`` on Windows). | |
| For ``abi3t``, define ``Py_TARGET_ABI3T=0x030F0000`` instead, link | |
| ``python3t.lib`` on Windows, and name the module ``<name>.abi3t.so``. | |
| On CPython 3.15+, build tools can also use the platform-tagged suffixes | |
| ``.abi3-<platform>.so`` and ``.abi3t-<platform>.so`` (such as | |
| ``.abi3t-darwin.so``). CPython 3.15+ loads both forms, but CPython 3.12 to | |
| 3.14 only load ``.abi3.so``. | |
| Building wheels | |
| --------------- | |
| * Build ``abi3`` wheels with the CPython version you target. On 3.15+, | |
| setuptools and CMake name the module ``.abi3-<platform>.so``, so a module | |
| that targets 3.12 to 3.14 but is built with 3.15+ has a suffix that its | |
| target versions do not load. | |
| * Build ``abi3t`` wheels with free-threaded CPython 3.15+. With GIL-enabled | |
| Python, scikit-build-core and setuptools tag the wheel ``abi3`` even when | |
| the module is ``abi3t``, so the wheel installs where it cannot load. | |
| * When a ``setup.py`` runs CMake, pass ``-DPython_EXECUTABLE=<sys.executable>``. | |
| FindPython skips free-threaded interpreters by default, so it can find a | |
| GIL-enabled Python and build an ``abi3`` module into an ``abi3t`` wheel. | |
| * Every extension module in an ``abi3`` or ``abi3t`` wheel must use the | |
| stable ABI; one version-specific module makes the wheel tag wrong. | |
| pybind11 rejects the combination with PyPy, GraalPy, and free-threaded | |
| CPython before 3.15 at compile time: they have no stable ABI. | |
| What changes under the stable ABI | |
| ================================= | |
| The C++ API of pybind11 is the same; the differences are in what is | |
| available and in how a few things are implemented. | |
| .. list-table:: | |
| :header-rows: 1 | |
| :widths: 30 20 50 | |
| * - Feature | |
| - Stable ABI | |
| - Notes | |
| * - Classes, functions, casters, STL, numpy, Eigen | |
| - supported | |
| - Under abi3t, ``numpy.h`` needs NumPy 2.5+ at run time (it reads | |
| array fields through NumPy's abi3t accessors). Older NumPy versions | |
| install on 3.15, so require ``numpy>=2.5`` for abi3t wheels. | |
| * - ``py::dynamic_attr()`` | |
| - supported | |
| - Every instance reserves a ``__dict__`` slot (one pointer) that | |
| ``py::dynamic_attr()`` types use; there is no | |
| ``Py_TPFLAGS_MANAGED_DICT`` in the stable ABI. | |
| * - Buffer protocol | |
| - supported | |
| - Through the ``Py_bf_*`` type slots. | |
| * - ``py::gil_scoped_acquire`` / ``release`` | |
| - supported | |
| - ``PYBIND11_SIMPLE_GIL_MANAGEMENT`` is forced; ``disarm()`` and | |
| thread-state disassociation are not available. | |
| * - ``py::metaclass(handle)`` | |
| - restricted | |
| - The metaclass must not define ``__new__``, and a metaclass less | |
| derived than ``pybind11_type`` resolves to ``pybind11_type``. The | |
| metaclass of every base must be ``pybind11_type`` or a base of the | |
| requested metaclass (``PyType_FromMetaclass()`` rejects a conflict). | |
| * - ``py::custom_type_setup`` | |
| - not available | |
| - Its callback receives a ``PyHeapTypeObject *``, which is opaque. | |
| * - ``pybind11/embed.h`` | |
| - not available | |
| - Embedding uses non-limited initialization functions. | |
| * - ``pybind11/subinterpreter.h`` | |
| - not available | |
| - Reads thread- and interpreter-state fields. | |
| * - ``pybind11/chrono.h`` | |
| - supported | |
| - The ``datetime`` C API is not in the stable ABI; fields are read as | |
| attributes and objects are built by calling the ``datetime`` types. | |
| * - GIL-held assertions (``PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF``) | |
| - not available | |
| - ``PyGILState_Check()`` is not part of the stable ABI. | |
| abi3t | |
| ===== | |
| Under abi3t, ``PyObject`` and ``PyModuleDef`` are incomplete types and | |
| ``PyMutex`` and ``PyUnstable_TryIncRef()`` are not available. pybind11 then: | |
| * stores its per-instance data as :pep:`697` type data | |
| (``PyObject_GetTypeData()``) instead of embedding ``PyObject_HEAD``; | |
| * exports the module through the :pep:`793` ``PyModExport_<name>`` hook | |
| instead of ``PyInit_<name>``, so ``PYBIND11_MODULE`` is unchanged but | |
| ``py::module_::create_extension_module()``, the ``py::module_(name, doc)`` | |
| constructor, and the deprecated ``PYBIND11_PLUGIN`` are not available. If | |
| you restrict exported symbols (a linker version script, | |
| ``-exported_symbols_list``, or a ``.def`` file), export ``PyModExport_*`` | |
| too; | |
| * locks its internals with critical sections on a private object, and keeps | |
| one weak reference per registered instance so that the instance registry | |
| can hand out strong references safely (``PyWeakref_GetRef()``). This weak | |
| reference is visible from Python: ``weakref.getweakrefcount()`` counts it, | |
| and ``weakref.ref(obj)`` without a callback returns that same object. | |
| ``pybind11/numpy.h`` reads NumPy's object fields through the accessors NumPy | |
| 2.5 added for abi3t, so older NumPy versions are rejected at run time. The | |
| internals tag is ``_abi3t``: an abi3t module and an abi3 module loaded | |
| into the same GIL-enabled interpreter do not share internals (see below). | |
| CPython's headers define ``Py_GIL_DISABLED`` for every abi3t build, so the | |
| macro only says that the code must be thread-safe. To know whether the running | |
| interpreter is free-threaded, check at run time, for example with | |
| ``sys._is_gil_enabled()`` or ``sysconfig.get_config_var("Py_GIL_DISABLED")``. | |
| ABI isolation | |
| ============= | |
| A stable-ABI module and a regular module can be loaded in one process, but | |
| they do not share pybind11's internal state: the internals ID carries an | |
| ``_abi3`` or ``_abi3t`` tag identifying the compiled Python ABI target | |
| (:pep:`803`), so each kind of module registers its own types and instances. | |
| Types bound in one kind of module are opaque to the other, except | |
| through the ``pybind11_conduit_v1`` protocol | |
| (``include/pybind11/conduit/README.txt``), which bridges the two: the C++ ABI | |
| is unchanged, so ``PYBIND11_PLATFORM_ABI_ID`` is the same. | |
| Implementation notes and performance | |
| ==================================== | |
| Without access to CPython's struct layouts, pybind11 uses public functions | |
| where it used to read fields directly. The costs are small and are confined | |
| to specific operations: | |
| * Type objects are created with ``PyType_FromMetaclass()`` and | |
| ``PyType_Spec``. This is also the default for regular builds on CPython | |
| 3.12+; define ``PYBIND11_TYPE_CREATION_VIA_SPEC=0`` (CMake: | |
| ``-DPYBIND11_TYPE_CREATION_VIA_SPEC=OFF``) to use the previous path, which | |
| fills in the ``PyHeapTypeObject`` fields directly. Defining | |
| ``PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET`` in a regular build also | |
| selects the previous path, so all bound classes share one dictionary layout. | |
| * Instance allocation and deallocation look up ``tp_alloc``/``tp_free`` with | |
| ``PyType_GetSlot()``; the ``__dict__`` of ``py::dynamic_attr()`` instances | |
| is a fixed slot in the instance layout. | |
| * Attribute *assignment* on bound classes (``Type.static_prop = value``) walks | |
| ``__mro__`` and the class dictionaries instead of using ``_PyType_Lookup()``; | |
| attribute reads use the metaclass default and are not affected. | |
| * Methods are bound through a pybind11-provided ``instancemethod`` type and | |
| ``types.MethodType`` instead of ``PyInstanceMethod_Type`` / | |
| ``PyMethod_New()``. | |
| * Tuple and list element access uses the checked function forms; type names | |
| in error messages are reconstructed from ``__module__`` and ``__name__``. | |
| * ``py::eval``/``py::exec`` compile with ``Py_CompileString()`` and run with | |
| ``PyEval_EvalCode()``; ``py::eval_file`` reads the file through Python. | |
| Modules built for the stable ABI check the interpreter version at import: | |
| any CPython from the targeted version on is accepted. |