跳转到内容
新建笔记

Setuptools:构建、安装与 distutils 迁移

Setuptools 是 Python 项目的构建后端之一。pip 安装项目,build 生成发行文件,pyproject.toml 声明构建要求与项目元数据;这些职责分开后,安装和发布流程更容易复现。

原记录提到 Python 内置的 distutils。这一说明只适用于旧版本:Python 3.12 已从标准库移除它。Setuptools 仍提供兼容实现,但新项目应直接采用受支持的构建接口。参见 Python 3.12 的移除说明。

建立目录 toolchain-demo,包含下面两份文件:

toolchain-demo/
├── pyproject.toml
└── src/
└── vitalogos_toolchain_demo/
└── __init__.py
pyproject.toml
[build-system]
requires = ["setuptools>=65", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "vitalogos-toolchain-demo"
version = "0.1.0"
description = "A small local packaging example"
requires-python = ">=3.11"
[tool.setuptools.packages.find]
where = ["src"]
src/vitalogos_toolchain_demo/__init__.py
def add(left: int, right: int) -> int:
return left + right

这是不含第三方运行依赖的示例。requires 声明构建后端需要的包,requires-python 声明本项目支持的 Python 范围;它们都不是切换当前解释器的命令。若包有运行依赖,应在 [project] 中声明 dependencies,不能只在自己的电脑上安装后就认为用户也会拥有它们。

目录使用 src 布局,可以减少“当前目录刚好能导入”对安装检查的干扰。配置语法见 Setuptools 快速开始。

在已选定的虚拟环境中进入项目根目录:

终端窗口
python -m pip install build
python -m build
python -m pip install dist/vitalogos_toolchain_demo-0.1.0-py3-none-any.whl

python -m build 默认生成源码包 .tar.gz 和 wheel .whl。默认构建会建立隔离环境并安装构建依赖,因此可能访问配置的索引。离线构建时需要提前准备满足声明的工具;--no-isolation 会使用当前环境的构建依赖,不能替代依赖安装。

安装 wheel 后,离开项目目录运行以下程序:

check_installed.py
from importlib.metadata import version
from vitalogos_toolchain_demo import add
assert version("vitalogos-toolchain-demo") == "0.1.0"
assert add(2, 3) == 5
assert add(-4, 1) == -3
print("installed package OK")

这样检查的是已安装的发行包及其元数据。发行名里的连字符与导入名里的下划线用途不同,不必强行写成完全相同的字符串。示例 wheel 的 py3-none-any 来自纯 Python 包;有二进制扩展的项目通常具有平台和 ABI 限制。

原记录的操作现在的常见入口说明
pip install .python -m pip install .安装当前项目,通常由前端调用声明的构建后端
python setup.py sdistpython -m build --sdist只生成源码发行包
python setup.py bdist_wheelpython -m build --wheel只生成 wheel
开发时边改边导入python -m pip install --editable .可编辑安装仍受后端与构建步骤约束

setup.py 作为 Setuptools 配置文件仍可使用;不应把“不再推荐直接用它执行安装和发行构建”理解成“任何含有 setup.py 的项目都失效”。需要动态配置或兼容旧项目时,应按项目实际构建规则处理。区别见 setup.py 的弃用范围。

原记录中的 python setup.py build_ext --inplace 用于已经声明了扩展模块的 Setuptools 项目:编译扩展,并把可导入的扩展产物放到源码包对应位置。它要求实际存在扩展源码、正确的扩展声明、Python 开发头文件及匹配的编译器;上面的纯 Python 示例没有扩展,所以不能拿它证明该命令完成了 C/C++ 编译。

--inplace 不会自动打包依赖库,也不会使 Windows、Linux 或不同 Python ABI 的产物通用。可编辑安装有时仍需重新编译扩展,修改 C/C++ 文件后不能假定旧二进制会自动更新。build_ext 作为构建阶段仍然有用途,具体工程方式见 Setuptools 扩展模块文档。

本文验证范围是纯 Python 包的源码包、wheel、安装与导入;没有据此宣称验证过某个未提供源码的 C/C++ 扩展。包管理与索引配置见 pip。