前言

目录对python程序进行打包方式主要有5种: py2exe、py2app,pyinstaller,cx_Freeze,nuitka。本文介绍一种新工具: PyOxidizer。

本文是使用使用PyOxidizer构建独立的Python应用程序的一个笔记。

基本按照官方教程的引导。

PyOxidizer

PyOxidizer是indygreg开源了一个项目,用于构建独立的Python应用程序。文档在这儿

有趣的是, PyOxidizer本身基于Rust, 个中原因indygreg这篇文章里做了阐述。

安装

为了使用PyOxidizer,首先需要按照Rust环境。

安装Rust

Rust版本要求: 1.33+.

可以按照rust官方官方的引导说明来安装。

我在MacOS环境里工作,我准备使用rustup,方便将来管理Rust版本,安装过程非常简单: brew install rustup

如果你也使用rustup,安装好之后接下来运行:rustup-init

安装完成之后检查版本:

1
2
➜  ~ rustc --version
rustc 1.35.0 (3c235d560 2019-05-20)

安装PyOxidizer

cargo install pyoxidizer

安装完成后,尝试运行它:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
➜  ~ pyoxidizer
PyOxidizer 0.1.2
Gregory Szorc <gregory.szorc@gmail.com>
Build and distribute Python applications

USAGE:
    pyoxidizer [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    add                             Add PyOxidizer to an existing Rust project. (EXPERIMENTAL)
    analyze                         Analyze a built binary
    build                           Build a PyOxidizer enabled project
    build-artifacts                 Process a PyOxidizer config file and build derived artifacts
    help                            Prints this message or the help of the given subcommand(s)
    init                            Create a new Rust project embedding Python.
    python-distribution-extract     Extract a Python distribution archive to a directory
    python-distribution-licenses    Show licenses for a given Python distribution
    run                             Build and run a PyOxidizer application
    run-build-script                Run functionality that a build script would perform

使用

创建项目

pyoxidizer init pyapp

该命令将创建一个支持嵌入Python的Rust项目。运行完命令,将打印相关信息及下一步该做什么的提示。

根据提示信息,依次运行:

1
2
3
cd pyapp
pyoxidizer build # 第一次运行会下载对应平台的Python解释器
pyoxidizer run

如果一切顺利,pyoxidizer run将启动了一个Rust可执行文件,它启动了一个交互式Python调试器!尝试输入一些Python代码:

1
2
>>> print("hello, world")
hello, world

自定义Python和打包行为

自定义

项目根目录里有一个自动生成的pyoxidizer.toml文件,该文件决定默认运行时行为。

找到[[embedded_python_run]]部分, 这部分决定Python解释器启动时要执行的操作,调整为:

1
2
3
[[embedded_python_run]]
mode = "eval"
code = "import uuid; print(uuid.uuid4())"

现在我们告诉解释器启动时运行:eval(import uuid; print(uuid.uuid4())

pyoxidizer run输出的结果为: 4ef94bc0-4cbe-4404-9269-0690fec68094

打包第三方库

接下来,让我们试着打包现有的Python应用程序!

我们试着打包第三方库:pyflakes

编辑配置文件:pyoxidizer.toml,使得:

1
2
3
[[packaging_rule]]
type = "pip-install-simple"
package = "pyflakes==2.1.1"

以及

1
2
3
[[embedded_python_run]]
mode = "eval"
code = "from pyflakes.api import main; main()"

这将告诉PyOxidizer你要安装pyflakes的2.1.1版本。在构建时,会运行pip install pyflakes==2.1.1,并将它们添加到生成的二进制文件中。我们试试看:pyoxidizer run -- --help

新的pyoxidizer.toml文件应该类似于:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Multiple [[python_distribution]] sections elided for brevity.

[[build]]
application_name = "pyflakes"

[[embedded_python_config]]
raw_allocator = "system"

[[packaging_rule]]
type = "stdlib-extensions-policy"
policy = "all"

[[packaging_rule]]
type = "stdlib"
include_source = false

[[packaging_rule]]
type = "pip-install-simple"
package = "pyflakes==2.1.1"

[[embedded_python_run]]
mode = "eval"
code = "from pyflakes.api import main; main()"

成功为pyflakes制作了一个可执行文件!

参考