知乎排版有问题,建议直接打开我的博客原文:
最近在用pyinstaller打包基于pyqt5和opencv的GUI程序。基本上总结了使用pyinstaller的常用操作。
环境:
- win10_x64
- python3.6
- Pyinstaller 3.3.1
安装
一般来说,安装直接
pip install pyinstaller
即可,但是若是某些程序打包出现问题则建议安装开发版
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip
命令选项说明
安装完成之后可以通过如下命令查看帮助
pyinstaller --help
可选参数
选项格式说明-h, --help
–显示此帮助信息并退出-v, --version
–显示程序版本信息并退出--distpath
DIR在哪里放置捆绑的应用程序(默认:./dist)--workpath
WORKPATH在哪里放置所有的临时工作文件,.log,.pyz等(默认:./build)-y, --noconfirm
–替换输出目录而不要求确认--upx-dir
UPX_DIRUPX程序(压缩)的路径(默认:搜索执行路径)-a, --ascii
–不包括unicode编码支持(默认:包括如果可用)--clean
–清理pyinstaller缓存并在构建之前删除临时文件--log-level
LEVEL构建时控制台消息中的信息级别。(默认:INFO)
生成什么
选项格式说明-D, --onedir
–创建一个包含可执行文件的单个文件夹包(默认)-F, --onefile
–创建一个文件捆绑的单一的可执行文件--specpath
DIR存储生成的spec文件的文件夹(默认:当前目录)-n, --name
NAME要分配给捆绑应用程序和规格文件的名称(默认:第一个脚本的名称)
捆绑什么,在哪里搜索
选项格式说明--add-data
<SRC;DEST or SRC:DEST>可执行文件添加其他非二进制文件或文件夹。路径分隔符是特定于平台的,os.pathsep
(在Windows用;
大多数unix系统上用:
)。该选项可以多次使用。--add-binary
<SRC;DEST or SRC:DEST>可执行文件添加额外的二进制文件。类同–add-data选项。该选项可以多次使用。-p, --paths
DIR搜索导入的路径(如使用PYTHONPATH)。允许多个路径,用”;”(win)或”:”(unix)分隔,或多次使用此选项--hidden-import, --hiddenimport
MODULENAME在脚本的代码中命名不可见的导入。该选项可以多次使用。--additional-hooks-dir
HOOKSPATH用来搜索钩子的额外路径。该选项可以多次使用。--runtime-hook
RUNTIME_HOOKS自定义运行时钩子文件的路径。运行时钩子是与可执行文件捆绑在一起的代码,并在任何其他代码或模块之前执行,以设置运行时环境的特殊功能。该选项可以多次使用。--exclude-module
EXCLUDES忽略可选的模块或包(Python名称,而不是路径名)。该选项可以多次使用。--key
KEY用于加密Python字节码的密钥(需要相关加密包支持)
如何生成
选项格式说明-d, --debug
–告诉引导程序在初始化和启动捆绑应用程序时发出进度消息。用于诊断导包丢失的问题。-s, --strip
–将符号表格条应用于可执行文件和共享库(不推荐用于Windows)--noupx
–即使可用,也不要使用UPX(在Windows和Unix之间工作方式不同)
Windows和Mac OS特定的选项
选项格式说明-c, --console, --nowindowed
–打开标准I/O的控制台窗口(默认)-w, --windowed, --noconsole
–Windows和Mac OS:不提供标准I/O的控制台窗口。在Mac OS上,这也触发了构建OS .app包。UNIX系统中忽略此选项。-i, --icon
<FILE.ico or FILE.exe,ID or FILE.icns>将该图标应用于Windows可执行文件。FILE.exe,ID,从exe中提取带有ID的图标。FILE.icns:将图标应用于Mac OS上的.app包
Windows特定的选项
选项格式说明--version-file
FILE导入版本信息文件,用于设置exe文件的版本信息-m, --manifest
将清单FILE或XML添加到exe-r, --resource
RESOURCE将资源添加或更新到Windows可执行文件。RESOURCE是一到四个项目,FILE [,TYPE [,NAME [,LANGUAGE]]]。文件可以是数据文件或exe / dll。对于数据文件,至少必须指定TYPE和NAME。LANGUAGE默认为0,或者可以指定为通配符来更新给定TYPE和NAME的所有资源。对于exe / dll文件,如果TYPE,NAME和LANGUAGE被省略或者指定为通配符,那么来自FILE的所有资源将被添加/更新为最终的可执行文件。该选项可以多次使用。--uac-admin
–使用此选项将创建一个清单,在应用程序重新启动时请求系统权限提升。--uac-uiaccess
–使用此选项允许权限提升的应用程序在远程桌面中使用。
还有一些高级参数一般用不到,就不贴了。
命令选项建议使用完整的长命令,比较好记忆且易于阅读。
使用Pyinstaller
- 打包成一个文件夹
pyinstaller <options> test.py
- 打包成一个单一的可执行文件
pyinstaller --onefile <options> test.py
默认情况下打包会在当前目录下生成dist和build文件夹以及.spec文件。dist中即打包出来的可执行文件目录,build文件夹下为构建过程临时文件目录,.spec为打包的配置文件。
打包成文件夹和单一可执行文件的优缺点
- 启动时间
单一可执行文件比文件夹的启动时间要长
因为当程序运行时,单一的可执行文件需要解压程序的第三方依赖文件到临时文件夹中。 - 文件结构
单一可执行文件的文件结构和工程目录是一样的,但是生成文件夹就不一样了,若程序中包含相对路径,这个相对路径自然基于的是文件夹目录,这点需要注意。
spec文件
.spec文件类似于cmake的.makefile文件,都是用于控制编译构建过程的配置文件。
正常使用中我们是不需要管spec文件的,但是下面几种情况需要修改spec文件:
- 需要打包资源文件
- 需要include一些PyInstaller不知道的run-time库
- 为可执行文件添加run-time选项
- 多程序打包
可以通过下面命令单独生成spec文件
pyi-makespec <options> script.py
打包的时候默认生成在当前目录下,也可以指定生成目录
pyinstaller --specpath=$ProjectFileDir$\build <options> test.py
$ProjectFileDir$
是PyCharm中工程根目录的路径宏。各种命令一般在IDE的扩展工具中为工程单独定制好,后面的举例类同。
后面可以直接通过.spec文件来打包
pyinstaller <options> test.spec
当通过spec文件来生成app文件的时候只有下面几个参数是有用的:
选项格式说明–upx-dir
DIR指定upx工具的目录–distpath
DIR指定生成的–noconfirm
–替换输出目录而不要求确认–ascii
–不包括unicode编码支持
spec文件解析
下面是一个spec文件的例子。
# -*- mode: python -*-block_cipher = Nonea = Analysis(['..\\core\\main.py'], pathex=['D:\\ProgramSourceCode\\PycharmProjects\\video_proc\\venv\\Lib\\site-packages\\PyQt5\\Qt\\bin'], binaries=[('D:\\ProgramSourceCode\\PycharmProjects\\video_proc\\venv\\Lib\\site-packages\\cv2\\opencv_ffmpeg341_64.dll', './cv2')], datas=[], hiddenimports=[], hookspath=[], 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, a.binaries, a.zipfiles, a.datas, [], name='main', debug=False, strip=False, upx=True, runtime_tmpdir=None, console=False , version='D:\\ProgramSourceCode\\PycharmProjects\\video_proc\\res\\file_version_info.txt', icon='D:\\ProgramSourceCode\\PycharmProjects\\video_proc\\res\\main.ico')
spec文件中主要包含4个class: Analysis, PYZ, EXE和COLLECT
- Analysis以py文件为输入,它会分析py文件的依赖模块,并生成相应的信息
- PYZ是一个.pyz的压缩包,包含程序运行需要的所有依赖
- EXE根据上面两项生成
- COLLECT生成其他部分的输出文件夹,COLLECT是可选的
上面说了有时候我们需要另外添加资源文件,可以通过编辑spec文件,也可以通过命令行参数。
例如使用opencv的时候存在找不到视频编解码器的情况
即找不到opencv_ffmpeg341_64.dll
这时候需要我们手动设置资源路径,
可以通过--add-binary
参数设置,也可以在spec文件添加binaries参数,这个参数是个list,每个元素是个二元组
binaries=[('D:\\ProgramSourceCode\\PycharmProjects\\video_proc\\venv\\Lib\\site-packages\\cv2\\opencv_ffmpeg341_64.dll', './cv2')]
前一个代表原始资源路径,后一个代表拷贝到可执行文件夹的文件路径。
参考命令
以下是我使用PyCharm开发某工程的扩展工具的参考命令,一般有俩个命令,一个debug版本,debug版需要去掉--onefile
,--windowed
选项
pyinstaller --noconfirm --clean --windowed
--specpath=$ProjectFileDir$\build
--workpath=$ProjectFileDir$\build
--distpath=$ProjectFileDir$\bin
--icon=$ProjectFileDir$\res\$FileNameWithoutExtension$.ico
--version-file=$ProjectFileDir$\res\file_version_info.txt
--add-binary=$ProjectFileDir$\venv\Lib\site-packages\cv2\opencv_ffmpeg341_64.dll;./cv2
--paths=$ProjectFileDir$\venv\Lib\site-packages\PyQt5\Qt\bin;$ProjectFileDir$\res;$ProjectFileDir$;$ProjectFileDir$\core;$ProjectFileDir$\core\view;$ProjectFileDir$\core\model;$ProjectFileDir$\core\control;$ProjectFileDir$\core\conf $FileName$
解释一下,覆盖安装,清除临时文件,不显示控制台,指定spec和build路径为同一目录,指定dist路径,指定ico图标,指定应用程序版本信息文件,添加二进制文件,添加搜索路径,最后一个$FileName$
为程序入口文件。
打包常见问题
生成单执行文件成功,生成文件夹不能执行
就是前面说的,可能是文件结构不同,导致的相对路径出现的问题。
成功打包但是一运行就报错
- 说明缺少必要的资源文件,例如刚才举例的
opencv_ffmpeg341_64.dll
,检查是否有些必要的资源文件没有打包进去(使用debug模式,并且显示控制台)。 - 导包方式有错误,使得找不到自己写的module/file,为什么导包方式有错误这点下面会接着讲。
找不到module/file
首先查看哪些module路径没找到
使用debug模式,并且开启控制台显示
或者在打包默认生成的build\目录下查看warn-main.txt
文件,文件记录了PyInstaller无法找到的module列表。一般来说很容易出现missing module,不过这些module一般是第三方包并不影响程序运行,所以也不需要处理,除非这个module是你自己写的,则说明没能成功导入(没找到)。
程序运行的时候from...import
或者import
运行都很正常,为什么pyinstaller就是找不到呢?
因为pyinstaller都是在spec文件中pathex参数指定的路径中去搜索的,也就是说假设你有2个文件分别为core\model\test1.py
,core\model\test2.py
,你--paths
中只指定到了core,你test1.py
文件中使用import test2
pyinstaller是找不到test2的,你只能--paths
中再添加一条路径到core\model
,让pyinstaller看得到test2.py.
使用from...import
同理,需要在path中添加工程目录或工程子目录,让pyinstaller能找得到相关文件。
相关资料
更多建议:查看Github官方说明页面