C API ABI 的稳定性

除非另有文档说明,Python 的 C API 将遵循 PEP 387 所描述的向下兼容策略。 对它的大部分改变都是源代码级兼容的(通常只会增加新的 API)。改变现有 API 或移除 API 只会在弃用期结束之后或需修复严重问题时才会发生。

CPython 的应用程序二进制接口(ABI)可以跨微版本向上和向下兼容(在以相同方式编译的情况下,参见下文 平台的考虑 一节)。因此,针对 Python 3.10.0 编译的代码将适用于 3.10.8,反之亦然,但对于 3.9.x 和 3.11.x 则需要单独编译。

存在具有不同稳定性预期的两个 C API 层次:

  • 不稳定 API,可能在次要版本中发生改变而没有弃用期。它的名称会以 PyUnstable 前缀来标记。

  • 受限 API,将会在多个次要版本间保持兼容。当定义了 Py_LIMITED_API 时,将只有这个子集会从 Python.h 对外公开。

这些将在下文中更详细地讨论。

带有一个下划线前缀的名称,如 _Py_InternalState,是可能不经通知就改变甚至是在补丁发布版中改变的私有 API。 如果你需要使用这样的 API,请考虑联系 CPython 开发团队 来讨论为你的应用场景添加公有 API。

不稳定 C API

任何名称带有 PyUnstable 前缀的 API 都将对外公开 CPython 的实现细节,并可能不加弃用警告即在次要版本中发生改变(例如从 3.9 到 3.10)。但是,它不会在问题修正发布版中改变(例如从 3.10.0 到 3.10.1)。

它通常是针对专门的,低层级的工具如调试器等。

使用此 API 的项目需要跟随 CPython 开发进程并花费额外的努力来适应改变。

稳定应用程序二进制接口

Python 的 稳定 ABI 允许扩展在不重新编译的情况下兼容多个 Python 版本。

备注

为简单起见,本文档会讨论 扩展,但稳定 ABI 对 API 的所有使用方式都同样适用 —— 例如嵌入 Python。

有两种稳定 ABI:

  • abi3 于 Python 3.2 中引入,兼容 CPython 的 自由线程 构建。

  • abi3t 于 Python 3.15 中引入,兼容 CPython 的 自由线程 构建。它具有比 abi3 更严格的 API 限制。

    Added in version 3.15: abi3t 是在 PEP 803 中添加的

扩展可以同时针对 abi3abi3t 二者 进行编译;其结果将同时兼容 Python 的自由线程构建和非自由线程构建。目前,与仅针对 abi3t 编译相比,这样做没有缺点。

每个稳定 ABI 都使用 Python 版本号的前两个数字作为版本号。例如,稳定 ABI 3.14 对应 Python 3.14。针对稳定 ABI 3.x 编译的扩展与 Python 3.x 及更高版本保持 ABI 兼容。

以稳定 ABI 为目标的扩展只能使用 C API 的一个受限子集。该子集称为 受限 API;其内容在 下文列出

在 Windows 上,使用稳定 ABI 的扩展应当链接到 python3.dll,而不是链接到版本专属库,例如 python39.dll。这个库只会公开相关符号。

在某些平台上,Python 会查找并加载名称带有 abi3abi3t 标签的共享库文件(例如 mymodule.abi3.so)。自由线程 解释器只识别 abi3t 标签,而非自由线程解释器会优先使用 abi3,但会回退到 abi3t。因此,同时兼容这两种 ABI 的扩展应使用 abi3t 标签。

Python 不一定会检查它所加载的扩展是否具有兼容的 ABI。建议扩展作者使用 Py_mod_abi 槽位或 PyABIInfo_Check() 函数添加检查,但用户(或其打包工具)最终需要负责确保,例如,针对稳定 ABI 3.10 构建的扩展不会被安装到更低版本的 Python 中。

稳定 ABI 中的所有函数都以函数的形式存在于 Python 的共享库中,而不是仅以宏的形式存在。这使得它们可用于不使用 C 预处理器的语言,包括 Python 的 ctypes

针对稳定 ABI 编译

备注

构建工具(例如 meson-python、scikit-build-core 或 Setuptools)通常具有用于设置宏,并将这些宏与扩展文件名和其他元数据同步的机制。如果存在这样的机制,应优先使用它,而不是手动定义宏。

本节的其余部分主要与工具作者以及手动编译扩展的人相关。

参见

Python 打包用户指南中的 推荐工具列表

要针对稳定 ABI 编译,请将以下一个或两个宏定义为你的扩展应支持的最低 Python 版本,格式为 Py_PACK_VERSION。通常,你应选择一个具体值,而不是正在用于编译的 Python 头文件版本。

这些宏必须在包含 Python.h 之前定义。由于此时 Py_PACK_VERSION 尚不可用,你需要直接使用数值。作为参考,几个较新 Python 版本对应的值如下:

0x30b0000  /* Py_PACK_VERSION(3.11) */
0x30c0000  /* Py_PACK_VERSION(3.12) */
0x30d0000  /* Py_PACK_VERSION(3.13) */
0x30e0000  /* Py_PACK_VERSION(3.14) */
0x30f0000  /* Py_PACK_VERSION(3.15) */
0x3100000  /* Py_PACK_VERSION(3.16) */

当定义其中一个宏时,Python.h 将只公开与给定稳定 ABI 兼容的 API —— 即 受限 API,以及一些需要对编译器可见、但不应直接使用的定义。当二者都被定义时,Python.h 将只公开同时兼容这两种稳定 ABI 的 API。

Py_LIMITED_API

目标为 abi3,也就是 CPython 的非 自由线程构建。 通用信息请参见 上文

Py_TARGET_ABI3T

目标为 abi3t,也就是 CPython 的 自由线程构建。通用信息请参见 上文

Added in version 3.15.

这两个宏都会指定一个目标 ABI;命名风格不同是出于向后兼容。

历史说明

你也可以将 Py_LIMITED_API 定义为 3。 这与 0x03020000 (Python 3.2,即引入稳定 ABI 的版本) 的作用相同。

当二者都被定义时,Python.h 可能会,也可能不会,重新定义 Py_LIMITED_API 以匹配 Py_TARGET_ABI3T

自由线程构建 上 —— 也就是定义了 Py_GIL_DISABLED 时 —— Py_TARGET_ABI3T 默认取 Py_LIMITED_API 的值。这意味着有两种方式可以同时针对 abi3abi3t 构建:

  • 同时定义 Py_LIMITED_APIPy_TARGET_ABI3T,或者

  • 只定义 Py_LIMITED_API,并且:

    • 在 Windows 上,定义 Py_GIL_DISABLED

    • 在其他系统上,使用 Python 自由线程构建的头文件。

稳定 ABI 的范围与性能

稳定 ABI 的目标是允许完成完整 C API 能做到的所有事情,但可能会带来性能损失。通常,与稳定 ABI 兼容会要求对扩展的源代码做出一些修改。

例如,虽然 PyList_GetItem() 可用,但它的“非安全”宏变体 PyList_GET_ITEM() 不可用。该宏可能更快,因为它可以依赖列表对象的版本专属实现细节。

再举一例,当 针对稳定 ABI 编译时,某些 C API 函数会被内联或被宏替换。针对稳定 ABI 编译会禁用这种内联,使其在 Python 的数据结构得到改进时仍保持稳定,但可能会降低性能。

通过省略 Py_LIMITED_APIPy_TARGET_ABI3T 定义,可以将与稳定 ABI 兼容的源代码编译为版本专属 ABI。这样就可以将一个可能更快的版本专属扩展,与一个针对稳定 ABI 编译的版本一同分发 —— 后者较慢,但兼容性更好,可作为回退方案。

稳定 ABI 注意事项

请注意,针对稳定 ABI 编译 并不 完全保证代码会与预期的 Python 版本兼容。稳定 ABI 防止的是 ABI 问题,例如因缺少符号导致的链接器错误,或因结构体布局或函数签名改变导致的数据损坏。然而,Python 中的其他改变可能会改变扩展的 行为

有一个问题是 Py_TARGET_ABI3TPy_LIMITED_API 宏无法防范的:使用在较低 Python 版本中无效的参数来调用函数。例如,假设某个函数开始接受 NULL 作为参数。在 Python 3.9 中,NULL 现在会选择一种默认行为,但在 Python 3.8 中,该参数会被直接使用,从而导致 NULL 解引用并崩溃。结构体字段也存在类似情况。

由于这些原因,我们建议使用扩展所支持的 所有 Python 次要版本来测试该扩展。

我们还建议查看所使用 API 的全部文档以检查其是否显式指明为受限 API 的一部分。即使定义了 Py_LIMITED_API,少数私有声明还是会出于技术原因(或者甚至是作为程序缺陷在无意中)被暴露出来。

还要注意,虽然使用 Py_LIMITED_API 3.8 编译意味着扩展应当能在 Python 3.12 上 加载,也能使用 Python 3.12 编译,但同一份源代码不一定能在将 Py_LIMITED_API 设为 3.12 时完成编译。通常,只要稳定 ABI 保持稳定,受限 API 的某些部分可能会被弃用并移除。

平台的考虑

ABI 稳定性不仅取决于 Python,还取决于所使用的编译器、底层库和编译器选项。就 稳定 ABI 而言,这些细节定义了一个“平台”。它们通常取决于操作系统类型和处理器架构

每个特定的 Python 分发方都有责任确保特定平台上的所有 Python 版本都以不会破坏稳定 ABI 或版本专属 ABI 的方式构建。来自 python.org 的 Windows 和 macOS 发布版以及许多第三方分发版就是这种情况。

ABI 检查

Added in version 3.15.

Python 包含一种基本的 ABI 兼容性检查。

这种检查并不全面。它只能防范将不兼容模块安装给错误解释器的常见情况。它也不会考虑 平台不兼容性。它只能在扩展成功加载后进行。

尽管存在这些限制,仍建议扩展模块使用此机制,以便可检测到的不兼容性会引发异常,而不是导致崩溃。

大多数模块可以通过 Py_mod_abi 槽位和 PyABIInfo_VAR 宏来使用此检查,例如:

PyABIInfo_VAR(abi_info);

static PyModuleDef_Slot mymodule_slots[] = {
   {Py_mod_abi, &abi_info},
   ...
};

完整 API 将在下文针对高级使用场景进行说明。

int PyABIInfo_Check(PyABIInfo *info, const char *module_name)
属于 稳定 ABI 自 3.15 版起.

验证给定的 info 是否与当前正在运行的解释器兼容。

成功时返回 0。失败时引发异常并返回 -1。

如果 ABI 不兼容,引发的异常将是 ImportError

module_name 参数可以为 NULL,也可以指向一个以 NUL 终止、使用 UTF-8 编码、用于错误消息的字符串。

请注意,如果 info 描述的是当前代码所使用的 ABI(例如由 PyABIInfo_VAR 定义),则使用任何其他 Python C API 都可能导致崩溃。尤其是,检查所引发的异常是不安全的。

Added in version 3.15.

PyABIInfo_VAR(NAME)
属于 稳定 ABI 自 3.15 版起.

定义一个具有给定 NAME 的静态 PyABIInfo 变量,用于描述当前代码将使用的 ABI。此宏会展开为:

static PyABIInfo NAME = {
    1, 0,
    PyABIInfo_DEFAULT_FLAGS,
    PY_VERSION_HEX,
    PyABIInfo_DEFAULT_ABI_VERSION
}

Added in version 3.15.

type PyABIInfo
属于 稳定 ABI (包括所有成员) 自 3.15 版起.
uint8_t abiinfo_major_version

PyABIInfo 的主版本号。可以设为:

  • 0 表示跳过所有检查,或者

  • 1 表示指定此版本的 PyABIInfo

uint8_t abiinfo_minor_version

PyABIInfo 的次版本号。必须设为 0;更大的值将保留给未来向后兼容版本的 PyABIInfo

uint16_t flags

此字段通常设为以下宏:

PyABIInfo_DEFAULT_FLAGS
属于 稳定 ABI 自 3.15 版起.

默认标志,基于 Py_LIMITED_APIPy_GIL_DISABLED 等宏的当前值。

或者,可以将此字段设为以下标志,并通过按位或组合。未使用的位必须设为零。

ABI 变体 —— 以下之一:

PyABIInfo_STABLE
属于 稳定 ABI 自 3.15 版起.

指定使用稳定 ABI。

PyABIInfo_INTERNAL

指定特定于某个 CPython 构建的 ABI。仅限内部使用。

自由线程兼容性 —— 以下之一:

PyABIInfo_FREETHREADED
属于 稳定 ABI 自 3.15 版起.

指定与 CPython 的 自由线程构建 兼容的 ABI。(即使用 --disable-gil 编译,并且 sys.abiflags 中带有 t 的构建)

PyABIInfo_GIL
属于 稳定 ABI 自 3.15 版起.

指定与 CPython 的非自由线程构建兼容的 ABI(即 使用 --disable-gil 编译的构建)。

PyABIInfo_FREETHREADING_AGNOSTIC
属于 稳定 ABI 自 3.15 版起.

指定与 CPython 的自由线程构建和非自由线程构建二者都兼容的 ABI,也就是同时兼容 abi3abi3t

uint32_t build_version

用于构建代码的 Python 头文件版本,采用 PY_VERSION_HEX 所使用的格式。

可以将其设为 0,以跳过与此字段相关的任何检查。此选项主要面向不直接使用 CPython 头文件,并且不模拟其某个特定版本的项目。

uint32_t abi_version

ABI 版本。

对于稳定 ABI,此字段应为 Py_LIMITED_APIPy_TARGET_ABI3T 的值。如果二者都被定义,则使用较小的值。(如果 Py_LIMITED_API3,则使用 Py_PACK_VERSION(3, 2) 而不是 3。)

否则,应将其设为 PY_VERSION_HEX

也可以将其设为 0,以跳过与此字段相关的任何检查。

PyABIInfo_DEFAULT_ABI_VERSION
属于 稳定 ABI 自 3.15 版起.

此字段应使用的值,基于 Py_LIMITED_APIPY_VERSION_HEXPy_GIL_DISABLED 等宏的当前值。

Added in version 3.15.

受限 API 的内容

这是 Python 3.16 的 受限 API 权威列表: