菜单

稳定ABI

相关源文件

Python 稳定 ABI(应用程序二进制接口)提供了一种构建可跨不同 Python 版本保持兼容性的 C 扩展模块的方法。本文档介绍了什么是稳定 ABI,它是如何工作的,以及使用它来创建在 Python 更新后仍能保持稳定性的扩展模块的最佳实践。

有关创建 C 扩展模块的常规信息,请参阅扩展开发和 C API

目的与范围

稳定 ABI 解决了 Python 扩展的二进制兼容性问题。如果没有它,为某一 Python 版本(例如 3.8)编译的 C 扩展必须为每个新版本(3.9、3.10 等)重新编译才能正常工作。稳定 ABI 保证:

  • 基于此构建的二进制扩展将在未来 Python 版本中无需重新编译即可工作。
  • 稳定 ABI 中的符号(函数、类型等)在不同 Python 版本中保持一致的行为。
  • 扩展作者可以使用单个二进制文件面向广泛的 Python 版本。

稳定 ABI 在 Python 3.2(PEP 384)中引入,并在后续版本中得到扩展。

来源:Misc/stable_abi.toml1-63 Doc/c-api/stable.rst

使用稳定 ABI

如何使用稳定 ABI 构建扩展

要使用稳定 ABI 构建扩展模块,请执行以下操作:

  1. 定义宏 Py_LIMITED_API 为您的扩展所需的最低 Python 版本(十六进制格式)。
  2. 包含 Python 头文件:#include <Python.h>
  3. 将您的代码限制为仅使用属于稳定 ABI 的函数和类型。

构建扩展时:

  • 在 Windows 上,链接到 python3.dll(而不是特定版本的 python3X.dll)。
  • 在类 Unix 系统上,使用适当的标志进行构建,以确保正确的符号解析。

版本规范

Py_LIMITED_API 应设置为目标最低 Python 版本(十六进制),格式为 0xMMmmNNpp,其中:

  • MM 是主版本号。
  • mm 是次版本号。
  • NN 是微版本号。
  • pp 是补丁级别(通常为 0)。

常见值包括:

  • 0x03020000 表示 Python 3.2(首个支持稳定 ABI 的版本)。
  • 0x03060000 表示 Python 3.6。
  • 0x03070000 表示 Python 3.7。
  • 0x030A0000 表示 Python 3.10。

来源:Include/Python.h30-46 Doc/c-api/stable.rst

稳定 ABI 架构

下图说明了稳定 ABI 与完整 Python C API 和扩展之间的关系。

稳定 ABI 是完整 Python C API 的一个子集,仅包含保证在 Python 版本之间保持兼容性的函数、类型和其他符号。

来源:Misc/stable_abi.toml13-59 PC/python3dll.c1-14

二进制兼容性

这与需要为每个新 Python 版本重新编译的常规扩展形成对比。

来源:Include/Python.h47-52 Doc/whatsnew/3.13.rst616-617

稳定 ABI 组件

稳定 ABI 由不同类型的项目组成:

组件类型描述示例
函数保证保持其签名和行为的 C API 函数。PyDict_New()PyList_Append()PyLong_FromLong()
结构体具有不同暴露级别的 C 结构体定义。PyObjectPyTypeObjectPyModuleDef
类型用于函数签名的类型定义。PyObject*Py_ssize_tPyTypeObject*
常量用于 API 调用的命名值。Py_NonePyExc_ValueError
用于常见操作的预处理器定义。Py_INCREF()Py_DECREF()

结构体暴露级别

稳定 ABI 中的结构体具有不同的暴露级别。

  1. 完整 ABI(full-abi:整个结构体定义是稳定的,包括大小和字段布局。例如:PyMethodDefPyModuleDef
  2. 不透明(opaque:只有指向结构体的指针是稳定的。内部布局可能会发生变化。例如:PyThreadStatePyInterpreterState
  3. 成员(members:只有特定的成员属于 ABI。例如:PyObject(只有 ob_refcntob_type 是稳定的)。

来源:Misc/stable_abi.toml40-50 Include/object.h109-164

稳定 ABI 中的类型对象

类型对象是稳定 ABI 的关键部分。

要使用稳定 ABI 创建类型对象,请使用 PyType_Spec 结构体和相关函数,而不是直接创建 PyTypeObject

来源:Include/object.h374-385 Include/object.h386-415

稳定 ABI 内容和演进

稳定 ABI 随着时间的推移而增长,每个 Python 版本都添加了新的函数和功能。

Python 版本新增功能重要新增内容
Python 3.2初始稳定 ABI (PEP 384)核心对象和类型系统,基本模块支持。
Python 3.3类型规范增强。PyType_FromSpecWithBases()
Python 3.4槽内省。PyType_GetSlot()
Python 3.5模块定义助手。PyModuleDef_Init()
Python 3.6路径处理。PyOS_FSPath()
Python 3.7内存和错误处理改进。PyMem_Calloc(),以及许多新的错误函数。
Python 3.8类型和集合改进。PyType_GetName()PyIter_Check()
Python 3.9类方法创建。PyCMethod_New()
Python 3.10模块和迭代器实用工具。PyIter_Send()PyModule_AddObjectRef()
Python 3.11缓冲区协议和异常改进。Buffer API 函数。
Python 3.12异常显示改进。PyErr_DisplayException()
Python 3.13GIL 相关函数和优化。PyMem_RawCalloc() 及其系列函数。

完整的符号列表维护在 Misc/stable_abi.toml 中,并且可以在安装的 Doc/data/stable_abi.dat 文件中查看。

来源:Misc/stable_abi.toml147-620 Doc/data/stable_abi.dat1-500

限制和注意事项

不兼容多线程

稳定 ABI 与 Python 的多线程版本(无 GIL)不兼容。使用稳定 ABI 的扩展无法在全局解释器锁被禁用的 Python 版本中加载。

来源:Include/Python.h48-52 Doc/whatsnew/3.13.rst47-52

内存管理

在使用稳定 ABI 时,内存管理变得尤为重要。请仅使用 Python 的内存管理函数,如 PyMem_Malloc(),而不是 C 标准库的 malloc()。这有助于避免内存损坏问题。

来源:Doc/c-api/memory.rst49-67

扩展隔离

扩展应尽可能被隔离,并且不应依赖于每个进程的全局状态。尽可能使用每个模块的状态,如“隔离扩展”操作指南中所述。

这对于稳定 ABI 尤其重要,因为您的扩展可能会在存在多个解释器的环境中加载。

来源:Doc/howto/isolating-extensions.rst30-60

测试稳定 ABI 合规性

Python 测试套件包含验证所有稳定 ABI 符号是否可访问的测试。您也可以类似地测试您的扩展,以确保它仅使用稳定 ABI 符号,可以使用 ctypes 等工具。

来源:Lib/test/test_stable_abi_ctypes.py1-20

结论

稳定的 ABI 提供了一种强大的方式来构建能够跨 Python 版本保持兼容性的扩展模块。通过将你的扩展限制为仅使用已定义的 Stable ABI 函数和类型,你可以创建二进制扩展,而无需为每个新的 Python 版本重新编译,从而使分发和维护更加容易。

在使用 Stable ABI 进行开发时,请记住:

  • Py_LIMITED_API 定义为你支持的最低 Python 版本
  • 仅使用属于 Stable ABI 的函数和类型
  • 注意不同结构暴露的级别
  • 在多个 Python 版本上进行彻底测试

这些实践将有助于确保你的扩展在不同 Python 版本上都能可靠运行。