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
174 changes: 174 additions & 0 deletions docs/how-to-guides/limited-api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
.. SPDX-FileCopyrightText: 2026 The meson-python developers
..
.. SPDX-License-Identifier: MIT

.. _howto-limited-api:

***********************************
Targeting the CPython Limited C API
***********************************

This page describes how to configure your package to build against the
CPython `limited API`_ and build `stable ABI`_ wheels. Limited API builds
target a minimum interpreter version and produce a single wheel that
can support newer interpreter versions.

You can enable limited API builds by default or make them opt-in.
If your package does not yet use the limited API, we recommend making
limited API builds opt-in so you can transition to stable ABI wheels
gradually or distribute stable ABI wheels only on selected platforms.

Compile your extension modules for the limited API by specifying the
``limited_api`` argument to the ``extension_module()`` function in the
Meson Python module. The version passed to ``limited_api`` selects
the limited API your extension uses. Meson converts this version to
the corresponding value of the ``Py_LIMITED_API`` preprocessor macro.

The wheel's :ref:`Python compatibility tag <limited-api-wheel-tags>`
still corresponds to the interpreter used for the build, regardless of
the ``limited_api`` version you select.

Enabling the
:option:`tool.meson-python.limited-api` setting declares that all the
extension modules in your package target the limited API and adjusts the
wheel filename ABI tag accordingly:

.. code-block:: meson

py = import('python').find_installation(pure: false)

py.extension_module(
'_core',
'_core.c',
limited_api: '3.10',
install: true,
subdir: 'example',
)

.. code-block:: toml

[tool.meson-python]
limited-api = true


For limited API builds, on platforms where Python extension modules
targeting the stable ABI use a dedicated filename suffix, ``meson-python``
verifies that all the extension modules included in the wheel use the
stable ABI filename suffix and fails the build otherwise.


.. _opt-in-limited-api-example:

Set up Limited API support as opt-in
------------------------------------

To make limited API builds opt-in, add
``python.allow_limited_api=false`` to the ``default_options`` in your
existing ``project()`` call in ``meson.build``:

.. code-block:: meson

project(
'example',
'c',
default_options: ['python.allow_limited_api=false'],
)

Keep ``limited-api = true`` in ``pyproject.toml`` and the ``limited_api``
argument to ``extension_module()`` as shown above. When
``python.allow_limited_api`` is false, Meson ignores the ``limited_api``
argument, compiles extension modules for the ABI of the interpreter
used for the build, and produces a wheel tagged as compatible with
the build interpreter.

To build a stable ABI wheel, explicitly enable limited API builds:

.. tab-set::

.. tab-item:: pypa/build
:sync: key_pypa_build

.. code-block:: console

$ python -m build --wheel -Csetup-args="-Dpython.allow_limited_api=true" .

.. tab-item:: pip
:sync: key_pip

.. code-block:: console

$ python -m pip wheel -Csetup-args="-Dpython.allow_limited_api=true" .


.. _limited-api-wheel-tags:

Limited API compatibility
-------------------------

``meson-python`` conservatively chooses the wheel's Python compatibility
tag based only on the interpreter used for the build, regardless of the
target ``limited_api`` version. For example, a wheel built with CPython
3.12 for the 3.10 limited API is tagged ``cp312-abi3`` and can be
installed only on GIL-enabled CPython 3.12 and later. When building
stable ABI wheels for distribution, for example on PyPI, build with the
oldest CPython version you want the wheel to support, as `recommended by
CPython`_. If you are installing from source into a particular
environment, use that environment's interpreter; you do not need to
build with the oldest supported version.

PyPy supports the limited API, but does not implement a stable ABI, thus
the :option:`tool.meson-python.limited-api` setting has no effect on the
wheel tags when building with PyPy.


The ``abi3t`` stable ABI
------------------------

CPython 3.15 introduces the ``abi3t`` stable ABI, see
the `abi3t migration guide`_. Extension modules built for ``abi3t``
can be loaded by both the GIL-enabled and the free-threaded builds of
CPython 3.15 and later: a single wheel tagged ``abi3.abi3t`` supports
all CPython interpreters from version 3.15 on.

``abi3t`` extension modules require limited API version 3.15 or later
and, currently, a free-threaded interpreter for the build: compiling
for ``abi3t`` with a GIL-enabled interpreter is not supported yet.
Nothing else is required: the CPython headers select ``abi3t`` when
``Py_LIMITED_API`` is defined while compiling for a free-threaded
interpreter.

Meson refuses a ``limited_api`` version newer than the interpreter
used for the build. If you build ``abi3`` wheels for older
CPython versions and ``abi3.abi3t`` wheels for CPython 3.15 and later,
you can select the limited API version by querying the ``Py_GIL_DISABLED``
sysconfig variable, which is 1 for free-threaded builds:

.. code-block:: meson

py = import('python').find_installation(pure: false)

limited_api = '3.10'
if py.language_version().version_compare('>=3.15')
if py.get_variable('Py_GIL_DISABLED') == 1
limited_api = '3.15'
endif
endif

py.extension_module(
'_core',
'_core.c',
limited_api: limited_api,
install: true,
subdir: 'example',
)

Free-threaded CPython 3.13 and 3.14 do not support the limited API:
disable limited API builds when using these interpreters.
The :ref:`opt-in configuration above <opt-in-limited-api-example>`
disables them by default.

.. _limited API: https://docs.python.org/3/c-api/stable.html#limited-c-api
.. _stable ABI: https://docs.python.org/3/c-api/stable.html#stable-application-binary-interface
.. _recommended by CPython: https://docs.python.org/3/c-api/stable.html#limited-api-caveats
.. _improve performance: https://docs.python.org/3/c-api/stable.html#limited-api-scope-and-performance
.. _abi3t migration guide: https://docs.python.org/3.15/howto/abi3t-migration.html
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ the use of ``meson-python`` and Meson for Python packaging.
how-to-guides/meson-args
how-to-guides/debug-builds
how-to-guides/shared-libraries
how-to-guides/limited-api
reference/limitations
projects-using-meson-python

Expand Down
11 changes: 6 additions & 5 deletions docs/reference/pyproject-settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ use them and examples.
modules can be compiled for the Python limited API specifying the
``limited_api`` argument to the |extension_module()|_ function
in the Meson Python module. When this setting is set to true, the
value ``abi3`` is used for the Python wheel filename ABI tag.

This setting is automatically reverted to false when the
Python wheel filename ABI tag is set to ``abi3``, or ``abi3.abi3t``
when building with free-threaded CPython 3.15 or later. This
setting is automatically reverted to false when the
``-Dpython.allow_limited_api=false`` option is passed to ``meson
setup``.
setup``. See :ref:`howto-limited-api` for more information on limited
API builds.

.. option:: tool.meson-python.meson

Expand Down Expand Up @@ -91,7 +92,7 @@ use them and examples.
glob pattern is useful exclusively to limit the effect of an exclude
pattern that matches too many files.

.. _python limited api: https://docs.python.org/3/c-api/stable.html?highlight=limited%20api#stable-application-binary-interface
.. _python limited api: https://docs.python.org/3/c-api/stable.html#stable-application-binary-interface
.. _extension_module(): `https://mesonbuild.com/Python-module.html#extension_module
.. _meson introspection data: https://mesonbuild.com/IDE-integration.html#install-plan

Expand Down