setup.py
(已弃用)¶
在引入基于 pyproject.toml 的构建(在 PEP 517 和 PEP 518 中)之前,pip 仅支持使用 setup.py
文件安装包,这些文件使用 setuptools 构建。
这里记录的接口目前仅出于遗留目的保留,直到迁移到基于 pyproject.toml
的构建完成。
注意
pip 对各种 setup.py
调用方式的参数和语法被认为是与 setuptools 强耦合的实现细节。此构建系统接口不应被任何其他构建后端使用,这些后端应该基于 pyproject.toml 构建系统接口。
此外,项目不应期望围绕 setup.py
接口存在任何形式的向后兼容性保证。
构建过程¶
构建包的整体过程是
生成包的元数据。
为包生成一个 wheel。
如果需要,wheel 随后可用于执行安装。
元数据生成¶
作为第一步,pip
需要获取关于包的元数据(名称、版本、依赖项等)。它通过调用 setup.py egg_info
来收集这些信息。
egg_info
命令会生成包的元数据,pip 随后可以消费这些元数据并继续收集包的所有依赖项。一旦依赖项解析过程完成,pip 将继续执行这些包的构建过程的下一阶段。
Wheel 生成¶
当提供一个包的 源代码发行版(或“sdist”) 时,pip 将尝试构建一个 wheel。由于 wheel 发行版可以被 缓存,这可以大大加快包的未来安装速度。
这是通过调用 setup.py bdist_wheel
来完成的,这需要安装 wheel 包。
如果 wheel 生成成功(这可能包括编译 C/C++ 代码,具体取决于包),生成的 wheel 将被添加到 pip 的 wheel 缓存中,并将用于本次安装。构建的 wheel 由 pip 在本地缓存,以避免重复的相同构建。
如果 wheel 生成失败,pip 会运行 setup.py clean
来清理可能已生成的任何构建工件。之后,pip 将尝试直接安装。
可编辑安装¶
对于以“可编辑”模式安装包 (pip install --editable),pip 将调用 setup.py develop
,它将使用 setuptools 的机制来执行可编辑/开发安装。
Setuptools 注入¶
为了支持直接使用 distutils
的项目,pip 在调用 setup.py
之前将 setuptools
注入 sys.modules
。这种注入对于基于 distutils
的项目来说应该是透明的。
定制构建¶
--global-option
和 --build-option
参数用于 pip install
和 pip wheel
会将额外的参数注入到 setup.py
命令中 (--build-option
仅在 pip wheel
中可用)。
注意
使用 --global-option
和 --build-option
非常依赖于 setuptools,并且被认为更多是当前实现中的一个意外,而不是一个受支持的接口。它在这里记录是为了完整性。一旦这个构建系统接口被删除,这些标志将不再受支持。
这些参数在命令中包含如下:
python setup.py <global_options> BUILD COMMAND <build_options>
选项会直接传递,目前提供了对 distutils 命令行的直接访问。例如
$ python -m pip wheel --global-option bdist_ext --global-option -DFOO wheel
$ python -m pip wheel --global-option bdist_ext --global-option -DFOO wheel
C:> py -m pip wheel --global-option bdist_ext --global-option -DFOO wheel
将导致 pip 调用
setup.py bdist_ext -DFOO bdist_wheel -d TARGET
这会将一个预处理器符号传递给扩展构建。
构建输出¶
构建系统产生的任何输出都会被 pip 读取(如果请求则显示给用户)。为了正确读取构建系统输出,pip 要求输出以明确定义的编码方式写入,具体来说是用户为文本输出配置的编码方式(可以通过 Python 中的 locale.getpreferredencoding
获取)。如果配置的编码方式是 ASCII,pip 假设为 UTF-8(以考虑某些 Unix 系统的行为)。
构建系统应确保其调用的任何工具(编译器等)以正确的编码方式生成输出。在实践中,尤其是在 Windows 上,工具在使用“OEM”和“ANSI”代码页方面不一致,这可能并非总是可行。因此,如果遇到编码错误的构建工具输出,pip 会尝试通过将意外的字节序列转换为 Python 风格的十六进制转义序列 ("\x80\xff"
等) 来干净地恢复。但是,输出仍然有可能使用错误的编码方式显示(乱码)。