通常来说,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 发

行版。