PEP 652: Maintaining the Stable ABI (#1810)
This commit is contained in:
parent
c19863770f
commit
4e2254a52a
|
@ -0,0 +1,462 @@
|
||||||
|
PEP: 652
|
||||||
|
Title: Maintaining the Stable ABI
|
||||||
|
Author: Petr Viktorin <encukou@gmail.com>
|
||||||
|
Discussions-To: https://discuss.python.org/t/pre-pep-maintaining-the-stable-abi/6986/
|
||||||
|
Status: Draft
|
||||||
|
Type: Standards Track
|
||||||
|
Content-Type: text/x-rst
|
||||||
|
Created: 09-Feb-2021
|
||||||
|
Python-Version: 3.10
|
||||||
|
|
||||||
|
|
||||||
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
|
CPython's Limited C-API and Stable ABI, introduced in :pep:`384`,
|
||||||
|
will be formalized in a single definitive file, tested, and documented.
|
||||||
|
|
||||||
|
|
||||||
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
|
:pep:`384` defined a Limited API and Stable ABI, which allow extenders and
|
||||||
|
embedders of CPython to compile extension modules that are binary-compatible
|
||||||
|
with any subsequent version of 3.x.
|
||||||
|
In theory, this brings several advantages:
|
||||||
|
|
||||||
|
* A module can be built only once per platform and support multiple versions
|
||||||
|
of Python, reducing time, power and maintainer attention needed for builds
|
||||||
|
(in exchange for potentially worse performance).
|
||||||
|
|
||||||
|
* Binary wheels using the Stable ABI work with new versions of CPython
|
||||||
|
throughout the pre-release period, and can be tested in environments where
|
||||||
|
building from source is not practical.
|
||||||
|
|
||||||
|
* As a welcome side effect of the Limited API's hiding of implementation
|
||||||
|
details, this API is becoming a viable target for alternate Python
|
||||||
|
implementations that would be incompatible with the full C API.
|
||||||
|
|
||||||
|
However, in hindsight, PEP 384 and its implementation has several issues:
|
||||||
|
|
||||||
|
* It is ill-defined. According to PEP 384, functions are *opt-out*:
|
||||||
|
all functions not specially marked are part of the Stable ABI.
|
||||||
|
In practice, for Windows there's a list that's *opt-in*.
|
||||||
|
For users there is a ``#define`` that should make only the Stable ABI
|
||||||
|
available, but there is no process that ensures it is kept up-to date.
|
||||||
|
Neither is there a process for updating the documentation.
|
||||||
|
* Until recently, the Stable ABI was not tested at all. It tends to break.
|
||||||
|
For example, changing a function to a macro can break the Stable ABI as the
|
||||||
|
function symbol is removed.
|
||||||
|
* There is no way to deprecate parts of the Limited API.
|
||||||
|
* It is incomplete. Some operations are not available in the Stable ABI,
|
||||||
|
with little reason except "we forgot".
|
||||||
|
(This last point is one the PEP will not help with, however.)
|
||||||
|
|
||||||
|
This PEP defines the Limited API more clearly and introducess process
|
||||||
|
designed to make the Stable ABI and Limited API more useful and robust.
|
||||||
|
|
||||||
|
|
||||||
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
|
This PEP contains a lot of clarifications and definitions, but just one big
|
||||||
|
technical change: the Stable ABI will be explicitly listed in
|
||||||
|
a human-maintained “manifest” file.
|
||||||
|
|
||||||
|
There have been efforts to collect such lists automatically, e.g. by scanning
|
||||||
|
the symbols exported from Python.
|
||||||
|
Such automation might seem easier to maintain than a handcrafted file,
|
||||||
|
but has major issues: for example, the set exported symbols has
|
||||||
|
platform-specific variations.
|
||||||
|
Also, the cost of updating an explicit manifest is small compared
|
||||||
|
to the overall work that should go into changing API that will need to
|
||||||
|
be suppported forever (or until Python 3 reaches end of life, if that
|
||||||
|
comes sooner).
|
||||||
|
|
||||||
|
This PEP proposes automatically generating things *from* the manifest:
|
||||||
|
initially documentation and DLL contents, with later possibilities
|
||||||
|
for also automating tests.
|
||||||
|
|
||||||
|
|
||||||
|
Stable ABI vs. Limited API
|
||||||
|
==========================
|
||||||
|
|
||||||
|
:pep:`384` and this document deal with the *Limited API* and the *Stable ABI*,
|
||||||
|
two related but distinct concepts. In short:
|
||||||
|
|
||||||
|
* The *Stable ABI* is a promise that certain extensions compiled with
|
||||||
|
CPython 3.x will be binary compatible with all subsequent versions
|
||||||
|
of CPython 3.x.
|
||||||
|
* The *Limited API* is a subset of CPython's C API that produces such extensions.
|
||||||
|
|
||||||
|
This section clarifies these terms and defines some of their semantics
|
||||||
|
(either pre-existing or newly proposed here).
|
||||||
|
|
||||||
|
The word “Extensions” is used as a shorthand for all code that uses the
|
||||||
|
Python API, e.g. extension modules or software that embeds Python.
|
||||||
|
|
||||||
|
|
||||||
|
Stable ABI
|
||||||
|
----------
|
||||||
|
|
||||||
|
The CPython *Stable ABI* is a promise that extensions built against
|
||||||
|
a specific Stable ABI version will be compatible with any newer
|
||||||
|
interpreter of the same major version.
|
||||||
|
|
||||||
|
The Stable ABI does not define a complete binary interface:
|
||||||
|
important details like the layout of structures in memory or function
|
||||||
|
calling conventions are determined by the platform and the compiler and
|
||||||
|
its settings.
|
||||||
|
The Stable ABI promise only applies if these lower-details are also stable.
|
||||||
|
|
||||||
|
For example, an extension built with the CPython 3.10 Stable ABI will be usable
|
||||||
|
with CPython 3.11, 3.12, etc.
|
||||||
|
It will not necessarily be compatible with CPython 4.0, nor with CPython 3.10
|
||||||
|
on a different platform.
|
||||||
|
|
||||||
|
The Stable ABI is not generally forward-compatible: an extension built and
|
||||||
|
tested with CPython 3.10 will not generally be compatible with CPython 3.9.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
For example, starting in Python 3.10, the ``Py_tp_doc`` slot may be set to
|
||||||
|
``NULL``, while in older versions, a ``NULL`` value will likely crash the
|
||||||
|
interpreter.
|
||||||
|
|
||||||
|
The Stable ABI trades performance for its stability.
|
||||||
|
For example, extensions built for a specific CPython version will automatically
|
||||||
|
use faster macros instead of functions in the Stable ABI.
|
||||||
|
|
||||||
|
Future Python versions may deprecate some members of the Stable ABI.
|
||||||
|
Deprecated members will still work, but may suffer from issues like reduced
|
||||||
|
performance or, in the most extreme cases, memory/resource leaks.
|
||||||
|
|
||||||
|
Limited API
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The Stable ABI promise holds for extensions compiled from code that restricts
|
||||||
|
itself to the *Limited API* (application programming interface).
|
||||||
|
The Limited API is a subset of CPython's C API.
|
||||||
|
|
||||||
|
Extensions that target the Limited API should define the preprocessor macro
|
||||||
|
``Py_LIMITED_API`` to either ``3`` or the current ``PYTHON_API_VERSION``.
|
||||||
|
This will enable Stable ABI versions of several functions and limit definitions
|
||||||
|
to the Limited API.
|
||||||
|
(However, note that the macro is not perfect: due to technical issues or
|
||||||
|
oversights, some non-limited API might be exposed even with it defined.)
|
||||||
|
|
||||||
|
The Limited API is not guaranteed to be *stable*.
|
||||||
|
In the future, parts of the Limited API may be deprecated.
|
||||||
|
They may even be removed, as long as the *Stable ABI* is kept
|
||||||
|
stable and Python's general backwards compatibility policy, :pep:`387`,
|
||||||
|
is followed.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
For example, a function declaration might be removed from public header
|
||||||
|
files but kept in the library.
|
||||||
|
This is currently a possibility for the future; this PEP does not to propose
|
||||||
|
a concrete process for deprecations and removals.
|
||||||
|
|
||||||
|
The goal for the Limited API is to cover everything needed to interact
|
||||||
|
with the interpreter.
|
||||||
|
The main reason to not include a public API in the Limited subset
|
||||||
|
should be that it needs implementation details that change between CPython
|
||||||
|
versions (like struct memory layouts) – usually for performance reasons.
|
||||||
|
|
||||||
|
The Limited API is not limited to CPython. Other implementations are
|
||||||
|
encouraged to implement it and help drive its design.
|
||||||
|
|
||||||
|
|
||||||
|
Specification
|
||||||
|
=============
|
||||||
|
|
||||||
|
To make the Stable ABI more useful and robust, the following changes
|
||||||
|
are proposed.
|
||||||
|
|
||||||
|
|
||||||
|
Stable ABI Manifest
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
All members of the Stable ABI – functions, typedefs, structs, data, macros,
|
||||||
|
and constants – will be explicitly listed in a single "manifest" file,
|
||||||
|
``Misc/stable_abi.txt``.
|
||||||
|
|
||||||
|
For structs, any fields that users of the Stable ABI are allowed to access
|
||||||
|
will be listed explicitly.
|
||||||
|
|
||||||
|
The manifest will also serve as the definitive list of the Limited API.
|
||||||
|
Members that are not part of the Limited API, but are part of the Stable ABI
|
||||||
|
(e.g. ``PyObject.ob_type``, which is accessible by the ``Py_TYPE`` macro),
|
||||||
|
will be annotated as such.
|
||||||
|
|
||||||
|
For items that are only available on some systems, the manifest will record the
|
||||||
|
feature macro that determines their presence (such as ``MS_WINDOWS`` or
|
||||||
|
``HAVE_FORK``).
|
||||||
|
To make the implementation (and usage from non-C languages) easier,
|
||||||
|
all such macros will be simple names.
|
||||||
|
If a future item needs a “negative” macro or complex expression (such as a
|
||||||
|
hypothetical ``#ifndef MACOSX`` or ``#if defined(POSIX) && !defined(LINUX)``),
|
||||||
|
a new feature macro will be derived.
|
||||||
|
|
||||||
|
The format of the manifest will be subject to change whenever needed.
|
||||||
|
It should be consumed only by scripts in the CPython repository.
|
||||||
|
If a stable list is needed, a script can be added to generate it.
|
||||||
|
|
||||||
|
The following wil be generated from the ABI manifest:
|
||||||
|
|
||||||
|
* Source for the Windows shared library, ``PC/python3dll.c``.
|
||||||
|
* Input for documentation (see below).
|
||||||
|
* Test case that checks the runtime availablility of symbols (see below).
|
||||||
|
|
||||||
|
The following will be checked against the Stable ABI manifest as part of
|
||||||
|
continuous integration:
|
||||||
|
|
||||||
|
* The reference count summary, ``Doc/data/refcounts.txt``, includes all
|
||||||
|
function in the Stable ABI (among others).
|
||||||
|
* The functions/structs declared and constants/macros defined
|
||||||
|
when ``Python.h`` is included with ``Py_LIMITED_API`` set.
|
||||||
|
(Initially Linux only; checks on other systems may be added in the future.)
|
||||||
|
|
||||||
|
After the initial implementation, details such as function arguments will be
|
||||||
|
added and the manifest will be checked for internal consistency (e.g. all
|
||||||
|
types used in function signatures are part of the API).
|
||||||
|
|
||||||
|
|
||||||
|
Contents of the Stable ABI
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
The initial Stable ABI manifest will include:
|
||||||
|
|
||||||
|
* The Stable ABI specified in :pep:`384`.
|
||||||
|
* Everything listed in ``PC/python3dll.c``.
|
||||||
|
* All structs (struct typedefs) which these functions return or take as
|
||||||
|
arguments. (Fields of such structs will not necessarily be added.)
|
||||||
|
* New type slots, such as ``Py_am_aiter``.
|
||||||
|
* The type flags ``Py_TPFLAGS_DEFAULT``, ``Py_TPFLAGS_BASETYPE``,
|
||||||
|
``Py_TPFLAGS_HAVE_GC``, ``Py_TPFLAGS_METHOD_DESCRIPTOR``.
|
||||||
|
* The calling conventions ``METH_*`` (except deprecated ones).
|
||||||
|
* All API needed by macros is the Stable ABI (annotated as not being part of
|
||||||
|
the Limited API).
|
||||||
|
|
||||||
|
Items that are no longer in CPython when this PEP is accepted will be removed
|
||||||
|
from the list.
|
||||||
|
|
||||||
|
Additional items may be aded to the initial manifest according to
|
||||||
|
the checklist below.
|
||||||
|
|
||||||
|
|
||||||
|
Documenting the Limited API
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Notes saying “Part of the Limited API” will be added to Python's documentation
|
||||||
|
automatically, in a way similar to the notes on functions that return borrowed
|
||||||
|
references.
|
||||||
|
|
||||||
|
A complete list of all members of the Limited API will also be added to
|
||||||
|
the documentation.
|
||||||
|
|
||||||
|
|
||||||
|
Testing the Stable ABI
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
An automatically generated test module will be added to ensure that all symbols
|
||||||
|
included in the Stable ABI are available at compile time.
|
||||||
|
|
||||||
|
|
||||||
|
Changing the Limited API
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
A checklist for changing the Limited API, including adding new items to it
|
||||||
|
and removing existing ones, will be added to the `Devguide`_.
|
||||||
|
The checklist will 1) mention best practices and common pitfalls in Python
|
||||||
|
C API design and 2) guide the developer around the files that need changing and
|
||||||
|
scripts that need running when the Limited API is changed.
|
||||||
|
|
||||||
|
Below is the initial proposal for the checklist.
|
||||||
|
(After the PEP is accepted, see the Devguide for the current version.)
|
||||||
|
|
||||||
|
Note that the checklist applies to new changes; several items
|
||||||
|
in the *existing* Limited API are grandfathered and couldn't be added today.
|
||||||
|
|
||||||
|
Design considerations:
|
||||||
|
|
||||||
|
* Make sure the change does not break the Stable ABI of any version of Python
|
||||||
|
since 3.5.
|
||||||
|
* Make sure no exposed names are private (i.e. begin with an underscore).
|
||||||
|
* Make sure the new API is well documented.
|
||||||
|
* Make sure the types of all parameters and return values of the added
|
||||||
|
function(s) and all fields of the added struct(s) are be part of the
|
||||||
|
Limited API (or standard C).
|
||||||
|
|
||||||
|
* Make sure the new API and its intended use follows standard C, not just
|
||||||
|
features of currently supported platforms.
|
||||||
|
Specifically, follow the C dialect specified in :pep:`7`.
|
||||||
|
|
||||||
|
* Do not cast a function pointer to ``void*`` (a data pointer) or vice versa.
|
||||||
|
|
||||||
|
* Make sure the new API follows reference counting conventions. (Following them
|
||||||
|
makes the API easier to reason about, and easier use in other Python
|
||||||
|
implementations.)
|
||||||
|
|
||||||
|
* Do not return borrowed references from functions.
|
||||||
|
* Do not steal references to function arguments.
|
||||||
|
|
||||||
|
* Make sure the ownership rules and lifetimes of all applicable struct fields,
|
||||||
|
arguments and return values are well defined.
|
||||||
|
* Think about ease of use for the user. (In C, ease of use itself is not very
|
||||||
|
important; what *is* useful is reducing boilerplate code needed to use the
|
||||||
|
API. Bugs like to hide in boiler plates.)
|
||||||
|
|
||||||
|
* If a function will be often called with specific value for an argument,
|
||||||
|
consider making it default (used when ``NULL`` is passed in).
|
||||||
|
|
||||||
|
* Think about future extensions: for example, if it's possible that future
|
||||||
|
Python versions will need to add a new field to your struct,
|
||||||
|
how will that be done?
|
||||||
|
|
||||||
|
* Make as few assumptions as possible about details that might change in
|
||||||
|
future CPython versions or differ across C API implementations:
|
||||||
|
|
||||||
|
* The GIL
|
||||||
|
* Garbage collection
|
||||||
|
* Memory layout of PyObject, lists/tuples and other structures
|
||||||
|
|
||||||
|
If following these guidelines would hurt performance, add a fast function
|
||||||
|
(or macro) to the non-limited API and a stable equivalent to the Limited API.
|
||||||
|
|
||||||
|
If anything is unclear, or you have a good reason to break the guidelines,
|
||||||
|
consider discussing the change at the `capi-sig`_ mailing list.
|
||||||
|
|
||||||
|
.. _capi-sig: https://mail.python.org/mailman3/lists/capi-sig.python.org/
|
||||||
|
|
||||||
|
Procedure:
|
||||||
|
|
||||||
|
* Move the declaration to a header file directly under ``Include/``, into a
|
||||||
|
``#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03yy0000`` block
|
||||||
|
(with the ``yy`` corresponding to the target CPython version).
|
||||||
|
* Make an entry in the Stable ABI manifest, ``Misc/stable_abi.txt``.
|
||||||
|
* Regenerate the autogenerated files using ``make regen-all``.
|
||||||
|
(or the alternative for non-``make`` platforms)
|
||||||
|
* Build Python and run checks using ``make check-abi``.
|
||||||
|
(or the alternative for non-``make`` platforms)
|
||||||
|
|
||||||
|
|
||||||
|
Advice for Extenders and Embedders
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
The following notes will be added to documentation.
|
||||||
|
|
||||||
|
Extension authors should test with all Python versions they support,
|
||||||
|
and preferably build with the lowest such version.
|
||||||
|
|
||||||
|
Compiling with ``Py_LIMITED_API`` defined is *not* a guarantee that your code
|
||||||
|
conforms to the Limited API or the Stable ABI.
|
||||||
|
``Py_LIMITED_API`` only covers definitions, but an API also includes other
|
||||||
|
issues, such as expected semantics.
|
||||||
|
|
||||||
|
Examples of issues that ``Py_LIMITED_API`` does not guard against are:
|
||||||
|
|
||||||
|
* Calling a function with invalid arguments
|
||||||
|
* A function that started accepting ``NULL`` values for an argument
|
||||||
|
in Python 3.9 will fail if ``NULL`` is passed to it under Python 3.8.
|
||||||
|
Only testing with 3.8 (or lower versions) will uncover this issue.
|
||||||
|
* Some structs include a few fields that are part of the Stable ABI and other
|
||||||
|
fields that aren't.
|
||||||
|
``Py_LIMITED_API`` does not filter out such “private” fields.
|
||||||
|
* Code that uses something that is not documented as part of the Stable ABI,
|
||||||
|
but exposed even with ``Py_LIMITED_API`` defined, may break in the future.
|
||||||
|
Despite the team's best efforts, such issues may happen.
|
||||||
|
|
||||||
|
|
||||||
|
Note for Redistributors of Python
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
The Stable ABI promise relies on stable underlying ABI details, such as the
|
||||||
|
layout of structures in memory and function calling conventions, which
|
||||||
|
are affected by the compiler and its settings.
|
||||||
|
For the promise to hold, these details must not change between CPython 3.x
|
||||||
|
releases on a particular platform.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Backwards Compatibility
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Backwards compatibility is one honking great idea!
|
||||||
|
|
||||||
|
This PEP aims at full compatibility with the existing Stable ABI and Limited
|
||||||
|
API, but defines them terms more explicitly.
|
||||||
|
It might not be consistent with some interpretations of what the existing
|
||||||
|
Stable ABI/Limited API is.
|
||||||
|
|
||||||
|
|
||||||
|
Security Implications
|
||||||
|
=====================
|
||||||
|
|
||||||
|
None known.
|
||||||
|
|
||||||
|
|
||||||
|
How to Teach This
|
||||||
|
=================
|
||||||
|
|
||||||
|
Technical documentation will be provided in ``Doc/c-api/stable``
|
||||||
|
and linked from the *What's New* document.
|
||||||
|
Docs for CPython core developers will be added to the devguide.
|
||||||
|
|
||||||
|
|
||||||
|
Reference Implementation
|
||||||
|
========================
|
||||||
|
|
||||||
|
Nothing presentable yet.
|
||||||
|
|
||||||
|
|
||||||
|
Ideas for the Future
|
||||||
|
====================
|
||||||
|
|
||||||
|
The following issues are out of scope of this PEP, but show possible
|
||||||
|
future directions.
|
||||||
|
|
||||||
|
Defining a process for deprecations/removals
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
While this PEP acknowledges that parts of the Limited API might be deprecated
|
||||||
|
or removed in the future, a process to do this is not in scope, and is left
|
||||||
|
to a possible future PEP.
|
||||||
|
|
||||||
|
|
||||||
|
C syntax for the ABI manifest
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
It might be useful to have the ABI manifest be a C header file, or to
|
||||||
|
generate header files from the manifest.
|
||||||
|
Again, either are options for the future.
|
||||||
|
|
||||||
|
|
||||||
|
Open Issues
|
||||||
|
===========
|
||||||
|
|
||||||
|
None so far.
|
||||||
|
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. _Devguide: https://devguide.python.org/
|
||||||
|
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
|
This document is placed in the public domain or under the
|
||||||
|
CC0-1.0-Universal license, whichever is more permissive.
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
|
Local Variables:
|
||||||
|
mode: indented-text
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
sentence-end-double-space: t
|
||||||
|
fill-column: 70
|
||||||
|
coding: utf-8
|
||||||
|
End:
|
Loading…
Reference in New Issue