5. 创建构建的分布 — Python 文档
5. 创建内置分布
“内置发行版”是您可能习惯于将其视为“二进制包”或“安装程序”(取决于您的背景)的东西。 不过,它不一定是二进制的,因为它可能只包含 Python 源代码和/或字节码; 我们不称它为包,因为 Python 中已经使用了这个词。 (“安装程序”是一个特定于主流桌面系统世界的术语。)
一个内置的发行版让你的模块发行版的安装者尽可能地轻松:对于基于 RPM 的 Linux 系统的用户来说,它是一个二进制 RPM; 对于 Windows 用户,它是一个可执行的安装程序; 对于基于 Debian 的 Linux 用户,它是一个 Debian 软件包; 等等。 显然,没有人能够为太阳底下的每个平台创建构建的发行版,因此 Distutils 旨在使模块开发人员能够专注于他们的专长——编写代码和创建源代码发行版——而一种称为 打包者的中间物种 应运而生,将源代码分发版转变为适用于与打包程序一样多的平台的构建分发版。
当然,模块开发者可以是他们自己的打包者; 或者打包者可能是“在那里”某个地方的志愿者,他可以访问原始开发人员没有的平台; 或者它可能是软件定期获取新的源代码分发并将它们转换为软件可以访问的尽可能多的平台的内置分发。 不管他们是谁,打包者都使用安装脚本和 bdist 命令系列来生成构建的发行版。
作为一个简单的例子,如果我在 Distutils 源代码树中运行以下命令:
python setup.py bdist
然后 Distutils 构建我的模块发行版(在本例中为 Distutils 本身),进行“假”安装(也在 build
目录中),并为我的平台创建默认类型的内置发行版。 构建发行版的默认格式在 Unix 上是一个“哑”tar 文件,在 Windows 上是一个简单的可执行安装程序。 (该 tar 文件被认为是“哑巴”文件,因为它必须在特定位置解压才能工作。)
因此,在 Unix 系统上的上述命令创建 Distutils-1.0.plat.tar.gz
; 从正确的位置解压这个 tarball 会安装 Distutils,就像你已经下载了源代码发行版并运行 python setup.py install
。 (“正确的地方”是文件系统的根目录或 Python 的 prefix
目录,具体取决于 bdist_dumb 命令的选项;默认是制作相对于 [X211X ]。)
显然,对于纯 Python 发行版,这并不比仅仅运行 python setup.py install
更简单——但是对于非纯发行版,其中包括需要编译的扩展,这可能意味着有人能够是否使用您的扩展。 即使您的发行版不包含任何扩展,创建“智能”构建的发行版(例如 RPM 包或 Windows 的可执行安装程序)对用户来说也更加方便。
bdist 命令有一个 --formats
选项,类似于 sdist 命令,您可以使用它来选择要生成的构建分发的类型:例如,
python setup.py bdist --format=zip
在 Unix 系统上运行时,会创建 Distutils-1.0.plat.zip
——同样,这个存档将从根目录解压以安装 Distutils。
构建发行版的可用格式有:
格式 | 说明 | 笔记 |
---|---|---|
gztar
|
gzip 压缩的 tar 文件 (.tar.gz )
|
(1),(3) |
ztar
|
压缩的 tar 文件 (.tar.Z )
|
(3) |
tar
|
tar 文件 (.tar )
|
(3) |
zip
|
压缩文件 (.zip )
|
(2),(4) |
rpm
|
转速 | (5) |
pkgtool
|
Solaris pkgtool | |
sdux
|
HP-UX swinstall | |
wininst
|
适用于 Windows 的自解压 ZIP 文件 | (4) |
msi
|
微软安装程序。 |
注意事项:
- Unix 上的默认值
- Windows 上的默认设置
- 需要外部实用程序:tar 和 gzip、bzip2 或 compress 之一
- 需要外部 zip 实用程序或 zipfile 模块(自 Python 1.6 起成为标准 Python 库的一部分)
- 需要外部 rpm 实用程序,版本 3.0.4 或更高(使用
rpm --version
找出您的版本)
您不必将 bdist 命令与 --formats
选项一起使用; 您也可以使用直接实现您感兴趣的格式的命令。 其中一些 bdist “子命令”实际上生成了几种类似的格式; 例如,bdist_dumb 命令生成所有“哑”存档格式(tar
、ztar
、gztar
和 zip
) , 和 bdist_rpm 生成二进制和源 RPM。 bdist 子命令以及每个子命令生成的格式是:
命令 | 格式 |
---|---|
bdist_dumb | 焦油,ztar,gztar,zip |
bdist_rpm | 转速,转速 |
bdist_wininst | 赢在 |
bdist_msi | 微星 |
以下部分详细介绍了各个 bdist_* 命令。
5.1. 创建愚蠢的构建发行版
5.2. 创建 RPM 包
许多流行的 Linux 发行版都使用 RPM 格式,包括 Red Hat、SuSE 和 Mandrake。 如果其中一个(或任何其他基于 RPM 的 Linux 发行版)是您常用的环境,那么为同一发行版的其他用户创建 RPM 包是微不足道的。 根据模块发行版的复杂性以及 Linux 发行版之间的差异,您还可以创建适用于不同基于 RPM 的发行版的 RPM。
创建模块发行版的 RPM 的常用方法是运行 bdist_rpm 命令:
python setup.py bdist_rpm
或带有 --format
选项的 bdist 命令:
python setup.py bdist --formats=rpm
前者允许您指定特定于 RPM 的选项; 后者允许您在一次运行中轻松指定多种格式。 如果您需要同时执行这两项操作,您可以明确指定多个 bdist_* 命令及其选项:
python setup.py bdist_rpm --packager="John Doe <jdoe@example.org>" \
bdist_wininst --target-version="2.0"
创建 RPM 包由 .spec
文件驱动,就像使用 Distutils 由安装脚本驱动一样。 为了让您的生活更轻松,bdist_rpm 命令通常会根据您在安装脚本、命令行和任何 Distutils 配置文件中提供的信息创建一个 .spec
文件。 .spec
文件中的各种选项和部分源自安装脚本中的选项,如下所示:
RPM .spec 文件选项或部分
|
Distutils 设置脚本选项 |
---|---|
姓名 | name
|
总结(在序言中) | description
|
版本 | version
|
供应商 | author 和author_email , 或者 - &maintainer 和maintainer_email
|
版权 | license
|
网址 | url
|
%description (section) | long_description
|
此外,.spec
文件中有许多选项在安装脚本中没有相应的选项。 其中大部分是通过 bdist_rpm 命令的选项处理的,如下所示:
RPM .spec 文件选项或部分
|
bdist_rpm 选项 | 默认值 |
---|---|---|
发布 | release
|
“1” |
集团 | group
|
“开发/图书馆” |
供应商 | vendor
|
(见上文) |
打包机 | packager
|
(无) |
提供 | provides
|
(无) |
需要 | requires
|
(无) |
冲突 | conflicts
|
(无) |
过时的 | obsoletes
|
(无) |
分布 | distribution_name
|
(无) |
构建要求 | build_requires
|
(无) |
图标 | icon
|
(无) |
显然,即使在命令行上提供这些选项中的一些也会很乏味且容易出错,因此通常最好将它们放在安装配置文件 setup.cfg
中—请参阅 编写安装程序部分配置文件。 如果您分发或打包许多 Python 模块分发,您可能希望将适用于所有这些分发的选项放在您的个人 Distutils 配置文件 (~/.pydistutils.cfg
) 中。 如果要暂时禁用此文件,可以将 –no-user-cfg 选项传递给 setup.py。
构建二进制 RPM 包需要三个步骤,所有这些都由 Distutils 自动处理:
- 创建一个
.spec
文件,它描述了包(类似于 Distutils 安装脚本;实际上,安装脚本中的大部分信息都在.spec
文件中) - 创建源 RPM
- 创建“二进制”RPM(可能包含也可能不包含二进制代码,具体取决于您的模块发行版是否包含 Python 扩展)
通常,RPM 将最后两个步骤捆绑在一起; 当您使用 Distutils 时,所有三个步骤通常都捆绑在一起。
如果您愿意,可以将这三个步骤分开。 可以使用--spec-only
选项使bdist_rpm只创建.spec
文件并退出; 在这种情况下,.spec
文件将被写入“分发目录”——通常是 dist/
,但可以使用 --dist-dir
选项进行自定义。 (通常,.spec
文件位于“构建树”的深处,位于由 bdist_rpm 创建的临时目录中。)
5.3. 创建 Windows 安装程序
可执行安装程序是 Windows 上二进制分发的自然格式。 它们显示了一个漂亮的图形用户界面,显示了从安装脚本中的元数据中获取的有关要安装的模块分发的一些信息,让用户选择几个选项,然后开始或取消安装。
由于元数据是从安装脚本中获取的,因此创建 Windows 安装程序通常就像运行一样简单:
python setup.py bdist_wininst
或带有 --formats
选项的 bdist 命令:
python setup.py bdist --formats=wininst
如果您有一个纯模块发行版(仅包含纯 Python 模块和包),则生成的安装程序将独立于版本并具有类似 foo-1.0.win32.exe
的名称。 这些安装程序甚至可以在 Unix 平台或 Mac OS X 上创建。
如果您有非纯发行版,则扩展只能在 Windows 平台上创建,并且取决于 Python 版本。 安装程序文件名将反映这一点,现在格式为 foo-1.0.win32-py2.0.exe
。 您必须为要支持的每个 Python 版本创建一个单独的安装程序。
在正常和优化模式下安装到目标系统后,安装程序将尝试将纯模块编译为 字节码 。 如果您出于某种原因不希望发生这种情况,您可以使用 --no-target-compile
和/或 --no-target-optimize
选项运行 bdist_wininst 命令。
默认情况下,安装程序在运行时会显示很酷的“Python Powered”徽标,但您也可以提供自己的 152x261 位图,该位图必须是带有 --bitmap
选项的 Windows .bmp
文件。
安装程序在运行时还会在桌面背景窗口上显示一个大标题,该标题由您的发行版名称和版本号构成。 可以使用 --title
选项将其更改为其他文本。
安装程序文件将写入“分发目录”——通常为 dist/
,但可使用 --dist-dir
选项进行自定义。
5.4. Windows 上的交叉编译
从 Python 2.6 开始,distutils 能够在 Windows 平台之间进行交叉编译。 实际上,这意味着安装正确的工具后,您可以使用 32 位版本的 Windows 创建 64 位扩展,反之亦然。
要为备用平台构建,请在构建命令中指定 --plat-name
选项。 当前有效值为“win32”、“win-amd64”和“win-ia64”。 例如,在 32 位版本的 Windows 上,您可以执行:
python setup.py build --plat-name=win-amd64
构建 64 位版本的扩展。 Windows 安装程序也支持此选项,因此命令:
python setup.py build --plat-name=win-amd64 bdist_wininst
将在您的 32 位版本的 Windows 上创建一个 64 位安装可执行文件。
要交叉编译,您必须下载 Python 源代码并为您所针对的平台交叉编译 Python 本身 - 从 Python 的二进制安装中是不可能的(因为其他平台的 .lib 等文件不包括在内。)在实践中,这意味着 32 位操作系统的用户将需要使用 Visual Studio 2008 打开 Python 源代码树中的 PCBuild/PCbuild.sln
解决方案,并在交叉之前构建“pythoncore”项目的“x64”配置- 编译扩展是可能的。
请注意,默认情况下,Visual Studio 2008 不安装 64 位编译器或工具。 您可能需要重新执行 Visual Studio 安装过程并选择这些工具(使用控制面板->[添加/删除] 程序是检查或修改现有安装的便捷方法。)
5.4.1. 安装后脚本
从 Python 2.3 开始,可以使用 --install-script
选项指定安装后脚本。 必须指定脚本的基本名称,并且脚本文件名还必须列在 setup 函数的脚本参数中。
复制所有文件后,此脚本将在安装时在目标系统上运行,其中 argv[1]
设置为 -install
,并在卸载时再次使用 argv[1]
设置为 -remove
。
安装脚本嵌入在 Windows 安装程序中运行,每个输出(sys.stdout
、sys.stderr
)都被重定向到缓冲区中,并在脚本完成后显示在 GUI 中。
某些在此上下文中特别有用的函数可作为安装脚本中的附加内置函数使用。
- directory_created(path)
file_created(path)
- 在安装时由 postinstall 脚本创建目录或文件时,应调用这些函数。 它将向卸载程序注册 path,以便在卸载发行版时将其删除。 为安全起见,只有在目录为空时才会删除目录。
- get_special_folder_path(csidl_string)
此功能可用于检索 Windows 上的特殊文件夹位置,如开始菜单或桌面。 它返回文件夹的完整路径。 csidl_string 必须是以下字符串之一:
"CSIDL_APPDATA" "CSIDL_COMMON_STARTMENU" "CSIDL_STARTMENU" "CSIDL_COMMON_DESKTOPDIRECTORY" "CSIDL_DESKTOPDIRECTORY" "CSIDL_COMMON_STARTUP" "CSIDL_STARTUP" "CSIDL_COMMON_PROGRAMS" "CSIDL_PROGRAMS" "CSIDL_FONTS"
如果无法检索文件夹,则会引发
OSError
。哪些文件夹可用取决于确切的 Windows 版本,也可能取决于配置。 有关详细信息,请参阅 Microsoft 的
SHGetSpecialFolderPath()
函数文档。
- create_shortcut(target, description, filename[, arguments[, workdir[, iconpath[, iconindex]]]])
- 此函数创建一个快捷方式。 target是快捷方式要启动的程序的路径。 description 是快捷方式的描述。 filename 是用户将看到的快捷方式的标题。 arguments 指定命令行参数(如果有)。 workdir 是程序的工作目录。 iconpath是包含快捷方式图标的文件,iconindex是文件iconpath中图标的索引。 同样,有关详细信息,请参阅 Microsoft 文档
IShellLink
接口。
5.5. Vista 用户访问控制 (UAC)
从 Python 2.6 开始,bdist_wininst 支持 --user-access-control
选项。 默认值为“none”(表示未完成 UAC 处理),其他有效值为“auto”(表示如果为所有用户安装了 Python 则提示 UAC 提升)和“force”(表示始终提示提升)。