Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 656 – 使用 Musl 的 Linux 发行版的平台标签

作者:
Tzu-ping Chung <uranusjr at gmail.com>
赞助商:
Brett Cannon <brett at python.org>
PEP 代表:
Paul Moore <p.f.moore at gmail.com>
讨论地址:
Discourse 线程
状态:
最终
类型:
标准跟踪
主题:
打包
创建:
2021 年 3 月 17 日
更新历史:
2021 年 3 月 17 日,2021 年 4 月 18 日
决议:
Discourse 消息

目录

摘要

本 PEP 提议了一个新的平台标签系列 musllinux,用于 Python 安装依赖于 Linux 发行版上的 musl 的 Python 二进制包分发。该标签与 PEP 600 中指定的“永久 manylinux”平台标签类似,但目标是基于 musl 的平台。

动机

随着容器的广泛使用,像 Alpine Linux [alpine] 这样的发行版比以往任何时候都更受欢迎。它们中的许多基于 musl [musl],它是与 glibc 不同的 libc 实现,因此无法使用现有的 manylinux 平台标签。这意味着 Python 包项目无法在 PyPI 上为它们部署二进制分发。这些项目的使用者要求这些项目进行构建约束,给项目维护者带来不必要的负担。

理由

根据文档,musl 具有稳定的 ABI,并且保持向后兼容性 [musl-compatibility] [compare-libcs],因此针对早期版本 musl 编译的二进制文件保证可以在较新 musl 运行时上运行 [musl-compat-ml]。因此,我们使用与基于 glibc 版本的 manylinux 标签类似的方案,但针对的是 musl 版本而不是 glibc。

新平台标签背后的逻辑很大程度上遵循 PEP 600(“永久 manylinux”),并且要求使用该标签的轮子做出类似的承诺。有关该设计背后的理由和论证的更多详细信息,请参阅 PEP 600

The musllinux 平台标签仅适用于针对 musl libc 动态链接并在 Linux 操作系统上的运行时共享库上执行的 Python 解释器。静态链接的解释器或与其他 libc 实现(例如 glibc)混合构建不在本文件定义的平台标签的范围内,也不受其支持。此类解释器不应声明与 musllinux 平台标签的兼容性。

规范

使用新方案的标签将采用以下形式

musllinux_${MUSLMAJOR}_${MUSLMINOR}_${ARCH}

该标签承诺该轮子适用于任何使用 musl 版本 ${MUSLMAJOR}.${MUSLMINOR} 的主流 Linux 发行版,遵循永久设计。所有其他系统级依赖关系要求依赖于社区对 PEP 600 中引入的故意模糊的“主流”描述的定义。当所有使用指定 musl 版本的主流发行版默认提供依赖关系时,轮子可以使用较新的系统依赖关系;一旦所有使用 musl 版本的主流发行版默认提供特定依赖关系版本,依赖于旧版本的使用者将自动从该 musllinux 标签的覆盖范围内删除。

读取 musl 版本

musl 版本值可以通过执行 Python 解释器当前正在运行的 musl libc 共享库并解析输出获得

import re
import subprocess

def get_musl_major_minor(so: str) -> tuple[int, int] | None:
    """Detect musl runtime version.

    Returns a two-tuple ``(major, minor)`` that indicates musl
    library's version, or ``None`` if the given libc .so does not
    output expected information.

    The libc library should output something like this to stderr::

        musl libc (x86_64)
        Version 1.2.2
        Dynamic Program Loader
    """
    proc = subprocess.run([so], stderr=subprocess.PIPE, text=True)
    lines = (line.strip() for line in proc.stderr.splitlines())
    lines = [line for line in lines if line]
    if len(lines) < 2 or lines[0][:4] != "musl":
        return None
    match = re.match(r"Version (\d+)\.(\d+)", lines[1])
    if match:
        return (int(match.group(1)), int(match.group(2)))
    return None

目前有两种方法可以找到 Python 解释器正在运行的 musl 库的位置,一种是使用系统 ldd 命令 [ldd],另一种是解析可执行文件 ELF 头部的 PT_INTERP 部分的值 [elf]

格式化标签

使用该标签的发行版做出了与 PEP 600 中描述的类似承诺,包括

  1. 该分发适用于任何 musl 版本为 ${MUSLMAJOR}.${MUSLMINOR} 或更高版本的主流 Linux 发行版。
  2. 该分发的 ${ARCH} 与主机系统上 sysconfig.get_platform() 的返回值匹配,将句点 (.) 和连字符 (-) 字符替换为下划线 (_),如 PEP 425PEP 427 中所述。

示例值

musllinux_1_1_x86_64   # musl 1.1 running on x86-64.
musllinux_1_2_aarch64  # musl 1.2 running on ARM 64-bit.

可以使用以下 Python 代码格式化该值

import sysconfig

def format_musllinux(musl_version: tuple[int, int]) -> str:
    os_name, sep, arch = sysconfig.get_platform().partition("-")
    assert os_name == "linux" and sep, "Not a Linux"
    arch = arch.replace(".", "_").replace("-", "_")
    return f"musllinux_{musl_version[0]}_{musl_version[1]}_{arch}"

对包索引的建议

建议 Python 包仓库(包括 PyPI)接受与以下正则表达式匹配的平台标签

musllinux_([0-9]+)_([0-9]+)_([^.-]+)

Python 包仓库可能会实施额外的要求来拒绝已知存在问题的 Wheel,包括但不限于

  • 一个 musllinux_1_1 轮子,其中包含仅在 musl 1.2 或更高版本中可用的符号。
  • 依赖于包索引的预期受众无法普遍获得的外部库的 Wheel。
  • 一个声称与不存在的 musl 版本兼容的平台标签(例如 musllinux_9000_0)。

此类策略最终取决于各个包仓库。作者无意对维护者施加限制。

向后兼容性

本 PEP 中没有向后兼容性问题。

被拒绝的想法

基于 Alpine Linux 创建一个平台标签

过去在 manylinux 标签系列上的经验表明,这种方法在时间上成本过高。作者认为“与其他人配合良好”的规则既更具包容性,在实践中也足够有效。

参考文献


来源: https://github.com/python/peps/blob/main/peps/pep-0656.rst

最后修改时间: 2023 年 9 月 9 日 17:39:29 GMT