跳转至

三种python打包方案踩坑总结

pyinstaller 打包问题

有的时候会出现打包失败的问题,这个可以参考pyinstaller使用注意事项

cx_freeze 打包问题

如果直接使用cxfreeze -c hello.py --target-dir dist的话,会发现cx_freeze把python标准库都给打包进去了,就比如这次打包一个tree模拟程序,虽然用7z压缩之后只有7M,但是解压之后竟然有21M,有些大,pyinstaller打包标准库也不过才6、7M,后来通过查找资料,了解到可以通过排除模块,因此写出了以下的命令cxfreeze -c hello.py --target-dir dist --exclude tkinter,email,http(后面还可以继续写用不到的模块,暂时先列出这几个),这样不断的调整,在不影响使用的前提下,打包之后的程序只有11M左右,压缩之后也只有4M,这个大小看着还行 还有,这次打包tree模拟程序时,发现在主机上打包会出现稀奇古怪的问题,哪怕是在虚拟环境中打包,也会出现一些问题,之后放在虚拟机里面打包,就没有这些问题了

nuitka打包问题

目前能通过打包的命令如下:

Bash
nuitka --standalone --mingw64 --plugin-enable=pyqt5 --windows-disable-console --output-dir=out --  
nofollow-import-to=tkinter,numpy,pillow,PIL TAssistant.py
在打包TAssistant时,会出现无法打包的问题,经过多次测试发现,虽然通过--include-module=pydoc,以为导入了pydoc,但是却并没有正确导入,所以目前的解决办法是在TAssistant.py中直接加入一个import pydoc,这样就强制导入pydoc模块了 其他可用的参数:

--windows-icon-from-ico=resource/images/logo.png(导入图标)

--windows-company-name={AUTHOR}(软件信息,同下)

--windows-product-name={app_name}

--windows-product-version={VERSION}

--follow-import-to=common,components,view(如果有多个目录中含有python脚本,建议增加这一句命令)

Note

  1. 建议还是在虚拟环境中打包比较好,以免引入一些不需要的模块,导致程序体积增大

  2. 有的PyQt/PySide项目中含有类似QThreadpooolQSql等,如果想要使用Nuitka,需要将PyQt5迁移到PySide6,经过测试使用PySide6框架打包兼容性最好,但如果使用PyQt5PyQt6PySide2等,都会出现一些兼容问题导致无法正常运行

  3. 不同版本的nuitka对编译器要求不一样,考虑到编译器都比较大而且部署起来比较麻烦,所以如果没有特殊要求,建议还是固定一个版本,除非有重大更新再考虑更新nuitka

cython打包问题

为了解决HashChecker无法使用nuitka打包的问题,就采用cython+pyinstaller打包的方案,具体实现效果如下: 1. 写一个setup.py,内容如下:

Python
from distutils.core import setup
from Cython.Build import cythonize

def generate_cython_file():
    setup(
        name='HashChecker',
        ext_modules=cythonize(['config.py', 'logMonitor.py', 'main.py', 'task.py', './Widget/about_ui.py',
                               './Widget/main_ui.py',
                               './Widget/progress_ui.py',
                               './Widget/settings_ui.py',
                               './Widget/widget.py'], language_level=3),

    )
generate_cython_file()

然后在终端中输入:

Text Only
python setup.py build_ext --inplace

Note

cython打包有些怪,必须确保当前系统中安装VS C++(需要安装VS 2022/2019且需要安装C/C++组件),否则无法打包 还有入口文件和资源文件不要生成pyd,会很麻烦,还有因为其他的文件被打包成pyd,会导致pyinstaller找不到第三方模块,下面会提到

此时当前目录和build中都有一些pyd文件,这个时候同名的py文件就用不到了,因为我是在虚拟机打包的,多余的py文件就可以删掉了。

如果是第一次打包的话,也没有什么不一样的地方,直接pyinstaller file.py就行了,但需要进行多次打包,主要是会缺少第三方模块,这个时候需要根据pyinstaller的报错提示,手动引入第三方模块,这就需要修改spec文件了,修改的内容如下:

Text Only
# -*- mode: python ; coding: utf-8 -*-


block_cipher = None


a = Analysis(
    ['HashChecker.py'],
    pathex=[],
    binaries=[],
    datas=[],
    hiddenimports=['markdown','PyQt5.QtWinExtras','openpyxl','chardet','Widget.about_ui','Widget.main_ui','Widget.progress_ui','Widget.settings_ui','Widget.widget','logMonitor','task','config','main'],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    [],
    exclude_binaries=True,
    name='HashChecker',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    icon='source\\main.ico',
)
coll = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='HashChecker',
)

主要是hiddenimports这一项,需要将自己写的脚本以及第三方模块全部引入进去,之后再使用pyinstaller file.spec打包,就没有问题了,测试发现加载速度感觉快了一点,但是运行速度似乎没有明显的变化。

关于运行性能的对比

之前有人说nuitka打包后的程序速度媲美C++的,我也进行了一点测试,不完全准确,都使用for循环从1一直累加到10000000,然后采用不同的打包方式,每次运行后清空内存数据,对比结果如下(印象的数据,可能有误差):

打包方式 速度
nuitka 41秒
python源码 60秒
pyinstaller 61秒
cx_freeze 68秒

总结

打包工具 优点 缺点
pyinstaller 1. 兼容性较好
2. 打包方便
1. 打包体积大
2. 容易被反编译(对安全没有较高要求可以忽略)
nuitka 1. 打包体积较小
2. 有运行性能、内存占用的优化
1. 兼容性较差(只针对GUI开发)
2. 可能需要VC++环境
3. 打包比较麻烦,有一定的条件
cx_freeze 1. 兼容性较好
2. 打包方便
1. 打包体积大(可通过自行裁剪缩小体积)
2. 不太主流

因此,具体使用什么打包工具进行打包,需要根据实际需求来定,而不是盲目只使用其中一种打包方式

另外,cython更多的是作为一种编程语言来使用,利用cython生成pyd文件来加速只是它的次要作用,且经过测试对数据计算方面有比较大的明显,但对于I/O方面没有较大的优化