跳到主要内容

CEP 20 - 支持 abi3 Python 包

标题支持 abi3 Python 包
状态已批准
作者Isuru Fernando <ifernando@quansight.com>
创建于2024 年 7 月 1 日
更新于2024 年 12 月 19 日
讨论https://github.com/conda/ceps/pull/86
实施https://github.com/conda/conda-build/pull/5456

摘要

本 CEP 详细说明了 conda 安装工具(conda/mamba/micromamba/pixi)如何支持 abi3 Python 包,以及 conda 构建工具 (conda-build/rattler-build) 如何构建它们。

动机

在为 Python 构建扩展时,它们可能会使用 Python 次版本特定的符号。这导致扩展只能在该次版本上使用。这些扩展通过扩展名后缀来识别。例如,foo.cpython-310-x86_64-linux-gnu.so 是一个仅支持 x86_64-linux-gnu 平台上的 CPython 3.10 的扩展。

然而,某些符号在所有 Python 主版本.次版本中都可用,并且 Python 版本有一定的下限。这些符号是有限 C API 的一部分。保证在 Python 3.X 中引入的有限 C API 中的符号在 Python 3.Y 中可用,对于任何 Y >= X。仅使用这些符号的扩展通过扩展名后缀 abi3.so 来识别。例如,foo.abi3.so

这些扩展仅支持构建它们的平台(例如 x86_64-linux-gnu),但这并未在扩展名后缀中指定。

请注意,稳定的 ABI 仅特定于 CPython,并且与 PyPy 或其他 Python 实现不兼容。对于独立于 Python 实现的 ABI,请参阅 HPy 项目

构建 abi3 包的动机是我们只需要为一个 Python 版本构建扩展,并且该扩展将适用于任何后续的 Python 版本。这减少了构建矩阵,从 4-5 个 Python 次版本减少到一个 Python 次版本,并减轻了包构建者的维护负担。

noarch:Python 包

abi3 包与 Python 版本无关,我们将首先查看 noarch: python 包,它们也与 Python 版本无关,并且此外还与架构无关。

noarch: python 包具有以下几个属性

  • A1:它们在 info/index.json 中具有 subdir: noarch

  • A2:它们在 info/index.json 中具有 noarch: python

  • A3:Python 文件位于 <PREFIX>/site-packages 中。

  • A4:入口点记录在 info/link.json 中。

conda 安装工具执行四件事来支持它们

  • B1<PREFIX>/site-packages 中的文件被移动到正确的位置。例如:<PREFIX>/lib/python3.10/site-packages

  • B2:Python 文件(以 *.py 结尾的文件)被编译为 .pyc 文件。例如:<PREFIX>/lib/python3.10/site-packages/foo.py 被编译为 <PREFIX>/lib/python3.10/site-packages/__pycache__/foo.cpython-310.pyc

  • B3:创建的 .pyc 文件记录在 <PREFIX>/conda-meta/<pkg>.json 中,以便在卸载包时正确删除它们。

  • B4info/link.json 中的入口点被物化。

info/link.json 文件

noarch: pythoninfo/link.json 示例看起来像

{
"noarch": {
"entry_points": [
"isympy = isympy:main"
],
"type": "python"
},
"package_metadata_version": 1,
"preferred_env": "foo"
}

noarch: genericinfo/link.json 示例看起来像

{
"noarch": {
"type": "generic"
},
"package_metadata_version": 1
}

这里 preferred_env 自 2017 年以来被 conda 忽略,并且不受其他 conda 安装工具的支持。因此,info/link.json 专门用于 noarch 包,并且在两种类型中,noarch: generic 包不需要任何特殊操作。

info/index.json 文件

noarch: python 配方示例。

{
"arch": null,
"build": "pyh2585a3b_103",
"build_number": 103,
"depends": [
"mpmath >=0.19",
"python >=3.8"
],
"license": "BSD-3-Clause",
"license_family": "BSD",
"name": "sympy",
"noarch": "python",
"platform": null,
"subdir": "noarch",
"timestamp": 1718625708903,
"version": "1.12.1"
}

求解器工具中的当前行为

Conda 包上传工具(如 anaconda-client)使用 A1 将包上传到 noarch 子目录。

Conda 安装工具的行为略有不同。

Conda

  1. 操作 B1、B2、B3 应用于具有 A3 的包。
  2. 操作 B4 应用于具有 A4 的包。

Micromamba

  1. 操作 B1、B2、B3 应用于同时具有 A2、A3 的包。
  2. 操作 B4 应用于同时具有 A2、A4 的包。

abi3 包的实现

安装工具中的支持

我们要求 abi3 包中具有以下属性

  • C1:它们具有 subdir: <platform>,其中 <platform> 是构建包的子目录。

  • C2:它们具有 noarch: python

  • C3:应用 A2、A3、A4

这与当前的 conda/mamba/micromamba 安装工具兼容。

构建工具中的支持

这需要构建工具支持设置 subdir: <platform>

特别是,配方作者将设置

build:
python_version_independent: true

requirements:
host:
- python
- python-abi3

这将使构建工具

  • D1:在 info/index.json 中设置 noarch: python

请注意,python-abi3 将设置运行时需求。这是配方作者明确要求的,以便我们不将此 CEP 限制为 abi3 包,并允许 abi4 等的可能性。

一个 python-abi3=3.8 包会在其 run_exports 条目中设置自身,并将具有以下要求

requirements:
run:
- cpython >=3.8
- python-gil

考虑的替代方案

post-link.sh 脚本中应用所有操作。

python-feedstock 中提供的草案工作。这是 @mbargull 提出的建议,但一些社区成员(@baszalmstra,@wolfv)不喜欢 post-link 脚本,因为它们可以用于任意代码执行。但是,在作者看来,这种攻击媒介并不是一个新的,因为安装工具使用主机环境中的 Python 可执行文件来编译 Python 文件。

带有 __linux, __osx, __win 约束的 noarch: python 包。

@wolfv 的这个建议并不理想,因为它会使 noarch 子目录 repodata.json 文件中充斥着对相关平台无用的包。

新的 package_metadata_version

由于我们可以在当前安装工具的约束范围内工作,因此我们不需要来自安装工具的额外支持。

所有 CEP 均明确采用 CC0 1.0 通用