0
点赞
收藏
分享

微信扫一扫

独立可执行文件

在介绍 Python 代码打包的材料中,创建独立可执行文件是经常被忽略的一个主题。这

主要是因为 Python 标准库中缺少合适的工具能够让程序员创建简单的可执行文件,用户不

需要安装 Python 解释器就可以运行这些可执行文件。

与 Python 相比,编译语言有一个很大的优点,就是它允许为给定的系统架构创建可执

行的应用程序,用户不需要知道底层技术就可以运行。Python 代码作为一个包分发时,需

要有 Python 解释器才能运行。这对于没有足够技术水平的用户来说造成了很大不便。

对开发者友好的操作系统(例如 Mac OS X 或大多数 Linux 发行版)都预装了 Python。

因此对于它们的用户来说,基于 Python 的应用仍然可以作为源代码包分发,依赖于主脚本

文件中特定的解释器指令(interpreter directive),这一指令通常被称为 shebang。对于大多数 Python 应用而言,其格式如下所示:

#!/usr/bin/env python

这种指令放在脚本的第一行,会将其标记为默认由指定环境的 Python 版本进行解释。

当然,它也可以采用更详细的形式,其中包括特定的 Python 版本,例如 python 3.4、

python 3 或 python 2。注意,这适用于大多数 POSIX 系统,但从定义来看并不是可移

植的。这种解决方案依赖于特定 Python 版本的存在,也依赖于/usr/bin/env 的 env 可

执行文件的可用性。在某些操作系统中,这两个假设可能都无法满足。此外,shebang 在

Windows 上也无法使用。另外,即使是有经验的开发人员,Windows 中 Python 环境的引导

也是一项挑战,所以你不能期望非技术用户能够自己完成。

另一件需要考虑的事情是桌面环境中简单的用户体验。用户通常期望,只通过单击就

可以从桌面运行应用程序。并不是所有桌面环境都支持将 Python 应用作为源代码分发。

因此,我们最好能够创建一个二进制发行版,其使用方法与其他任何编译的可执行文

件相同。幸运的是,可以创建一个可执行文件,里面同时嵌入了 Python 解释器和我们的项

目。这样用户无需考虑 Python 或其他依赖就可以打开我们的应用。

独立可执行文件何时有用

如果用户体验的简单性比用户与应用代码交互的能力更加重要,那么独立可执行文件

非常有用。注意,将应用作为可执行文件分发,只会使代码读取或修改更加困难但不

是不可能。这不是保护应用代码的方法,而是应该作为使应用交互更加简单的方法。

独立可执行文件应该是对非技术最终用户分发应用的首选方式,也可能是分发

Windows 上的 Python 应用的唯一合理方式。

独立可执行文件通常适用于以下情形。

• 依赖于特定 Python 版本的应用,该版本在目标操作系统是可能不容易找到。

• 依赖于修改过的预编译 CPython 源代码的应用。

• 带有图形界面的应用。

• 具有许多用不同语言编写的二进制扩展的应用。

• 游戏。

常用工具

Python 没有任何内置库支持构建独立可执行文件。幸运的是,一些社区项目解决了这

一问题,并取得了不同程度的成功。其中最有名的 4 个是:

• PyInstaller;

• cx_Freeze;

• py2exe;

• py2app。

它们中的每一个在使用上都略有不同,每一个也都受到稍微不同的限制。在选择工具

之前,你需要确定面向哪些平台,因为每种打包工具仅支持特定的一些操作系统。

最好的情况是,在项目周期的最开始做出这样的决定。当然,所有这些工具都不需要

在代码中进行深入的交互,但如果你早期就开始构建独立包,那么你可以将整个过程自动

化,并节省未来的集成时间与成本。如果你将这件事放到以后,你可能会发现自己处于这

样的境地:项目构建得过于复杂,以致于所有可用的工具都无法使用。为这样的项目提供

独立可执行文件是有问题的,而且需要大量的时间。

1.PyInstaller

到目前为止,PyInstallerhttp://www.pyinstaller.org/)是将 Python 包冻结为独立可执行

文件的最先进的程序。它在目前每种可用的解决方案中提供最广泛的多平台兼容性,所以

它也是最受推荐的方法。PyInstaller 支持的平台包括:

• Windows(32 位和 64 位);

• Linux(32 位和 64 位);

• Mac OS X(32 位和 64 位);

• FreeBSD、Solaris 和 AIX。

支持的 Python 版本包括 Python 2.7 与 Python 3.3、3.4 和 3.5。它可以在 PyPI 上找到,

所以可以利用 pip 在工作环境中安装它。如果你用这种安装方法时遇到问题,你可以随时

从项目主页上下载安装程序。

不幸的是,它不支持跨平台构建(交叉编译),因此如果你想要为某个特定平台构建独

立可执行文件,那么你需要在那个平台上执行构建。随着许多虚拟化工具的出现,这在今

天并不是一个大问题。如果你的计算机上没有安装某个特定的系统,你可是随时使用

Vagrant,它会为你提供所需要的操作系统作为虚拟机。

简单应用的用法很简单。假设我们的应用包含在名为 myscript.py 的脚本中。这是一个

简单的"Hello world!"应用。我们想要为 Windows 用户创建一个独立可执行文件,我们的源代码

位于文件系统的 D://dev/app 目录下。利用下面这个简短的命令可以将我们的应用打包:

$ pyinstaller myscript.py

2121 INFO: PyInstaller: 3.1

2121 INFO: Python: 2.7.10

2121 INFO: Platform: Windows-7-6.1.7601-SP1

2121 INFO: wrote D:\dev\app\myscript.spec

2137 INFO: UPX is not available.

2138 INFO: Extending PYTHONPATH with paths

['D:\\dev\\app', 'D:\\dev\\app']

2138 INFO: checking Analysis

2138 INFO: Building Analysis because out00-Analysis.toc is non

existent

2138 INFO: Initializing module dependency graph...

2154 INFO: Initializing module graph hooks...

2325 INFO: running Analysis out00-Analysis.toc

(...)

25884 INFO: Updating resource type 24 name 2 language 1033

即使是简单的应用,PyInstaller 的标准输出也相当长,所以为了简洁起见,上一个例子

只截取了一部分。如果在 Windows 上运行,生成的目录和文件结构如下所示:

$ tree /0066

│ myscript.py

│ myscript.spec

├───build

│ └───myscript

│ myscript.exe

│ myscript.exe.manifest

│ out00-Analysis.toc

│ out00-COLLECT.toc

│ out00-EXE.toc

│ out00-PKG.pkg

│ out00-PKG.toc

│ out00-PYZ.pyz

│ out00-PYZ.toc

│ warnmyscript.txt

└───dist

└───myscript

bz2.pyd

Microsoft.VC90.CRT.manifest

msvcm90.dll

msvcp90.dll

msvcr90.dll

myscript.exe

myscript.exe.manifest

python27.dll

select.pyd

unicodedata.pyd

_hashlib.pyd

dist/myscript 目录包含构建应用,现在可以分发给用户。注意,必须分发整个目

录。它包含运行应用所需要的所有附加文件(DLL、编译扩展库等)。利用 pyinstaller

命令的--onefile 开关可以得到更紧凑的发行版,如下所示:

$ pyinstaller --onefile myscript.py

(...)

$ tree /f

├───build

│ └───myscript

│ myscript.exe.manifest

│ out00-Analysis.toc

│ out00-EXE.toc

│ out00-PKG.pkg

│ out00-PKG.toc

│ out00-PYZ.pyz

│ out00-PYZ.toc

│ warnmyscript.txt

└───dist

myscript.exe

如果使用--onefile 选项进行构建,你唯一需要向用户分发的文件就是 dist 目录中

找到的单一可执行文件(这里是 myscript.exe)。对于小型应用来说,这可能是首选选项。

运行 pyinstaller 命令的一个副作用是创建了*.spec 文件。这是一个自动生成的

Python 模块,其中包含如何从源代码创建可执行文件的说明。例如,我们已经在下面的代

码中使用了这个:

# -*- mode: python -*-

block_cipher = None

a = Analysis(['myscript.py'],

pathex=['D:\\dev\\app'],

binaries=None,

datas=None,

hiddenimports=[],

hookspath=[],

runtime_hooks=[],

excludes=[],

win_no_prefer_redirects=False,

win_private_assemblies=False,

cipher=block_cipher)

pyz = PYZ(a.pure, a.zipped_data,

cipher=block_cipher)

exe = EXE(pyz,

a.scripts,

a.binaries,

a.zipfiles,

a.datas,

name='myscript',

debug=False,

strip=False,

upx=True,

console=True )

这个.spec 文件包含前面说过的所有 pyinstaller 参数。如果你对构建执行了大量

自定义,那么这一点是非常有用的,因为它可以用来替代保存配置的构建脚本。一旦创建

完成后,你可以用它而不是 Python 脚本作为 pyinstaller 命令的参数,如下所示:

$ pyinstaller.exe myscript.spec

注意,这是一个真正的 Python 模块,因此你可将其扩展,并利用你已经熟悉的语言对

构建过程执行更复杂的自定义。如果你面向许多不同的平台,那么自定义.spec 文件特别

有用。此外,不是所有的 pyinstaller 选项都可以通过命令行参数使用,只有在修

改.spec 文件时可以使用。

PyInstaller 是一个扩展工具,它对于绝大多数程序的用法都非常简单。无论如何,如果

你有兴趣用它作为分发应用的工具,那么推荐你深入阅读它的文档。

2.cx_Freeze

cx_Freezehttp://cx-freeze.sourceforge.net/)是另一种用于创建独立可执行文件的工具。

它是一种比 PyInstaller 更加简单的解决方案,但也支持 3 个主要平台:

• Windows;

• Linux;

• Mac OS X。

与 PyInstaller 一样,它不允许我们执行跨平台构建,因此你需要在想要分发的同一个

操作系统中创建可执行文件。cx_Freeze 的主要缺点是它不允许我们创建真正的单文件可执

行文件。用它构建的应用都需要与相关的 DLL 文件和库一起分发。假如我们想要创建与

PyInstaller 一节介绍过的相同的应用,示例用法也非常简单,如下所示:

$ cxfreeze myscript.py

copying C:\Python27\lib\site-packages\cx_Freeze\bases\Console.exe ->

D:\dev\app\dist\myscript.exe

copying C:\Windows\system32\python27.dll ->

D:\dev\app\dist\python27.dll

writing zip file D:\dev\app\dist\myscript.exe

(...)

copying C:\Python27\DLLs\bz2.pyd -> D:\dev\app\dist\bz2.pyd

copying C:\Python27\DLLs\unicodedata.pyd ->

D:\dev\app\dist\unicodedata.pyd

生成的文件结构如下所示:

$ tree /f

│ myscript.py

└───dist

bz2.pyd

myscript.exe

python27.dll

unicodedata.pyd

cx_Freeze 扩展了 distutils 包,而不是为构建规范提供自己的格式(像 PyInstaller 那

样)。也就是说,你可以使用熟悉的 setup.py 脚本来配置如何构建独立可执行文件。如果

你已经使用 setuptools 或 distutils 来分发包的话,那么使用 cx_Freeze 非常方便,因

为额外的集成只需要对 setup.py 脚本进行很小的修改。下面是这种 setup.py 脚本的一

个示例,利用 cx_Freeze.setup()在 Windows 上创建独立可执行文件,如下所示:

import sys

from cx_Freeze import setup, Executable

# 自动检测依赖。但可能需要微调。

build_exe_options = {"packages": ["os"], "excludes": ["tkinter"]}

setup(

name="myscript",

version="0.0.1",

description="My Hello World application!",

options={

"build_exe": build_exe_options

},

executables=[Executable("myscript.py")]

)

利用这样一个文件,可以向 setup.py 脚本添加新的 build_exe 命令来创建新的可

执行文件:

$ python setup.py build_exe

cx_Freeze 的用法似乎比 PyInstaller 更简单一些,而且 distutils 集成是一个非常有

用的功能。不幸的是,这个项目可能会给没有经验的开发者带来一些麻烦。

• 在 Windows 中利用 pip 安装可能会有问题。

• 官方文档非常简短,有些地方还是缺失的。

3.py2exe 和 py2app

py2exehttp://www.py2exe.org/)和 py2apphttps://pythonhosted.org/py2app/)是另外

两种用于创建独立可执行文件的程序,通过 distutils 或 setuptools 与 Python 打包

进行集成。这里将它们二者放在一起,是因为它们的用法和限制都非常相似。py2exe 和

py2app 的主要缺点是它们只面向一种平台。

• py2exe 允许构建 Windows 可执行文件。

• py2app 允许构建 Mac OS X 应用。

由于用法非常相似,并且只需要修改 setup.py 脚本,这两个包似乎是互补的。py2app

项目的文档中给出了 setup.py 脚本的以下示例,可以根据所使用的平台选择正确的工具

(py2exe 或 py2app)来构建独立可执行文件,如下所示:

import sys

from setuptools import setup

mainscript = 'MyApplication.py'

if sys.platform == 'darwin':

extra_options = dict(

setup_requires=['py2app'],

app=[mainscript],

# Cross-platform applications generally expect sys.argv to

# be used for opening files.

options=dict(py2app=dict(argv_emulation=True)),

)

elif sys.platform == 'win32':

extra_options = dict(

setup_requires=['py2exe'],

app=[mainscript],

)

else:

extra_options = dict(

# Normally unix-like platforms will use "setup.py install"

# and install the main script as such

scripts=[mainscript],

)

setup(

name="MyApplication",

**extra_options

)

有了这样的脚本,你可以利用 python setup.py py2exe 命令构建 Windows 可执

行文件,也可以利用 python setup.py py2app 构建 Mac OS X 应用。交叉编译当然是

不可能的。

尽管有一些限制,并且灵活性不如PyInstaller或cx_Freeze,但最好知道py2exe和py2app

项目的存在。在某些情况下,PyInstaller 或 cx_Freeze 可能无法正确构建项目的可执行文件。

在这种情况下,检查其他解决方案能否处理我们的代码总是值得的。

举报

相关推荐

0 条评论