PEP 425 – 内置分发的兼容性标签
- 作者:
- Daniel Holth <dholth at gmail.com>
- BDFL 委托:
- Alyssa Coghlan <ncoghlan at gmail.com>
- 状态:
- 最终版
- 类型:
- 标准跟踪
- 主题:
- 打包
- 创建日期:
- 2012年7月27日
- Python 版本:
- 3.4
- 发布历史:
- 2012年8月8日,2012年10月18日,2013年2月15日
- 决议:
- Python-Dev 消息
摘要
本 PEP 规定了一种标签系统,用于指示内置或二进制分发与哪些版本的 Python 兼容。一组三个标签表示内置分发所需的 Python 实现和语言版本、ABI 和平台。这些标签是简洁的,因为它们将被包含在文件名中。
PEP 接受
本 PEP 于 2013 年 2 月 17 日被 Alyssa Coghlan 接受。
基本原理
如今,“python setup.py bdist”在 PyPy 和 CPython 上生成相同的文件名,但却是互不兼容的存档,这使得在同一文件夹或索引中共享内置分发变得不便。相反,内置分发应该有一个文件命名约定,其中包含足够的信息来决定特定存档是否与特定实现兼容。
之前的努力来自于 CPython 是唯一重要的实现,并且 ABI 与 Python 语言版本相同的时候。本规范通过包含 Python 实现、语言版本、ABI 和平台作为一组标签,改进了旧方案。
通过将其支持的标签与分发列出的标签进行比较,安装程序可以做出明智的决定,而无需阅读其完整的元数据,即可决定是否下载特定的内置分发。
概述
标签格式为 {python 标签}-{abi 标签}-{平台标签}
- python 标签
- ‘py27’, ‘cp33’
- abi tag
- ‘cp32dmu’, ‘none’
- platform tag
- ‘linux_x86_64’, ‘any’
例如,标签 py27-none-any 表示与 Python 2.7(任何 Python 2.7 实现)兼容,没有 abi 要求,适用于任何平台。
使用
wheel 内置包格式在其文件名中包含这些标签,形式为 {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl。其他包格式可能有自己的约定。
详情
Python 标签
Python 标签指示分发所需的实现和版本。主要实现有缩写代码,最初是
- py: 通用 Python (不需要特定于实现的功能)
- cp: CPython
- ip: IronPython
- pp: PyPy
- jy: Jython
其他 Python 实现应该使用 sys.implementation.name。
版本是 py_version_nodot。CPython 不需要点,但如果需要,则使用下划线 _ 代替。PyPy 可能应该在这里使用自己的版本 pp18, pp19。
对于许多纯 Python 分发,版本可以是主版本 2 或 3,即 py2, py3。
重要的是,像 py2 和 py3 这样的仅限主版本标签不是 py20 和 py30 的缩写。相反,这些标签表示打包者有意发布了跨版本兼容的分发。
一个单一来源的 Python 2/3 兼容分发可以使用复合标签 py2.py3。请参阅下面的 压缩标签集。
ABI 标签
ABI 标签指示任何包含的扩展模块所需的 Python ABI。对于特定于实现的 ABI,实现的缩写方式与 Python 标签相同,例如 cp33d 将是具有调试功能的 CPython 3.3 ABI。
CPython 稳定 ABI 是 abi3,就像共享库的后缀一样。
具有非常不稳定 ABI 的实现可以使用其源代码修订和编译器标志等的 SHA-256 哈希值的前 6 个字节(作为 8 个 base64 编码字符),但可能不太需要分发二进制分发。每个实现的社区可以决定如何最好地使用 ABI 标签。
平台标签
平台标签就是 distutils.util.get_platform(),其中所有连字符 - 和句点 . 都被下划线 _ 替换。
- win32
- linux_i386
- linux_x86_64
使用
安装程序使用这些标签来决定从潜在的内置分发列表中下载哪个(如果有的话)内置分发。安装程序维护一个它将支持的 (pyver, abi, arch) 元组列表。如果内置分发的标签 在 列表中,那么它就可以被安装。
建议安装程序默认尝试选择可用的功能最完整的内置分发(最特定于安装环境的分发),然后再退回到为旧 Python 版本发布的纯 Python 版本。还建议安装程序提供一种配置和重新排序允许的兼容性标签列表的方法;例如,用户可能只接受 *-none-any 标签,以便只下载声明自己是纯 Python 的内置包。
另一个理想的安装程序功能可能是将“如果可能,从源代码重新编译”作为比一些兼容但传统的预构建选项更优选的选项。
此示例列表适用于在 linux_x86_64 系统上运行 CPython 3.3 的安装程序。它的顺序是从最优先(包含编译的扩展模块,为当前 Python 版本构建的分发)到最不优先(使用旧版本 Python 构建的纯 Python 分发)
- cp33-cp33m-linux_x86_64
- cp33-abi3-linux_x86_64
- cp3-abi3-linux_x86_64
- cp33-none-linux_x86_64*
- cp3-none-linux_x86_64*
- py33-none-linux_x86_64*
- py3-none-linux_x86_64*
- cp33-none-any
- cp3-none-any
- py33-none-any
- py3-none-any
- py32-none-any
- py31-none-any
- py30-none-any
- 内置分发可能由于 C 扩展以外的原因而具有平台特定性,例如包含作为子进程调用的本地可执行文件。
有时,一个特定版本的包会有多个受支持的内置分发。例如,打包者可以发布一个标记为 cp33-abi3-linux_x86_64 的包,其中包含一个可选的 C 扩展,以及一个标记为 py3-none-any 的相同分发,该分发不包含 C 扩展。在支持的标签列表中,标签的索引打破了平局,并且带有 C 扩展的包优先于不带 C 扩展的包安装,因为该标签首先出现在列表中。
压缩标签集
为了允许适用于多个兼容性标签三元组的 bdist 的紧凑文件名,文件名中的每个标签都可以是一个“.”分隔的、排序的标签集。例如,pip 是一个纯 Python 包,使用相同的源代码在 Python 2 和 3 下运行,可以分发带有标签 py2.py3-none-any 的 bdist。简单标签的完整列表是
for x in pytag.split('.'):
for y in abitag.split('.'):
for z in archtag.split('.'):
yield '-'.join((x, y, z))
实现此方案的 bdist 格式应在 bdist 特定的元数据中包含展开的标签。这种压缩方案可以生成大量不受支持的标签和没有 Python 实现支持的“不可能”标签,例如“cp33-cp31u-win64”,因此请谨慎使用。
常见问题
- 默认使用哪些标签?
- 工具默认应使用最优选的架构相关标签,例如
cp33-cp33m-win32,或者最优选的纯 Python 标签,例如py33-none-any。如果打包者覆盖了默认值,则表示他们打算提供跨 Python 兼容性。 - 如果我的分发使用了仅最新版本 Python 独有的功能,我应该使用哪个标签?
- 兼容性标签帮助安装程序选择分发 单个版本 的 最兼容 构建。例如,当
beaglevote-1.2.0没有 Python 3.3 兼容构建时(它使用 Python 3.4 独有的功能),它仍然可以使用py3-none-any标签而不是py34-none-any标签。Python 3.3 用户必须结合其他限定符,例如对不使用新功能的旧版本beaglevote-1.1.0的要求,才能获得兼容的构建。 - 为什么 Python 版本号中没有
.? - CPython 在没有三位主版本号的情况下已经持续了 20 多年。这应该会持续一段时间。其他实现可以使用 _ 作为分隔符,因为 - 和 . 都分隔周围的文件名。
- 为什么将连字符和其他非字母数字字符规范化为下划线?
- 为了避免与分隔文件名组件的“.”和“-”字符冲突,并更好地兼容最广泛的文件系统对文件名的限制(包括在 URL 路径中无需引用即可使用)。
- 为什么不使用特殊字符 <X> 而不是“.”或“-”?
- 要么是因为该字符在某些情况下不方便或可能令人困惑(例如,“+”必须在 URL 中引用,“~”用于在 POSIX 中表示用户主目录),要么是因为其优点不足以令人信服,不足以证明更改 PEP 427 中定义的 wheel 格式的现有参考实现是合理的(例如,使用“,”而不是“.”来分隔压缩标签中的组件)。
- 谁将维护缩写实现的注册表?
- 可以在 python-dev 邮件列表中请求新的两位字母缩写。根据经验法则,缩写保留给当前最重要的 4 个实现。
- 兼容性标签是否进入 METADATA 或 PKG-INFO?
- 不。兼容性标签是内置分发元数据的一部分。METADATA / PKG-INFO 应该对整个分发有效,而不是该分发的单个构建。
- 你为什么不提我最喜欢的 Python 实现?
- 缩写标签有助于在公共索引中共享已编译的 Python 代码。你的 Python 实现也可以使用此规范,但标签更长。回想一下,所有“纯 Python”内置分发都只使用“py”。
- 为什么 ABI 标签(第二个标签)在参考实现中有时是“none”?
- 由于 Python 2 没有一种简单的方法来获取 SOABI(这个概念来自较新版本的 Python 3),因此在撰写本文时,参考实现猜测为“none”。理想情况下,它会检测“py27(d|m|u)”,类似于较新版本的 Python,但在此期间,“none”是一种足够好的表示“不知道”的方式。
参考资料
[1] Egg 文件名嵌入元数据 (http://peak.telecommunity.com/DevCenter/EggFormats#filename-embedded-metadata)
[2] 创建内置分发 (https://docs.pythonlang.cn/3.4/distutils/builtdist.html)
致谢
作者感谢 Paul Moore、Alyssa Coghlan、Marc Abramowitz 和 Michele Lacchia 先生提供的宝贵帮助和建议。
版权
本文档已置于公共领域。
来源: https://github.com/python/peps/blob/main/peps/pep-0425.rst
最后修改: 2025-02-01 08:59:27 GMT