全面介绍 Wheel 分发格式,以及为 Python 创建二进制包,确保在不同平台上高效可靠地分发软件。
Wheel 分发格式:为 Python 创建二进制包
Python 生态系统高度依赖于高效的包管理。 这个生态系统的基石之一是 Wheel 分发格式,通常由 .whl
扩展名标识。 本指南深入探讨了 Wheel 格式的复杂性、它的优点,以及如何为 Python 创建二进制包,以满足全球开发人员的需求,他们希望实现流畅可靠的软件分发。
什么是 Wheel 格式?
Wheel 格式是 Python 的一种已构建包格式。 它的设计比源代码分发 (sdist) 更易于安装。 它取代了旧的 egg 格式,解决了它的几个缺点。 基本上,它是一个具有特定结构和元数据的 ZIP 存档,允许 pip
和其他安装工具快速安装该包,而无需从源代码构建它。
Wheel 的主要特点
- 平台独立性(如适用): Wheels 可以为特定平台和架构构建(例如,Windows 64 位、Linux x86_64),或者可以独立于平台(纯 Python)。 这允许为不同的操作系统创建优化的二进制文件。
- 易于安装: Wheel 格式包括预构建的发行版,最大限度地减少了安装期间编译代码的需要。 这大大加快了安装过程,特别是对于具有 C 扩展或其他编译组件的包。
- 元数据包含: Wheels 包含有关包的所有必要元数据,包括依赖项、版本信息和入口点。 此元数据对于像
pip
这样的包管理器处理依赖项并正确安装包至关重要。 - 原子安装:
pip
以原子方式从 Wheels 安装包。 这意味着安装要么成功完成,要么完全回滚,从而防止部分安装的包,这可能导致不一致。 - 可重现性: Wheels 通过提供一致的构建工件来增强可重现性,该工件可以在多个环境中安装,而无需重新编译(假设目标平台匹配)。
为什么要使用 Wheels?
选择 Wheels 而不是源代码分发提供了许多优势,简化了包的安装和部署过程。 以下是主要优势的细分:
更快的安装时间
Wheels 最重要的优点之一是它们的速度。 通过提供预构建的发行版,Wheels 消除了安装过程中编译代码的需要。 这对于使用 C、C++ 或其他语言编写的具有已编译扩展的包特别有利。 想象一下部署一个复杂的科学库; 使用 Wheel 大大减少了最终用户机器上的设置时间。
示例: 从源代码安装 numpy
可能需要几分钟,尤其是在较旧的硬件上。 从 Wheel 安装通常需要几秒钟。
减少对构建工具的依赖
从源代码安装包通常需要用户在其系统上安装必要的构建工具(编译器、标头等)。 对于不熟悉软件开发的用户来说,这可能是一个障碍。 Wheels 删除了这种依赖性,使安装更简单、更容易访问。
示例: 研究实验室中的数据科学家可能没有从源代码构建包的必要编译器。 Wheel 允许他们直接安装该包,而无需配置其环境。
提高可靠性
通过提供预构建的二进制文件,Wheels 确保包在不同环境中以一致的方式安装。 这降低了由于系统配置或构建工具版本差异导致的安装错误的风险。 这种一致性对于需要稳定和可预测行为的应用程序至关重要。
示例: 部署到多个服务器的 Web 应用程序需要具有一致的包版本。 使用 Wheels 确保在每个服务器上安装相同的二进制文件,从而最大限度地减少部署问题的风险。
增强安全性
Wheels 可以被签名以验证其真实性和完整性。 这有助于防止恶意行为者分发被篡改的包。 包签名提供了额外的安全层,确保用户安装受信任的软件。
示例: 组织可以实施策略,要求所有包在部署到生产环境之前进行签名。 这可以防止供应链攻击,在供应链攻击中,恶意代码被注入到包中。
创建 Wheel 包:分步指南
创建 Wheel 包是一个简单的过程,涉及使用 setuptools
和 wheel
包。 以下是详细指南:
1. 设置您的项目
首先,确保您的项目结构正确。 至少,您需要一个 setup.py
文件和包的源代码。
项目结构示例:
my_package/ ├── my_module/ │ ├── __init__.py │ └── my_function.py ├── setup.py └── README.md
2. setup.py
文件
setup.py
文件是您项目的核心。 它包含有关包的元数据,并定义了应该如何构建和安装它。 这是一个 setup.py
文件的示例:
from setuptools import setup, find_packages setup( name='my_package', version='0.1.0', description='一个简单的示例包', long_description=open('README.md').read(), long_description_content_type='text/markdown', url='https://github.com/your_username/my_package', author='您的姓名', author_email='your.email@example.com', license='MIT', packages=find_packages(), install_requires=['requests'], classifiers=[ '开发状态 :: 3 - Alpha', '目标受众 :: 开发人员', '许可证 :: OSI 批准 :: MIT 许可证', '编程语言 :: Python :: 3', '编程语言 :: Python :: 3.6', '编程语言 :: Python :: 3.7', '编程语言 :: Python :: 3.8', '编程语言 :: Python :: 3.9', ], )
关键字段的说明:
name
:您的包的名称。 这是用户用来安装您的包的名称(例如,pip install my_package
)。version
:您的包的版本号。 遵循语义版本控制 (SemVer) 以获得一致的版本控制实践(例如,0.1.0
、1.0.0
、2.5.1
)。description
:您的包的简短描述。long_description
:您的包的详细描述。 这通常从README.md
文件中读取。url
:您的包的主页或存储库的 URL。author
:包作者的姓名。author_email
:包作者的电子邮件地址。license
:您的包分发的许可证(例如,MIT、Apache 2.0、GPL)。packages
:要包含在您的分发版中的包的列表。find_packages()
自动查找您项目中的所有包。install_requires
:您的包所需的依赖项列表。 当安装您的包时,pip
将自动安装这些依赖项。classifiers
:帮助用户在 PyPI(Python 包索引)上找到您的包的元数据。 这些分类器描述了开发状态、目标受众、许可证和支持的 Python 版本。
3. 安装 wheel
如果您没有安装 wheel
包,您可以使用 pip
安装它:
pip install wheel
4. 构建 Wheel 包
导航到您项目的根目录(setup.py
所在的位置)并运行以下命令:
python setup.py bdist_wheel
此命令将创建一个 dist
目录,其中包含 Wheel 包 (.whl
文件) 和源代码分发版 (.tar.gz
文件)。
5. 找到 Wheel 文件
生成的 Wheel 文件将位于 dist
目录中。 它的名称将遵循 package_name-version-pyXX-none-any.whl
格式,其中:
package_name
:您的包的名称。version
:您的包的版本号。pyXX
:包兼容的 Python 版本(例如,Python 3.7 的py37
)。none
:表示该包与平台无关。any
:表示该包与任何架构兼容。
对于特定于平台的 wheels,none
和 any
标签将被替换为平台和架构标识符(例如,Windows 64 位为 win_amd64
)。
6. 测试 Wheel 包
在分发您的 Wheel 包之前,测试它以确保其正确安装至关重要。 您可以使用 pip
执行此操作:
pip install dist/my_package-0.1.0-py39-none-any.whl
将 dist/my_package-0.1.0-py39-none-any.whl
替换为您的 Wheel 文件的实际路径。
7. 分发您的 Wheel 包
构建并测试您的 Wheel 包后,您可以通过各种渠道分发它:
- PyPI (Python 包索引): 分发 Python 包最常用的方法。 您可以使用
twine
将您的 Wheel 包上传到 PyPI。 - 私有包索引: 对于组织内的内部使用,您可以使用
devpi
或 Artifactory 等工具设置私有包索引。 - 直接分发: 您还可以通过电子邮件、文件共享或其他方式将您的 Wheel 包直接分发给用户。
处理 C 扩展和特定于平台的 Wheels
创建特定于平台的 Wheels,尤其是包含 C 扩展的 Wheels,需要额外的步骤。 这是该过程的概述:
1. 编译 C 扩展
需要为每个目标平台编译 C 扩展。 这通常涉及使用 C 编译器(例如,GCC、MSVC)和特定于平台的构建工具。
示例: 在 Windows 上,您需要使用 Microsoft Visual C++ 编译器来构建 C 扩展。 在 Linux 上,您通常使用 GCC。
2. 使用 cffi
或 Cython
像 cffi
和 Cython
这样的工具可以简化创建 C 扩展的过程。 cffi
允许您直接从 Python 调用 C 代码,而无需自己编写 C 代码,而 Cython
允许您编写类似 C 的代码,这些代码被编译成 C 扩展。
3. 定义特定于平台的依赖项
在您的 setup.py
文件中,您可以使用 setup_requires
和 install_requires
参数定义特定于平台的依赖项。 这允许您为不同的平台指定不同的依赖项。
示例:
from setuptools import setup, Extension import platform if platform.system() == 'Windows': extra_compile_args = ['/O2', '/EHsc'] else: extra_compile_args = ['-O3'] setup( name='my_package', version='0.1.0', ext_modules=[ Extension( 'my_package.my_extension', ['my_package/my_extension.c'], extra_compile_args=extra_compile_args, ), ], )
4. 构建特定于平台的 Wheels
要构建特定于平台的 Wheels,您需要为每个目标平台使用适当的构建环境。 这可能涉及使用虚拟机或容器化技术(如 Docker)。
示例: 要为 Windows 64 位构建一个 Wheel,您需要在安装了 Microsoft Visual C++ 编译器的 Windows 64 位系统上运行构建过程。
Wheel 包创建的最佳实践
遵循最佳实践可确保您的 Wheel 包可靠、可维护且易于使用。 以下是一些主要建议:
1. 使用语义版本控制 (SemVer)
遵循语义版本控制 (SemVer) 以获得一致的版本控制实践。 SemVer 使用三部分版本号 (MAJOR.MINOR.PATCH
) 来指示每个版本中的更改类型。
- MAJOR:指示不兼容的 API 更改。
- MINOR:指示向后兼容的新功能。
- PATCH:指示向后兼容的错误修复。
示例: 以破坏现有代码的方式更改函数的参数将导致主要版本增加(例如,从 1.0.0 增加到 2.0.0)。 添加一个新功能而不更改现有功能将导致次要版本增加(例如,从 1.0.0 增加到 1.1.0)。 修复一个错误将导致补丁版本增加(例如,从 1.0.0 增加到 1.0.1)。
2. 包含 README.md
文件
包含一个 README.md
文件,该文件提供包的详细描述,包括安装说明、使用示例和贡献指南。 这可以帮助用户了解如何使用您的包并鼓励贡献。
3. 编写清晰简洁的文档
为您的包编写清晰简洁的文档,包括 API 文档、教程和示例。 使用 Sphinx 或 Read the Docs 等工具从您的代码注释生成文档。
4. 使用许可证
为您的包选择一个许可证,该许可证明确定义了可以使用、修改和分发它的条款。 常见许可证包括 MIT、Apache 2.0 和 GPL。
5. 彻底测试您的包
使用 pytest
或 unittest
等自动化测试工具彻底测试您的包。 编写单元测试、集成测试和端到端测试,以确保您的包在不同的情况下正常工作。
6. 使用持续集成 (CI)
使用持续集成 (CI) 工具,例如 GitHub Actions、GitLab CI 或 Jenkins,以在对代码库进行更改时自动构建和测试您的包。 这有助于及早发现错误,并确保您的包始终处于工作状态。
7. 签名您的包
签名您的包以验证其真实性和完整性。 这有助于防止恶意行为者分发被篡改的包。 使用 gpg
或 keyring
等工具签名您的包。
高级 Wheel 技术
对于更高级的用例,请考虑这些技术:
1. 使用 build
build
包提供了一种构建 Python 包的现代且标准化的方法。 它同时支持 Wheel 和源代码分发,并提供比 setuptools
更简单的接口。
pip install build python -m build
2. 可编辑安装
可编辑安装允许您以直接链接到源代码的方式安装包。 这对于开发很有用,因为对源代码的更改会立即反映在已安装的包中,而无需重新安装它。
pip install -e .
3. 自定义构建过程
您可以通过定义自定义构建脚本或使用 Meson 或 CMake 等构建系统来定制构建过程。 这允许您处理更复杂的构建场景,例如使用特定的编译器标志构建 C 扩展或链接到外部库。
4. 使用 auditwheel
auditwheel
工具用于审核和修复包含共享库的 Linux Wheels。 它确保 Wheel 包含在各种 Linux 发行版上运行所需的所有依赖项。
pip install auditwheel auditwheel repair dist/my_package-0.1.0-py39-linux_x86_64.whl
结论
Wheel 分发格式是 Python 开发人员实现高效、可靠和安全包分发的重要工具。 通过按照本指南中概述的步骤并采用最佳实践,您可以创建 Wheel 包,从而简化安装过程、减少对构建工具的依赖并改善整体用户体验。 无论您是将包分发给开源社区还是部署内部应用程序,了解和利用 Wheel 格式都是任何 Python 开发人员的宝贵技能。 随着 Python 的不断发展,采用现代打包实践(如 Wheel)可确保您的项目能够面向全球受众,并保持可访问性和可维护性。
通过采用这些实践,您可以为全球更强大和可访问的 Python 生态系统做出贡献。