Nuitka 目前 (2024.3.16) 最高只支持到 Python 3.11.x,而且实测中对于高版本的 numpy,PyInstaller 和 Nuitka 都不支持(会出现导入错误)。因此这里使用的是 numpy = "1.24.1"

背景:最近有个需求涉及科学计算,使用了 Python 的 Numpy 和 Scipy。然后使用了 Next.js + Ant Design 作为前端(UI),后端用 FastAPI 提供计算。最终交付给用户时肯定是不希望用户去装 Python 环境,加上可能需要对一些内部算法进行保密,因此需要打包成可执行程序。

PyInstaller

PyInstaller 可以打包 Python 程序和它依赖到单个包。用户使用的时候就不需要安装 Python 解释器和其它模块。

最简单的使用就是,安装完直接对脚本进行打包:

1
2
pip install -U pyinstaller
pyinstaller your_program.py

默认情况下是打包到一个文件夹里的,好处是依赖很清晰,而且如果依赖没有改变,后续更新代码后只需要更新对应的代码的可执行文件,而不需要更新整个打包。

打包成一个单独的 exe 的好处是非常方便,只有一个 exe。通常来说,单独一个 exe 也往往比一个文件夹的东西小。

内部的实现

PyInstaller 会分析你的脚本,然后得到脚本运行时依赖的各个模块(库),然后把这些依赖连同 Python 解释器拷贝到一个文件夹里,也可以直接打包在一个 exe 里。

PyInstaller 会分析 import 的语句,找到所依赖的模块。但是有一些使用类似 __import__()importlib.import_module() 或者 sys.path 在代码中引入的模块是没办法自动被识别的。这种情况需要额外指明这些依赖。

Nuitka

Nuitka 应该说并不是专门用于打包 Python 脚本的。Nuitka 是一个用 Python 写的(written in Python) Python 编译器。编译之后可以不需要分开的 Python 解释器。

目前只支持到 3.11,还不支持 3.12。

使用 Nuitka 相对 PyInstaller 需要的环境会更加复杂一些,额外需要一个 C 的编译器。但如果安装过 Visual Studio(不是 Visual Studio Code),一般就可以了。当然 MinGW64 也是可以的。

最基础的用法和 PyInstaller 差不多:

1
2
python -m pip install nuitka
python -m nuitka hello.py

由于 Nuitka 需要重新编译依赖,实测上打包速度是比较慢的。

数据文件

如果需要额外的附加数据文件,比如静态网页。想要在打包时自动拷贝到文件夹下,而不是手动拷贝。在 PyInstaller 中可以使用,--add-data

  • --add-data 的格式是 source:dest,提供需要拷贝的路径和目标路径

图标和基础信息

pyinstaller 附加图标只需要使用 -i,例如:pyinstaller -i "gu.ico" ×××.py

Specfile

PyInstaller 除了可以使用基础的命令行进行打包,也可以直接通过 specfile 更直观的定制生成。其实,即使使用命令行进行打包,也会生成 .spec 文件的。

下面不加任何指定命令生成的 .spec 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# -*- mode: python ; coding: utf-8 -*-


a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)

exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

参考资料

  1. PyInstaller 官方文档
  2. Nuitka 官网