Python 和构建系统

Python 编程语言在构建系统中得到了广泛的应用。如果我们需要为构建系统或与构建系统相关的工具编写代码,Python 通常是首选。

Python 要求

构建树需要 Python 3.8 或更高版本。所有不在 Python 发行版中的 Python 包都包含在源代码树中。因此,您只需要一个原生的 Python 安装,就可以开始工作了。

仅支持 CPython(从 www.python.org 获得的 Python 发行版)。

编译后的 Python 包

构建中有一些功能依赖于编译后的 Python 包(包含 C 源代码的包)。这些功能目前都是可选的,因为并非每个系统都包含构建这些扩展所需的 Python 开发头文件。

我们建议您安装 Python 开发头文件(mach bootstrap 应该可以为您做到这一点),以便您可以利用这些功能。

OS X 系统 Python 的问题

历史上,随 OS X 一起提供的 Python 充满了细微的错误和次优之处。

OS X 10.8 及以下的用户需要安装新的 Python 发行版。对于 OS X 10.9+,这可能不是必需的。但是,我们仍然建议安装单独的 Python,因为 OS X 系统 Python 存在历史问题。

我们建议通过 Homebrew 或 MacPorts 安装 Python。如果您运行 mach bootstrap,则应该为您完成此操作。

虚拟环境

构建系统严重依赖于 venv。Venv 提供独立且隔离的 Python “虚拟环境”。venv 解决的问题是多个 Python 组件之间的依赖关系冲突。如果系统上的两个组件依赖于不同版本的某个包,则可能发生冲突。Python 和 venv 并没有同时管理多个版本的包,而是采取了一种更简单的策略,即将其隔离,避免潜在的冲突。

在构建过程的早期阶段,会在 对象目录 内创建 venv。venv 的配置使其能够找到源代码树中的所有 Python 包。此代码位于 mach.site 中。

缺陷

构建系统中虚拟环境的处理方式存在许多缺陷。

  • mach 重复实现了 venv。

    build/mach_initialize.py 中的代码以与 venv 相同的方式配置 sys.path。有一些错误跟踪了这个问题。但是,还没有找到明确的解决方案。这不是一个大问题,因此不是一个高优先级的问题。

  • 它们在复制和打包过程中不会被保留。

    如果您尝试将整个树从一台机器复制到另一台机器,或者从一个目录复制到另一个目录,则 venv 很可能会崩溃。如果我们能够以某种方式保留它会很好。与其真正解决可移植的 venv,不如说我们真正需要解决的是将填充 venv 的逻辑以及所有依赖文件封装到适当的位置。

  • .pyc 文件写入源目录。

    我们在 venv 中大量依赖于 .pth 文件。.pth 文件是一个特殊的文件,其中包含路径列表。Python 会获取在 .pth 文件中遇到的所有列出的路径,并将其添加到 sys.path 中。

    当 Python 将 .py 文件编译成字节码时,它会写入一个 .pyc 文件,以便它不必再次执行此编译。它将这些 .pyc 文件放在 .pyc 文件旁边。Python 对确定这些 .pyc 文件的位置提供了很少的控制,即使在 Python 3(它提供了自定义导入器)中也是如此。

    由于 .pth 文件指向源代码树中的目录而不是对象目录,因此 .pyc 文件是在源代码树中创建的。这是不好的,因为当 Python 导入模块时,它首先会查找 .pyc 文件,然后才是 .py 文件。如果存在 .pyc 文件,但不存在 .py 文件,它将愉快地导入模块。这在文件移动、重构等过程中会导致混乱。

    有一些修复此问题的提案。请参阅 错误 795995

手动安装 Python

我们强烈建议您使用系统的包管理器或受良好支持的第三方包管理器为您安装 Python。如果这些工具不可用,我们建议使用以下工具安装 Python

如果所有其他方法都失败,请考虑手动从源代码编译 Python。但这应该被视为最不可取的选择。

Python 的常见问题

升级 Python 发行版会破坏 venv

如果您升级 Python 发行版(例如,从 3.6.9 安装 Python 3.6.15),则 venv 的某些部分可能会被破坏。这通常表现为一个神秘的 Cannot import XXX 异常。大多数情况下,正在导入的模块包含二进制/编译后的组件。

如果您升级或重新安装 Python 发行版,我们建议您清理您的构建。

系统级别安装的包与构建系统的包冲突

人们通常使用 sudo(例如 sudo pip install psutil)或系统的包管理器(例如 apt-get install python-mysql)来安装 Python 包。

这样做的问题是,系统级别安装的包可能会与源代码树提供的包冲突。从 错误 907902 和 changeset f18eae7c3b27(2013 年 9 月 16 日)开始,这应该不再是一个问题,因为作为构建的一部分创建的 venv 不会将系统的 site-packages 目录添加到 sys.path 中。但是,安装不当的包仍然可能找到方法侵入到混合环境中,并干扰我们的 venv。

作为一般原则,我们建议不要使用系统的包管理器或使用 sudo 安装 Python 包。相反,为所有 Python 项目创建虚拟环境和隔离的 Python 环境。

Python 不应位于 $PATH 中

mach 这样的工具会通过执行 /usr/bin/env python 或等效命令来查找 Python。请确保适当的 Python 2.7.3+ 路径位于 $PATH 中。在 OS X 上,这可能意味着您需要修改 shell 的初始化脚本,以便在 /usr/bin 之前放置某些内容。