PEP 571 – manylinux2010 平台标签
- 作者:
- Mark Williams <mrw at enotuniq.org>,Geoffrey Thomas <geofft at ldpreload.com>,Thomas Kluyver <thomas at kluyver.me.uk>
- BDFL 代表:
- Alyssa Coghlan <ncoghlan at gmail.com>
- 讨论列表:
- Distutils-SIG 列表
- 状态:
- 已取代
- 类型:
- 信息性
- 主题:
- 打包
- 创建日期:
- 2018 年 2 月 5 日
- 修订历史:
- 取代版本:
- 600
- 决议:
- Distutils-SIG 消息
摘要
本 PEP 提案创建一个 manylinux2010
平台标签,以取代由 PEP 513 引入的 manylinux1
标签。它还建议更新 PyPI 和 pip
以支持在兼容平台上上传、下载和安装 manylinux2010
发行版。
基本原理
顾名思义,manylinux1
平台标签使得在许多 Linux 系统上安装二进制扩展模块成为现实。像 cryptography
[2] 和 numpy
[3] 这样的库现在更容易被 Python 开发人员访问,因为它们在常见架构上的安装不再依赖于脆弱的开发环境和构建工具链。
manylinux1
wheel 通过允许它们包含的扩展模块仅链接到一小部分导出足够旧的版本化符号以受益于向后兼容性策略的系统级共享库来实现其可移植性。例如,manylinux1
wheel 中依赖于 glibc
的扩展模块必须针对 2.5 或更早版本构建;然后它们可以在提供更新的 glibc
版本但仍然在 2.5 版本导出所需符号的系统上运行。
PEP 513 从 CentOS 5.11 中提取了其白名单共享库及其符号版本,CentOS 5.11 是其编写时最旧的支持的 CentOS 版本。不幸的是,CentOS 5.11 于 2017 年 3 月 31 日终止支持,并明确警告不要继续使用。 [4] 将不再提供任何更新,例如安全补丁。这意味着其软件包将保持在过时的版本,这阻碍了使用 manylinux1
Docker 镜像的 Python 软件打包人员的工作。
CentOS 6 现在是最旧的支持的 CentOS 版本,并且将在 2020 年 11 月 30 日之前收到维护更新。 [5] 我们建议从 CentOS 6 派生一个名为 manylinux2010
的新的 PEP 425 样式平台标签,并且更新 manylinux
工具链、PyPI 和 pip
以支持它。
最初将其提议为 manylinux2
,但版本控制已更改为使用日历年份(也称为 CalVer [22])。这使得更容易无序地定义未来的 manylinux 标签:例如,假设的 manylinux2017
标准可以在 manylinux2014
之前通过新的 PEP 定义,或者可以定义 manylinux2007
标准,该标准针对比本 PEP 旧但比 manylinux1
新的系统。
日历版本控制也大致了解哪些 Linux 发行版支持哪些标签:manylinux2010
将适用于 2010 年以来发布的大多数发行版版本。但这只是一个近似值:实际的兼容性规则定义如下,一些更新的发行版可能不满足这些规则。
manylinux2010 策略
以下标准决定了 linux
wheel 是否有资格获得 manylinux2010
标签
- wheel 只能包含为 CentOS 6 支持的两种架构之一编译的二进制可执行文件和共享对象:x86_64 或 i686。 [5]
- wheel 的二进制可执行文件或共享对象不得链接到外部提供的库,除非是在以下白名单中
libgcc_s.so.1 libstdc++.so.6 libm.so.6 libdl.so.2 librt.so.1 libc.so.6 libnsl.so.1 libutil.so.1 libpthread.so.0 libresolv.so.2 libX11.so.6 libXext.so.6 libXrender.so.1 libICE.so.6 libSM.so.6 libGL.so.1 libgobject-2.0.so.0 libgthread-2.0.so.0 libglib-2.0.so.0
此列表与
manylinux1
的白名单外部提供的库相同,减去libncursesw.so.5
和libpanelw.so.5
。 [7]libpythonX.Y
由于与 PEP 513 中概述的原因相同,因此仍不符合包含条件。在 Fedora 30 发布包含
libcrypt.so.2
而不是libcrypt.so.1
后,libcrypt.so.1
已从白名单中追溯删除。在基于 Debian 的系统上,这些库由以下软件包提供
软件包 库 libc6 libdl.so.2, libresolv.so.2, librt.so.1, libc.so.6, libpthread.so.0, libm.so.6, libutil.so.1, libnsl.so.1 libgcc1 libgcc_s.so.1 libgl1 libGL.so.1 libglib2.0-0 libgobject-2.0.so.0, libgthread-2.0.so.0, libglib-2.0.so.0 libice6 libICE.so.6 libsm6 libSM.so.6 libstdc++6 libstdc++.so.6 libx11-6 libX11.so.6 libxext6 libXext.so.6 libxrender1 libXrender.so.1 在基于 RPM 的系统上,它们由这些软件包提供
软件包 库 glib2 libglib-2.0.so.0, libgthread-2.0.so.0, libgobject-2.0.so.0 glibc libresolv.so.2, libutil.so.1, libnsl.so.1, librt.so.1, libpthread.so.0, libdl.so.2, libm.so.6, libc.so.6 libICE libICE.so.6 libX11 libX11.so.6 libXext libXext.so.6 libXrender libXrender.so.1 libgcc libgcc_s.so.1 libstdc++ libstdc++.so.6 mesa libGL.so.1 - 如果 wheel 包含链接到任何也导出版本化符号的白名单库的二进制可执行文件或共享对象,则它们只能依赖于以下最大版本
GLIBC_2.12 CXXABI_1.3.3 GLIBCXX_3.4.13 GCC_4.5.0
例如,
manylinux2010
wheel 可以包含需要glibc
版本为GLIBC_2.4
的符号的二进制构件,因为这比GLIBC_2.12
的最大值早。 - 如果为任何版本的 CPython 2 或 CPython 3.0 及其包括 3.2 的版本构建 wheel,则 *必须* 包含一个指示其 Unicode ABI 的 CPython ABI 标签。然后,针对 Python 2 构建的
manylinux2010
wheel 必须包含cpy27mu
标签(表示它针对具有 UCS-4 ABI 的解释器构建)或cpy27m
标签(表示针对具有 UCS-2 ABI 的解释器构建)。(PEP 3149, [9]) - wheel *不得* 要求使用
PyFPE_jbuf
符号。这是通过针对 *不带*--with-fpectl
configure
标记编译的 Python 构建它来实现的。
兼容 Wheel 的编译
与 manylinux1
一样,auditwheel
工具将 manylinux2010
平台标签添加到由 pip wheel
或 bdist_wheel
在 manylinux2010
Docker 容器中构建的 linux
wheel。
Docker 镜像
提供了两个基于 CentOS 6 的 manylinux2010
Docker 镜像,用于构建可以可靠地转换为 manylinux2010
wheel 的二进制 linux
wheel。 [10] x86_64 和 i686 镜像安装了新的编译器套件(来自 devtoolset-8
的 gcc
、g++
和 gfortran
),以及 Python 和 pip
的最新版本。
与缺少 vsyscall
的内核的兼容性
Docker 容器假定其用户空间与其主机的内核兼容。不幸的是,越来越常见的内核配置打破了 x86_64 CentOS 6 Docker 镜像的这一假设。
在 glibc
2.14 及更早版本中,需要内核在 x86_64 上提供一种称为 vsyscall
的过时系统调用优化。[11] 为了实现该优化,内核将一个包含常用系统调用的只读页面(最显著的是 time(2)
)映射到每个进程的固定内存位置。然后,glibc
通过对指向 vsyscall
页面中适当偏移量的函数指针进行解引用并调用它来调用这些系统调用。这避免了影响普通系统调用调用的内核调用相关的开销。vsyscall
早已弃用,取而代之的是一种称为 vDSO 或“虚拟动态共享对象”的等效机制,其中内核将包含优化系统调用的可重定位虚拟共享对象映射到每个进程中。[12]
vsyscall
页面存在严重的安全隐患,因为它不参与地址空间布局随机化 (ASLR)。其可预测的位置和内容使其成为返回导向编程攻击中使用的代码片段的有用来源。[13] 同时,它的消除破坏了 x86_64 ABI,因为依赖于 vsyscall
的 glibc
版本在尝试对指向不存在页面的系统调用指针进行解引用时会出现段错误。作为一种折衷方案,Linux 3.1 实现了一个“模拟”的 vsyscall
,它减少了映射到进程中的可执行代码,从而减少了 ROP 代码片段的材料。[14] 多年来,vsyscall=emulated
一直是大多数发行版内核的默认配置。
不幸的是,vsyscall
模拟仍然在可靠的内存位置公开可预测的代码,并且仍然可用于返回导向编程。[15] 由于大多数发行版现已升级到不依赖于 vsyscall
的 glibc
版本,因此它们开始发布完全不支持 vsyscall
的内核。[16]
CentOS 5.11 和 6 都包含依赖于 vsyscall
页面的 glibc
版本(分别为 2.5 和 2.12.2),因此基于这两个版本的容器无法在许多发行版即将发布的内核版本下运行。[17] 例如,如果 Travis CI 开始在不提供 vsyscall
接口的内核下运行作业,那么 Python 包管理器将无法在那里使用我们的 Docker 镜像来构建 manylinux
轮子。[18]
我们从 glibc
git 仓库中提取了一个补丁,它将删除所有对 vsyscall
的依赖关系的功能移植到我们 manylinux2010
镜像中包含的 glibc
版本。[19] 重新构建 glibc
,以及 manylinux2010
镜像本身,仍然需要一个提供 vsyscall
机制的宿主机内核,但生成的镜像既可以在提供该机制的宿主机上运行,也可以在不提供该机制的宿主机上运行。因为 vsyscall
接口是一种仅应用于正在运行的进程的优化,所以使用此修改后的镜像构建的 manylinux2010
轮子应该与在未修改的 CentOS 6 系统上构建的轮子相同。此外,vsyscall
问题仅适用于 x86_64;它不是 i686 ABI 的一部分。
Auditwheel
auditwheel
工具也已更新以生成 manylinux2010
轮子。[20] 除了这一点,它的行为和目的与 PEP 513 中描述的一样。
安装程序的平台检测
平台可以在 PEP 513 中描述的 _manylinux
模块上定义一个 manylinux2010_compatible
布尔属性。如果该属性为 False
,则认为该平台与 manylinux2010
不兼容。
如果找不到 _manylinux
模块,或者它没有 manylinux2010_compatible
属性,则工具可能会回退到检查 glibc。如果平台具有 glibc 2.12 或更高版本,则假设它与 manylinux2010
兼容,除非 _manylinux
模块另有说明。
具体来说,我们提出的算法是
def is_manylinux2010_compatible():
# Only Linux, and only x86-64 / i686
from distutils.util import get_platform
if get_platform() not in ["linux-x86_64", "linux-i686"]:
return False
# Check for presence of _manylinux module
try:
import _manylinux
return bool(_manylinux.manylinux2010_compatible)
except (ImportError, AttributeError):
# Fall through to heuristic check below
pass
# Check glibc version. CentOS 6 uses glibc 2.12.
# PEP 513 contains an implementation of this function.
return have_compatible_glibc(2, 12)
与 manylinux1 wheel 的向后兼容性
如 PEP 513 中所解释的,为 manylinux1
白名单库指定的符号版本构成一个上限。对于本 PEP 中为 manylinux2010
定义的符号版本也是如此。因此,manylinux1
轮子被视为 manylinux2010
轮子。因此,识别 manylinux2010
平台标签的 pip
将为 manylinux2010
平台安装 manylinux1
轮子(即使显式设置),前提是没有任何可用的 manylinux2010
轮子。[21]
PyPI 支持
PyPI 应该允许上传包含 manylinux2010
平台标签的轮子,就像允许上传 manylinux1
轮子一样。它不应尝试验证 manylinux2010
轮子的兼容性。
PEP 571 的更改总结
根据在 PEP 批准后收到的反馈,对 PEP 进行了以下更改
libgcc_s
的最大版本符号已从GCC_4.3.0
更新到GCC_4.5.0
以解决 32 位 Cent OS 6 的问题。这不会影响 x86_64,因为 x86_64 的libgcc_s
在GCC_4.3.0
到GCC_4.5.0
之间没有额外的符号。
参考文献
版权
本文档已进入公有领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0571.rst
最后修改时间:2023-10-11 12:05:51 GMT