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

Python 增强提案

PEP 778 – 支持 Wheel 中的符号链接

作者:
Emma Harper Smith <emma at python.org>
发起人:
Barry Warsaw <barry at python.org>
PEP 代理人:
Paul Moore <p.f.moore at gmail.com>
讨论至:
Discourse 帖子
状态:
推迟
类型:
标准跟踪
主题:
打包
要求:
777
创建日期:
2024年5月18日
发布历史:
2024年10月10日

目录

摘要

目前 Wheel 对符号链接的处理不佳,安装时会复制内容而不是创建符号链接。为了正确处理 Wheel 中库的分发,我们提出了一个新的 LINKS 元数据文件,以平台可移植的方式处理符号链接。此规范要求一个新的 Wheel 主版本,详情在 PEP 777 中讨论。

PEP 延期

此 PEP 已被推迟,直到建立更好的 Wheel 格式重大更改兼容性方案。一旦为 Wheel 建立了兼容性方案,允许以不显眼的方式引入向后不兼容的行为,本 PEP 中应解决以下几点:

  • 将此主题重新聚焦于 POSIX 平台上共享库的符号链接,或许与平台标签绑定?
  • 符号链接应该作为文件属性在存档中实现,还是作为 LINKS 文件?是否可以将其编码在 RECORD 中?
  • 澄清此 PEP 不足以用于 PEP 660 可编辑安装,因为它将不再跨平台。
  • 描述在 POSIX 平台上符号链接不可用时的回退行为。

动机

目前,Wheel 中的符号链接被创建为文件副本,因为 CPython 中的 zipfile 模块出于安全原因不支持就地处理符号链接

给那些希望在 Wheel 中发布大型编译库的项目带来了问题,因为它们必须选择要么大幅增加项目在磁盘上的安装大小,要么省略符号链接并可能破坏一些下游用例。

为了发布一个可以正确加载以供 POSIX 上的运行时使用或构建时链接的库,该库应遵循 POSIX 风格加载器和链接器搜索的约定。加载器使用的两个主要文件名是“soname”和“real name”。“soname”是一个像 libfoo.so.3 这样的文件,其中 3 是一个数字,当库的接口更改时会递增。“real name”是一个名为 libfoo.so.3.1.4 的文件,其中额外的版本信息允许加载器找到特定版本的库。最后,当编译代码以链接到库时,链接器会搜索“链接器名称”,其名称像 libfoo.so。在这篇关于共享库的 Linux 文档中有更详细的描述。为了完全支持所有运行时和构建时用例,一个项目需要发布所有 3 个文件。通常,这在 POSIX 平台上通过使用符号链接来处理,这样库就不会在磁盘上重复 3 次。

回到 Python 打包,有许多流行的项目发布二进制库,例如 numpyscipypyarrow。其他 site-packages 会 dlopen 其他 Wheel 中的库,例如 pytorchjax。这些项目目前依赖于 Wheel 中的单个库,但这可能会导致链接器找到错误的库,如果存在具有“真实名称”库版本的系统库。

符号链接在 Wheel 中也可能带来潜在的好处,即通过简单地在用户的 site-packages 目录中放置一个符号链接来简化可编辑安装,但本 PEP 将此作为一个有待在未来 PEP 中探讨的开放问题。

基本原理

为了支持 POSIX 上加载和库链接中使用的库的 3 种主要命名方式,我们建议在 Python Wheel 中添加对符号链接的支持。为了跟踪已创建的符号链接,并可能支持其他可能不直接支持 POSIX 符号链接的平台,我们建议使用一个新的 Wheel 元数据文件 LINKS,它将存在于 .dist-info 目录中,与 METADATARECORD 和其他元数据文件并列。

使用 LINKS 文件将允许更多跨平台使用类似符号链接的功能。在 Windows 上,符号链接需要允许用户创建符号链接的组策略(例如,通过启用开发人员模式)或管理员权限。这意味着在某些用户系统上可能不支持符号链接。通过使用 LINKS 文件,安装程序将能够潜在地使用其他方法来处理符号链接,例如 Windows 上的 junctions,否则安装程序将不得不失败。

本 PEP 还描述了安装程序在安装更新的 Wheel 时必须执行的检查。这些检查旨在处理允许 Wheel 安装符号链接所带来的安全风险。有关这些检查为何重要的更多信息,请参阅安全隐患

规范

Wheel 主版本更新

本 PEP 要求对 Wheel 主版本进行更新,因此使用 LINKS 生成的 Wheel 的 Wheel-Version 必须至少为版本 2.0,以便旧的安装程序不会默默地安装符号链接失败并破坏用户环境。更多信息请参阅 PEP 777

安装程序行为规范

安装程序在决定任何 source_pathtarget_path 是否有效 *之前* 必须解析 LINKS 文件中包含的任何链接的路径。安装程序 必须 验证 source_pathtarget_path 是否位于来自 Wheel 的任何命名空间或包内部。安装程序 必须 拒绝 Wheel 中的循环符号链接。如果一长串符号链接(符号链接多次指向符号链接)超出了安装程序设置的限制,安装程序 可以 报错。

安装程序在处理带有符号链接的 Wheel 时 必须 遵循以下步骤:

  1. 检查 .dist-info 中是否存在 LINKS 文件。如果不存在,则无需进一步操作。
  2. 按照 Wheel 1.x 的方式提取 Wheel 包和数据目录中的所有文件。
  3. 验证对于每个 source_pathtarget_path 对,target_path 是否存在于刚提取的包命名空间之一中。
  4. 接下来,检查安装程序是否可以在 site 目录中为每对创建某种链接。如果安装程序无法为当前平台创建文件/文件夹 target_path 的链接,则 必须 报错。例如,如果 POSIX 符号链接指向文件目标,而安装程序在 Windows 上运行且无法创建符号链接但可以创建 junctions。在这种情况下,安装程序 必须 报错,因为它无法处理该链接。
  5. 最后,安装程序 必须source_pathtarget_path 之间添加一个与平台相关的链接。

安装程序在处理符号链接时 默认不得 复制文件而不是生成符号链接。安装程序 可以 在替代配置或命令行标志下提供此类行为。

构建后端规范

在创建 Wheel 时,构建后端在决定是否将符号链接包含在 Wheel 中时 必须 以与其目标相同的方式对待符号链接。构建后端 必须 验证 LINKS 文件中没有悬空符号链接。构建后端 应该 识别将包含在构建中的与平台相关的符号链接。在 POSIX 系统上,这通常是符号链接;在 Windows 上,这包括符号链接和 junctions。

向后兼容性

引入符号链接将需要 Wheel 格式主版本递增。这意味着使用新 Wheel 格式的新 Wheel 将在旧的安装程序工具上引发错误,根据Wheel 规范

请参阅关于“Wheel 2.0”的 PEP 777

安全隐患

如果处理不当,符号链接可能非常危险。一个简单的例子是,如果用户运行 sudo pip install malicious,并且没有保护措施,那么恶意包可能会覆盖 /etc/shadow 并替换系统上的密码哈希,从而允许恶意登录。

本 PEP 列出了安装程序对 Wheel 中的符号链接进行检查的几项要求,以确保上述攻击无法发生。这意味着安装程序 至关重要 地仔细实施这些安全防护措施,并防止在包安装时被恶意利用。

特别是,安装程序 必须 进行以下检查:

  1. 符号链接不得指向来自 Wheel 的任何包或命名空间之外
  2. 符号链接不得悬空(目标在安装时存在)
  3. 符号链接不得循环,并在达到一定检查深度后停止以避免拒绝服务请求

移除时不要跟随符号链接。

如何教授此内容

一旦这些更改在生态系统中传播开来,最终用户应该透明地体验到 Wheel 中符号链接的好处。如果平台不支持符号链接,安装程序提供清晰的错误消息并解释安装失败的原因非常重要。

对于构建库的人来说,packaging.python.org 上的文档应该描述 Wheel 中符号链接的用例和注意事项(特别是平台支持)。否则,它应该由构建后端透明地处理,就像处理任何普通文件一样。

参考实现

待办事项

被拒绝的想法

库维护者应使用 Python 来定位库

使用 Python 定位库会容易得多。然而,有些库,例如 libtorch,被扩展模块使用,并且本身需要加载依赖项。一些编译库无法使用 Python 找到其加载器依赖项。

未解决的问题

PEP 660 和延迟可编辑安装支持

本 PEP 将 PEP 660 可编辑安装机制的规范和实现留作未解决的问题,待未来的 PEP 处理;是否应在本 PEP 中指定?

安全

本 PEP 需要审查以确保它不会导致新的安全漏洞。我们是否应该对符号链接的来源或目标施加其他限制以保护用户?

先前的讨论

https://discuss.python.org/t/symbolic-links-in-wheels/1945/25


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

最后修改:2025-07-09 03:07:54 GMT