Pyinstaller详细教程

知乎排版有问题,建议直接打开我的博客原文:

Pyinstaller详细教程me.aimao.co

最近在用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–显示程序版本信息并退出--distpathDIR在哪里放置捆绑的应用程序(默认:./dist)--workpathWORKPATH在哪里放置所有的临时工作文件,.log,.pyz等(默认:./build)-y, --noconfirm–替换输出目录而不要求确认--upx-dirUPX_DIRUPX程序(压缩)的路径(默认:搜索执行路径)-a, --ascii–不包括unicode编码支持(默认:包括如果可用)--clean–清理pyinstaller缓存并在构建之前删除临时文件--log-levelLEVEL构建时控制台消息中的信息级别。(默认:INFO)

生成什么

选项格式说明-D, --onedir–创建一个包含可执行文件的单个文件夹包(默认)-F, --onefile–创建一个文件捆绑的单一的可执行文件--specpathDIR存储生成的spec文件的文件夹(默认:当前目录)-n, --nameNAME要分配给捆绑应用程序和规格文件的名称(默认:第一个脚本的名称)

捆绑什么,在哪里搜索

选项格式说明--add-data<SRC;DEST or SRC:DEST>可执行文件添加其他非二进制文件或文件夹。路径分隔符是特定于平台的,os.pathsep(在Windows用;大多数unix系统上用:)。该选项可以多次使用。--add-binary<SRC;DEST or SRC:DEST>可执行文件添加额外的二进制文件。类同–add-data选项。该选项可以多次使用。-p, --pathsDIR搜索导入的路径(如使用PYTHONPATH)。允许多个路径,用”;”(win)或”:”(unix)分隔,或多次使用此选项--hidden-import, --hiddenimportMODULENAME在脚本的代码中命名不可见的导入。该选项可以多次使用。--additional-hooks-dirHOOKSPATH用来搜索钩子的额外路径。该选项可以多次使用。--runtime-hookRUNTIME_HOOKS自定义运行时钩子文件的路径。运行时钩子是与可执行文件捆绑在一起的代码,并在任何其他代码或模块之前执行,以设置运行时环境的特殊功能。该选项可以多次使用。--exclude-moduleEXCLUDES忽略可选的模块或包(Python名称,而不是路径名)。该选项可以多次使用。--keyKEY用于加密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-fileFILE导入版本信息文件,用于设置exe文件的版本信息-m, --manifest将清单FILE或XML添加到exe-r, --resourceRESOURCE将资源添加或更新到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-dirDIR指定upx工具的目录–distpathDIR指定生成的–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 test2pyinstaller是找不到test2的,你只能--paths中再添加一条路径到core\model,让pyinstaller看得到test2.py.

使用from...import同理,需要在path中添加工程目录或工程子目录,让pyinstaller能找得到相关文件。

相关资料

更多建议:查看Github官方说明页面

    原文作者:王熊貓
    原文地址: https://zhuanlan.zhihu.com/p/40716095
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞