通常来说,Python 包有两种类型的发行版,如下所示。
• 源代码发行版。
• 构建(二进制)发行版。
源代码发行版是最简单的,也是最不依赖于平台的。对于纯 Python 包,无需动脑选择
它就行。这种发行版只包含 Python 源代码,应该已经是高度可移植的。
更复杂的情况是你的包引入了用其他语言(例如 C 语言)编写的一些扩展。如果包用
户的环境中有合适的开发工具链的话,那么源代码发行版也是可行的。这主要包括编译器
和正确的 C 头文件。对于这种情况,构建发行版的格式可能更适合,因为它可以为特定平
台提供已经构建好的扩展。
1.sdist
sdist 命令是最简单的命令。它创建一棵分发树,其中复制了运行一个包所需要的全部内容。然后这棵树被归档到一个或多个存档文件中(通常只创建一个 tar 文件)。这个存
档基本上是源代码树的副本。
这个命令是从目标系统独立地分发一个包的最简单方法。它将创建一个 dist 文件夹,
里面包含可被分发的存档。为了能够使用它,必须向 setup 传递一个额外参数以提供版本
号。如果你没有提供 version 值,那它将使用 version = 0.0.0,代码如下:
from setuptools import setup
setup(name='acme.sql', version='0.1.1')
这个版本号在升级安装时非常有用。每次发布包时,版本号都会增加,这样目标系统
就知道它发生了变化。
我们运行带有这个额外参数的 sdist 命令,代码如下:
$ python setup.py sdist
running sdist
...
creating dist
tar -cf dist/acme.sql-0.1.1.tar acme.sql-0.1.1
gzip -f9 dist/acme.sql-0.1.1.tar
removing 'acme.sql-0.1.1' (and everything under it)
$ ls dist/
acme.sql-0.1.1.tar.gz
在 Windows 中,存档是一个 ZIP 文件。
版本被用于标记存档名称,这个存档可以在任何拥有 Python 的系统上分发并安装。在
sdist 发行版中,如果包里面包含 C 库或扩展,那么目标系统将负责编译它们。这在基于
Linux 的系统或 Mac OS 中很常见,因为这些系统通常都会提供编译器,但这在 Windows
下却并不常见。因此,如果一个包打算在多个平台中运行,那么分发时应该总是同时提供
预构建的发行版。
2.bdist 和 wheels
为了能够分发预构建的发行版,distutils 提供了 build 命令,可以通过 4 个步骤
来编译包。
• build_py:通过字节编译并将其复制到构建文件夹中来构建纯 Python 模块。
• build_clib:如果包中包含任何 C 库,它会利用 C 编译器在构建文件夹中创建
一个静态库来构建 C 库。
• build_ext:构建 C 扩展,并像 build_clib 一样将结果放在构建文件夹中。
• build_scripts:构建被标记为脚本的模块。如果第一行被设置为!#的话,它还
会修改解释器路径并修改文件模式使其变为可执行文件。
上面每个步骤都是可以被单独调用的命令。编译过程的结果是一个构建文件夹,里面
包含要安装的包所需要的全部内容。distutils 包中还没有提供交叉编译器的选项。也
就是说,这些命令的结果总是针对构建时所使用的操作系统。
如果必须创建一些 C 扩展,构建过程将使用系统编译器和 Python 头文件(Python.h)。
Python 从源代码构建完成之后这个包含(include)文件就是可用的了。对于打包的发行版,
可能需要针对系统发行版的额外包。至少在流行的 Linux 发行版中,它通常被命名为
python-dev。它包含构建 Python 扩展所有必要的头文件。
所使用的 C 编译器是系统编译器。对于基于 Linux 的系统或 Mac OS X 而言,它分别
是 gcc 或 clang。对于 Windows 而言,可以使用 Microsoft Visual C++(有免费可用的命令
行版本),也可以使用开源项目 MinGW。你可以在 distutils 中进行相应的配置。
bdist 命令使用 build 命令来构建二进制发行版。它调用 build 和所有依赖的命令,
然后用和 sdist 相同的方式创建一份存档。
我们在 Mac OS X 系统中为 acme.sql 创建一个二进制发行版,如下所示:
$ python setup.py bdist
running bdist
running bdist_dumb
running build
...
running install_scripts
tar -cf dist/acme.sql-0.1.1.macosx-10.3-fat.tar .
gzip -f9 acme.sql-0.1.1.macosx-10.3-fat.tar
removing 'build/bdist.macosx-10.3-fat/dumb' (and everything under it)
$ ls dist/
acme.sql-0.1.1.macosx-10.3-fat.tar.gz acme.sql-0.1.1.tar.gz
注意,新创建的存档名称中包含系统名称及其发行版本(Mac OS X 10.3)。
在 Windows 中调用相同的命令,将会创建一个特定的发行版存档,如下所示:
C:\acme.sql> python.exe setup.py bdist
...
C:\acme.sql> dir dist
25/02/2008 08:18 <DIR> .
25/02/2008 08:18 <DIR> ..
25/02/2008 08:24 16 055 acme.sql-0.1.win32.zip
1 File(s) 16 055 bytes
2 Dir(s) 22 239 752 192 bytes free
如果一个包里包含 C 代码,那么除了源代码发行版之外,发布尽可能多的不同的二进
制发行版也很重要。至少,对于那些没有安装 C 编译器的人来说,一个 Windows 二进制发
行版是很重要的。
二进制版本中包含一棵可以直接复制到 Python 树中的树。它主要包含一个文件夹,将
被复制到 Python 的 site-packages 文件夹中。它还可能包含缓存字节码文件(在 Python
2 中是*.pyc 文件,在 Python 3 中是__pycache__/*.pyc)。
另一种构建发行版是 wheel 包提供的“wheel”。安装完 wheel 后(例如使用 pip),
它会向 distutils 中添加一个新的 bdist_wheel 命令。它允许创建特定平台的发行版
(目前仅适用于 Windows 和 Mac OS X),作为普通 bdist 发行版的替代。设计它是为了替
代早先 setuptools 引入的另一种发行版—egg。egg 现在已经过时了,所以这里不会介
绍它。使用 wheel 的优点相当多。在 Python Wheels 页面(http://pythonwheels.com/)中提到
的优点如下所示。
• 更快速地安装纯 Python 包和本地 C 扩展包。
• 避免安装任意代码执行(避免 setup.py)。
• 安装 C 扩展不需要 Windows 或 OS X 上的编译器。
• 允许更好的缓存,用于测试和持续集成。
• 创建.pyc 文件作为安装的一部分,以确保它们匹配所使用的 Python 解释器。
• 在跨平台和跨机器上更一致的安装。
根据 PyPA 的推荐,wheel 应该是你的默认分发格式。不幸的是,Linux 平台特定的 wheel
还不可用,因此如果你必须分发带有 C 扩展的包,那么你需要为 Linux 用户创建 sdist 发
行版。