whl编译命令作用解释
命令对比总览
命令 | 主要目的 | 核心输入文件 | 核心输出文件 | 输出物性质 |
---|---|---|---|---|
build_ext | 编译构建扩展模块 | .pyx , .c , .cpp , .cxx , .cc | .so (Unix), .pyd (Win) | 开发中间产物 |
bdist_wheel | 生成二进制分发包 | 所有源码 (.py ) + 已编译的扩展 (.so /.pyd ) | .whl (Wheel) 文件 | 分发最终产物 |
sdist | 生成源代码分发包 | 所有源码 (.py , .pyx , .c 等) + setup.py | .tar.gz 或 .zip 源码包 | 分发原始材料 |
1. build_ext
(构建扩展)
作用: 将 C/C++/Cython 源代码编译为 Python 可导入的二进制扩展模块。这是一个开发阶段的命令。
输入文件类型:
- Cython 源码:
.pyx
,.pxd
(声明文件) - C 源码:
.c
- C++ 源码:
.cpp
,.cxx
,.cc
- 头文件:
.h
,.hpp
(通过include_dirs
指定)
输出文件类型:
- 二进制扩展模块:
- Linux/macOS:
.so
(e.g.,my_module.cpython-39-x86_64-linux-gnu.so
) - Windows:
.pyd
(e.g.,my_module.cp39-win_amd64.pyd
)
- Linux/macOS:
- 中间文件 (通常位于
build/
目录):- 由 Cython 生成的
.c
文件 - 编译器生成的目标文件
.o
(Unix) /.obj
(Windows)
- 由 Cython 生成的
源文件类型 | 处理方式 | 说明 |
---|---|---|
.pyx (Cython) | Cython -> C -> 编译 -> 链接 | 最复杂的流程,build_ext 自动处理所有步骤。 |
.c (Pure C) | 编译 -> 链接 | 跳过 Cython 步骤,直接编译和链接。 |
.cpp / .cxx / .cc (C++) | 编译 -> 链接 | 处理 C++ 代码,会自动使用 C++ 编译器(如 g++)。 |
.py (Cython 模式) | Cython -> C -> 编译 -> 链接 | 如果使用 cythonize 并允许,可将 .py 文件当作 Cython 文件处理。 |
示例文件树 (运行 python setup.py build_ext --inplace
后):
项目初始结构:
my_project/
├── setup.py
├── my_package/
│ ├── __init__.py
│ ├── pure_py_module.py # 纯Python模块
│ └── my_cython_module.pyx # Cython源码
运行命令后结构 (--inplace
选项):
my_project/
├── setup.py
├── build/ # 构建临时目录 (可能生成)
│ └── temp.linux-x86_64-3.9/
│ └── my_cython_module.o
├── my_package/
│ ├── __init__.py
│ ├── pure_py_module.py
│ ├── my_cython_module.pyx # 输入的源文件
│ ├── my_cython_module.c # **输出**:Cython生成的C文件
│ └── my_cython_module.cpython-39-x86_64-linux-gnu.so # **输出**:最终二进制扩展
2. bdist_wheel
(构建Wheel分发包“built distribution” 和 “wheel”)
作用: 创建一个包含所有必需文件(包括预编译好的二进制扩展)的Wheel包(.whl
)。这是分发前的打包命令。
输入文件类型:
- 纯Python源码:
.py
- 包结构:
__init__.py
- 数据文件:
.txt
,.json
,.csv
等 (通过package_data
指定) - 已编译的扩展:
.so
,.pyd
(通常需要先运行build_ext
) - 元数据:
setup.py
,setup.cfg
,pyproject.toml
输出文件类型:
- Wheel 包文件:
.whl
(e.g.,my_package-1.0.0-cp39-cp39-linux_x86_64.whl
)- 注意:文件名编码了Python版本、ABI、平台信息。
示例文件树 (Wheel包 内部 结构):
假设我们有一个混合包(包含纯Python和C扩展),运行 python setup.py build_ext bdist_wheel
后,会生成一个 .whl
文件。这个Wheel文件本质上是一个ZIP包,其内部结构如下:
my_package-1.0.0-cp39-cp39-linux_x86_64.whl
的内部结构:
# 解压后的内容:
.
├── my_package/
│ ├── __init__.py # **输入**:原始的.py源码
│ ├── pure_py_module.py # **输入**:原始的.py源码
│ └── my_cython_module.cpython-39-x86_64-linux-gnu.so # **输入**:由build_ext生成的.so文件
│
└── my_package-1.0.0.dist-info/ # 元数据目录 (自动生成)├── METADATA├── WHEEL├── RECORD└── LICENSE
关键点: Wheel包包含了可直接运行的代码:原始的 .py
和预编译好的 .so
/.pyd
,但不包含 .pyx
或 .c
等中间源文件。
3. sdist
(源代码分发“source distribution”)
作用: 创建一个包含构建分发所需所有原始源代码的归档文件。这是最原始的分发格式。
输入文件类型:
- 所有Python源码:
.py
- 所有扩展源码:
.pyx
,.c
,.cpp
,.cxx
,.cc
,.h
- 包结构:
__init__.py
- 配置文件:
setup.py
,setup.cfg
,pyproject.toml
,MANIFEST.in
- 其他文件:
README.md
,LICENSE.txt
,requirements.txt
等
输出文件类型:
- 源代码归档文件:
.tar.gz
或.zip
(e.g.,my_package-1.0.0.tar.gz
)
示例文件树 (源码包 内部 结构):
运行 python setup.py sdist
后,会生成一个 .tar.gz
文件。其内部包含构建所需的一切原材料:
my_package-1.0.0.tar.gz
的内部结构:
# 解压后的内容:
my_package-1.0.0/
├── setup.py # 核心构建脚本
├── MANIFEST.in # 清单文件 (指定包含哪些额外文件)
├── README.md # 说明文档
├── LICENSE.txt # 许可证
│
└── my_package/├── __init__.py├── pure_py_module.py # 纯Python源码├── my_cython_module.pyx # **Cython源码** (Wheel包里没有这个!)└── my_cython_module.c # **C源码** (可能由开发者预先生成,也可能由打包时自动生成)
关键点: sdist 包是“原料包”,它包含了 .pyx
和 .c
文件。用户从 sdist 安装时,需要在本地机器上执行完整的 build_ext
过程(即编译),这要求用户环境有编译器工具链。
总结与关系
- 依赖关系:要生成一个包含二进制扩展的 Wheel (
bdist_wheel
),你通常需要先运行build_ext
来编译出.so
/.pyd
文件。Wheel 包会将这些二进制文件打包进去。 - 内容差异:
sdist
-> “源代码原料包” (包含.pyx
,.c
)bdist_wheel
-> “即食便当” (包含.py
和.so
/.pyd
,无需编译)
- 使用场景:
- 开发时:使用
build_ext --inplace
进行编译和测试。 - 分发时:使用
sdist
和bdist_wheel
生成分发包,并上传到 PyPI。pip
会优先下载与当前环境匹配的 Wheel 包,因为它安装最快。如果没有匹配的 Wheel,pip
会fallback到下载 sdist 并在本地编译。
- 开发时:使用