跨平台打包与安装器制作实战 - 第1节

一、打包工具全景:四大金刚横评

做Python开发这么多年,我遇到过最头疼的问题之一就是——「写得好好的程序,怎么到别人电脑上就跑不起来了?」

依赖环境不对、Python版本不一致、缺少某个DLL……这些坑我全踩过。后来我学乖了,老老实实研究打包工具。今天咱们就把市面上最主流的四个工具掰开揉碎聊一聊。

1.1 PyInstaller —— 江湖老大哥

PyInstaller 是我用得最多的工具。为什么?因为它省心。

你只需要一条命令:

pyinstaller --onefile --windowed my_app.py

它就能把你的Python脚本和所有依赖打包成一个独立的exe。我曾在Windows、macOS、Linux上都跑过,基本没出过大问题。

核心特点:

  • 支持一键打包成单个文件
  • 自动识别大部分第三方库
  • 跨平台支持(Win/Mac/Linux)
  • 社区活跃,遇到问题好搜答案

我的小技巧: 如果你用了OpenCV或Pandas这类大库,记得加 --exclude-module 排除不需要的模块。我曾经打包一个200KB的脚本,结果生成了500MB的exe……后来发现是打包了整个numpy。

1.2 cx_Freeze —— 老牌劲旅

cx_Freeze 比 PyInstaller 更早出现。它的打包方式不太一样——不是把文件塞进一个exe,而是生成一个文件夹,里面放着你的程序和所有依赖。

cxfreeze my_app.py --target-dir dist

我个人觉得,cx_Freeze 的配置更灵活。你可以用 setup.py 精细控制打包内容:

from cx_Freeze import setup, Executable

setup(
    name="MyApp",
    version="1.0",
    description="我的应用",
    executables=[Executable("my_app.py")]
)

注意: cx_Freeze 对某些GUI框架的支持不如PyInstaller好。我试过用它打包PyQt5应用,结果按钮图标全丢了……后来还是换回了PyInstaller。

1.3 Nuitka —— 性能怪兽

Nuitka 不是简单的打包工具。它把你的Python代码编译成C++,然后再生成可执行文件。说白了,它做的是「编译」而不是「打包」。

nuitka --standalone --onefile my_app.py

为什么我要提它?因为性能。我做过测试,同样的计算密集型程序,用Nuitka编译后运行速度能提升30%-50%。

适用场景:

  • 对性能有要求的应用
  • 需要保护源码(编译后反编译难度大)
  • 想体验「Python也能编译」的快感

避坑指南: 我曾经用Nuitka打包一个用了很多动态导入的项目,结果编译后一堆模块找不到。Nuitka对动态特性的支持有限,如果你的代码大量使用 __import__ 或 importlib,建议先用PyInstaller试试。

1.4 Briefcase —— 新秀登场

Briefcase 是 BeeWare 项目的一部分。它的野心很大——不仅打包,还要帮你生成安装包(.dmg、.msi、.deb)。

briefcase create
briefcase build
briefcase package

嗯,这里要注意。Briefcase 目前还不够成熟。我试过用它打包一个简单的Tkinter应用,结果在macOS上折腾了两天才跑通。但它的理念我很喜欢——一次配置,到处打包。

工具 打包速度 生成体积 跨平台 学习成本 推荐指数
PyInstaller ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 9/10
cx_Freeze ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ 7/10
Nuitka ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐ 8/10
Briefcase ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐ 6/10

二、跨平台打包的挑战

你以为选好工具就万事大吉了?太天真了。跨平台打包的坑,一个比一个深。

2.1 路径分隔符的噩梦

Windows用反斜杠 \,Mac和Linux用正斜杠 /。我见过太多人写死路径:

# 错误写法
file_path = "data\\config.json"

# 正确写法
import os
file_path = os.path.join("data", "config.json")

你想想看,在Windows上测试得好好的,一放到Linux服务器上就报错。这种问题排查起来特别费时间。

2.2 动态链接库的依赖地狱

Python的很多库底层调用了C/C++代码。比如Pillow依赖libjpeg,lxml依赖libxml2。这些动态库在不同平台上名字不一样:

  • Windows: .dll
  • macOS: .dylib
  • Linux: .so

我曾经踩过的坑: 在Windows上打包一个用了OpenCV的应用,一切正常。结果发给用Mac的同事,打开直接闪退。查了半天,发现是OpenCV的videoio模块在macOS上需要额外的ffmpeg库。最后我不得不在打包脚本里手动指定了依赖路径。

2.3 编码问题

Windows默认用GBK编码,Mac和Linux用UTF-8。如果你的程序读写文件时没指定编码,换台机器就可能乱码。

# 保险的做法
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()

三、选型策略

说了这么多,到底该选哪个?我个人的建议是这样的:

我的选型原则:

  1. 新手入门: 无脑选PyInstaller。社区大、文档全、坑少。
  2. 性能敏感: 试试Nuitka。虽然编译慢,但运行快。
  3. 需要生成安装包: 用Briefcase或PyInstaller+NSIS组合。
  4. 企业级项目: 建议PyInstaller + CI/CD自动化打包。

你可能会问:「为什么不用cx_Freeze?」说实话,它现在有点跟不上时代了。除非你维护的是老项目,否则我不建议在新项目里用它。

最后说一句: 不管你选哪个工具,一定要在目标平台上做测试。我习惯在Windows、macOS、Ubuntu三台机器上都跑一遍打包后的程序。别嫌麻烦,这步省了,后面可能更麻烦。

下一章,咱们会手把手教你用PyInstaller打包一个完整的桌面应用。到时候我会把那些坑一个个指给你看。