pyinstaller打包详解

PyInstaller是一个程序,它将Python程序冻结(包)为独立的可执行文件,在Windows,GNU/Linux,Mac OS X,FreeBSD,OpenBSD,Solaris和AIX下。与类似工具相比,它的主要优点是PyInstaller与Python 3.6-3.9配合使用,由于透明压缩,它构建了较小的可执行文件,它是完全多平台的,并使用操作系统支持来加载动态库,从而确保完全兼容。

可以传递一个或多个 Python 脚本的文件名,也可以传递一个 .spec 文件名。

在第一种情况下,将生成一个.spec文件(就像这样)并立即处理它。pyinstaller pyi-makespec

help文档参数

pyinstaller [-h] [-v] [-D] [-F] [--specpath DIR] [-n NAME]
                   [--add-data ]
                   [--add-binary ] [-p DIR]
                   [--hidden-import MODULENAME]
                   [--collect-submodules MODULENAME]
                   [--collect-data MODULENAME] [--collect-binaries MODULENAME]
                   [--collect-all MODULENAME] [--copy-metadata PACKAGENAME]
                   [--recursive-copy-metadata PACKAGENAME]
                   [--additional-hooks-dir HOOKSPATH]
                   [--runtime-hook RUNTIME_HOOKS] [--exclude-module EXCLUDES]
                   [--key KEY] [--splash IMAGE_FILE]
                   [-d {all,imports,bootloader,noarchive}]
                   [--python-option PYTHON_OPTION] [-s] [--noupx]
                   [--upx-exclude FILE] [-c] [-w]
                   [-i ]
                   [--disable-windowed-traceback] [--version-file FILE]
                   [-m ] [--no-embed-manifest] [-r RESOURCE]
                   [--uac-admin] [--uac-uiaccess] [--win-private-assemblies]
                   [--win-no-prefer-redirects]
                   [--osx-bundle-identifier BUNDLE_IDENTIFIER]
                   [--target-architecture ARCH] [--codesign-identity IDENTITY]
                   [--osx-entitlements-file FILENAME] [--runtime-tmpdir PATH]
                   [--bootloader-ignore-signals] [--distpath DIR]
                   [--workpath WORKPATH] [-y] [--upx-dir UPX_DIR] [-a]
                   [--clean] [--log-level LEVEL]
                   scriptname [scriptname ...]

可选参数

参数 解释
-h, --help 显示此帮助消息并退出
-v, --version 显示程序版本信息并退出。
–distpath DIR 将捆绑的应用放在何处(默认:./dist)
–workpath WORKPATH 放置所有临时工作文件的位置,.log、.pyz 等(默认:./build)
-y, --noconfirm 替换输出目录(默认:SPECPATH/dist/SPECNAME),而不要求确认
–upx-dir UPX_DIR UPX 实用程序的路径(默认:搜索执行路径)
-a, --ascii 不包括 Unicode 编码支持(默认:如果可用,则包括)
–clean 在构建之前清理 PyInstaller 缓存并删除临时文件。
–log-level LEVEL 构建时控制台消息中的详细信息量。级别可以是 TRACE、DEBUG、INFO、WARN、ERROR、CRITICAL(默认值:INFO)之一。
–uac-admin 添加管理员权限通过命令行的方式,例如pyinstaller -D -c --uac-admin main.py

生成结果参数

参数 解释
-D, --onedir 创建包含可执行文件的单文件夹捆绑包(默认)
-F, --onefile 创建单文件捆绑的可执行文件。
–specpath DIR 用于存储生成的 spec 文件的文件夹(默认:当前目录)
-n NAME, --name NAME 要分配给捆绑的应用程序和规范文件的名称(默认:第一个脚本的基本名称)

捆绑文件参数

参数 解释
–add-data 要添加到可执行文件的其他非二进制文件或文件夹。路径分隔符是特定于平台的,(在Windows和大多数unix系统上)被使用。此选项可以多次使用。分隔符可选=;:或者空格
–add-binary 要添加到可执行文件的其他二进制文件。有关更多详细信息,请参阅该选项。此选项可以多次使用。--add-data
-p DIR, --paths DIR 用于搜索导入的路径(如使用 PYTHONPATH)。允许使用多个路径、以 分隔或多次使用此选项。等效于在规范文件中提供参数。':'``pathex
–hidden-import MODULENAME, --hiddenimport MODULENAME 命名在脚本代码中不可见的导入。此选项可以多次使用。
–collect-submodules MODULENAME 从指定的包或模块中收集所有子模块。此选项可以多次使用。
–collect-data MODULENAME, --collect-datas MODULENAME 从指定的包或模块收集所有数据。此选项可以多次使用。
–collect-binaries MODULENAME 从指定的包或模块收集所有二进制文件。此选项可以多次使用。
–collect-all MODULENAME 从指定的包或模块中收集所有子模块、数据文件和二进制文件。此选项可以多次使用。
–copy-metadata PACKAGENAME 复制指定包的元数据。此选项可以多次使用。
–recursive-copy-metadata PACKAGENAME 复制指定包及其所有依赖项的元数据。此选项可以多次使用。
–additional-hooks-dir HOOKSPATH 用于搜索挂钩的其他路径。此选项可以多次使用。
–runtime-hook RUNTIME_HOOKS 自定义运行时挂钩文件的路径。运行时挂钩是与可执行文件捆绑在一起的代码,在任何其他代码或模块之前执行,以设置运行时环境的特殊功能。此选项可以多次使用。
–exclude-module EXCLUDES 将忽略的可选模块或包(Python 名称,而不是路径名)(好像找不到它)。此选项可以多次使用。
–key KEY 用于加密 Python 字节码的密钥。需要安装pycrypto可以用p代替ycryptodome代替
–splash IMAGE_FILE (实验性)将带有图像IMAGE_FILE的初始屏幕添加到应用程序中。初始屏幕可以在解压缩时显示进度更新。

Windows 和 Mac Os X 特定选项

参数 解释
-c, --console, --nowindowed 打开标准 I/O 的控制台窗口(默认)。在 Windows 上,如果第一个脚本是".pyw"文件,则此选项不起作用。
-w, --windowed, --noconsole Windows 和 Mac OS X:不为标准 I/O 提供控制台窗口。在 Mac OS 上,这也会触发构建 Mac OS .app捆绑包。在 Windows 上,如果第一个脚本是".pyw"文件,则会自动设置此选项。此选项在 *NIX 系统上被忽略。
-i
--icon
文件.ico:将图标应用于 Windows 可执行文件。文件.exe,ID:从exe中提取带有ID的图标。FILE.icns:将图标应用于 Mac OS 上的.app捆绑包。使用"NONE"不应用任何图标,从而使操作系统显示一些默认值(默认:应用 PyInstaller 的图标)
–disable-windowed-traceback 在窗口(无控制台)模式下禁用未处理异常的回溯转储(仅限 Windows 和 macOS),而是显示一条消息,指出此功能已禁用。

特定于窗口的选项

参数 解释
–version-file FILE 将版本资源从 FILE 添加到 exe。
-m
–manifest
将清单文件或 XML 添加到 exe。
–no-embed-manifest 生成外部.exe.manifest 文件,而不是将清单嵌入到 exe 中。仅适用于一进制模式;在单文件模式下,无论此选项如何,清单始终是嵌入的。
-r RESOURCE, --resource RESOURCE 将资源添加或更新到 Windows 可执行文件。资源是一到四个项目,FILE[,TYPE[,NAME[,LANGUAGE]]]。文件可以是数据文件或 exe/dll。对于数据文件,至少必须指定 TYPE 和 NAME。LANGUAGE 默认为 0 或指定为通配符 * 以更新给定 TYPE 和 NAME 的所有资源。对于 exe/dll 文件,如果省略了 TYPE、NAME 和 LANGUAGE 或指定为通配符 *,则 FILE 中的所有资源都将添加/更新到最终的可执行文件中。此选项可以多次使用。
–uac-admin 使用此选项将创建一个清单,该清单将在应用程序启动时请求提升。
–uac-uiaccess 使用此选项允许提升的应用程序使用远程桌面。

打包命令

  • 执行打包命令生成单独的 .exe 程序
pyinstaller -F main.py
  • 执行pyinstaller 提供的调试打包命令,查看打包错误日志,通过日志排查问题原因

    -D 参数表示打调试包,将展示生成的各种依赖文件,等待打包结束,查看 build/main/warn-main.txt 日志警告文件

    pyinstaller -D main.py
    
  • 添加用户依赖包

    分析日志发现缺失模块,现在通过命令行,把用户第三方依赖模块搜索路径添(请使用自己电脑定义的安装目录)加进打包命令,

    下面提供示例,site-packages可以不用添加的,即如果你没有使用pip -target 安装第三方模块到自己指定的目录,这一步可以省略。有些IDE工具会创建自己的安装包路径,所以请添加IDE的安装包的路径

    pyinstaller -D -p D:\\Python\\Python38\\Lib\\site-packages main.py
    
  • 命令行打包多文件

pyinstaller [主文件] -p [其他文件1] -p [其他文件2] 
--hidden-import [自建模块1] 
--hidden-import [自建模块2]
# 以上为一整条命令

例如:pyinstaller -F start_menu.py -p check_default_speedup.py -p check_server_os.py -p check_speedup.py

通过upx减少体积

通过upx可显著见小程序体积。

需要下载upx.exe

  • github下载

打包时加上以下参数:

--upx-dir UPX_DIR

UPX_DIR指向upx的下载目录不用具体到文件,一般建议直接和python解释器放在一起就好。pyinstaller会自动选择进行压缩(可写一个错误路径查看两次打的包大小)

使用spec方式

创建spec文件

打开终端进入项目路径下,输入指令: pyinstaller -makespec xxx.py,或者其他命令回车,程序结束后

当前目录(默认)下生成两个文件夹(bulid、dist)和一个文件start_menu.spec,现在删除两个文件夹,只保留start_menu.spec文件。

py文件打包配置

  • 针对多目录多文件的python项目,打包时候需要将所有相关的py文件输入到Analysis类里。
  • Analysis类中的pathex定义了打包的主目录,对于在此目录下的py文件可以只写文件名不写路径。
  • spec脚本,将所有项目中的py文件路径以列表形式写入Analysis

资源文件打包配置

  • 资源文件包括打包的python项目使用的相关文件,如图标文件,文本文件等。对于此类资源文件的打包需要设置Analysis的datas,

  • `datas接收元组:

    • datas写入必须是一对2元素元组,每一个元组代表一个文件。

    • 元素第一个是要打包文件的路径(可用相对路径),第二个是要打包进exe后的路径(只能用相对路径以为./开头,根目录下的话可省略./)

      datas=[('logo/icon.ico','./logo'),('image/xxx.png', 'image')]
      

Hidden import配置

  • pyinstaller在进行打包时,会解析打包的python文件,自动寻找py源文件的依赖模块。但是pyinstaller解析模块时可能会遗漏某些模块(not visible to the analysis phase),造成打包后执行程序时出现类似No Module named xxx。这时我们就需要在Analysis下hiddenimports中加入遗漏的模块

递归深度设置

  • 在打包导入某些模块时,常会出现"RecursionError: maximum recursion depth exceeded"的错误,这可能是打包时出现了大量的递归超出了python预设的递归深度。因此需要在spec文件上添加递归深度的设置,设置一个足够大的值来保证打包的进行,

    import sys
    sys.setrecursionlimit(5000)
    
  • 去除不必要的模块import

    有时需要让pyinstaller不打包某些用不到的模块,可通过在excludes=[]中添加此模块实现,如

    excludes=['zmq']
    

根据自己的项目编辑文件

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

block_cipher = None


a = Analysis(['start_menu.py','check_default_speedup.py', 'check_server_os.py', 'check_speedup.py'],#此项目中所有的python脚本
             pathex=[ 'D:\\Project\\python\\xxxTool'], # 项目绝对路径,此处很重要。
             binaries=[],
             datas=[],#此列表存放所有的资源文件,每个文件是一个二元组元素,例如[('image/xxx.png', '.')]  把image/xxx.png下打包到根目录下(一般建议前后目录一致,这里用.只是演示),可以用同样方法添加多个图片元素等。
			 
			 #add_files = [ ('fonts\\font.ttf', 'fonts'), 
							#('images\\*.png', 'images'), 
							#('images\\flappy.ico', 'images'), 
							#('audios\\*.wav', 'audios'),]

             hiddenimports=[],	# 同命令行--hidden-import [自建模块1]参数可多次添加,身份证项目中就在此处添加了两个工具模块py文件
             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='start_menu', #打包程序的名字
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True, # 此处console=True表示,打包后cmd窗口运行,不影响原程序运行
          icon='xxxxx.ico', # 修改图标,可不带此参数同命令行-i xxx.ico
          uac_admin=True     # 以管理员方式运行
          

将文件添加到捆绑包

默认情况下,pyinstaller只打包 *.py 文件,对于其它文件,如图片、文本文件等,需要添加额外的参数手动指定加入打包行列,或者更改特定的 spec 文件。

要将文件添加到捆绑包,请创建一个描述文件的列表,并将其提供给调用。

  • 捆绑到单个文件夹时ru,添加的数据文件将与可执行文件一起复制到该文件夹中。
  • 捆绑到单个可执行文件时,添加文件的副本将压缩到可执行文件中,并在执行之前展开到临时文件夹。
  • 当应用程序结束时,单文件可执行文件对添加的文件所做的任何更改都将丢失。

添加数据文件

使用 --add-data 命令选项或将它们作为列表添加到 spec 文件中,从而将数据文件添加到捆绑包中。

使用 spec 文件时,请提供一个列表,将文件描述为 参数的值。数据文件列表是元组列表。每个元组都有两个值,这两个值都必须是字符串:datas=Analysis

  • 第一个字符串指定当前在此系统中的一个或多个文件。
  • 第二个指定在运行时要包含文件的文件夹的名称。

用法的注意事项有几个:

写–add-data有时候加上引号会报错,这是因为在win环境和linux下不一样具体使用哪个请尝试吧。

  • --add-data后面可以加=,也可以直接空格,效果一样。
  • --add-data后面的参数值里,有两部分,用 ;隔开(windows用分号号,部分其他系统用:隔开),前面是指打包前文件所在的位置,后面是指打包后你希望文件所在的位置
  • --add-data image1.png;img 的意思是把当前目录里一个叫 “image1.png” 的文件打包进去,但是放在打包后的 img 目录下,也就是变成 img/image1.png,文件名不变。
  • --add-data可以用多次,可以一个文件一个文件地加,也可以整个文件夹一起加
  • --add-data 'images;images' 也就是把当前目录下 images 文件夹里的文件都打包进去,打包后的目录也是 images 一样的文件夹下。

单个自述文件添加

例如,要将单个自述文件添加到单文件夹应用程序的顶层,可以按如下方式修改规范文件:

pyinstaller -F --add-data 'use_ico.png;./' format_conversion.py

说明中–add-data后的文件和保存目录说是可以用分好和冒号但是实际使用冒号发现报错

命令行:
pyinstaller --add-data 'src/README.txt;.' myscript.py


spec 文件:
a = Analysis(...
     datas=[ ('src/README.txt', '.') ],
     ...
     )

包含某个文件夹中的所有文件

字符串可以使用或作为路径分隔符。可以使用"glob"缩写指定输入文件。例如,要包含某个文件夹中的所有文件:/mygame/ data

文件夹中的所有mp3文件都将复制到捆绑应用程序中。/mygame/sfx/*.mp3 sfx

added_files = [
         ( '/mygame/data', 'data' ),
         ( '/mygame/sfx/*.mp3', 'sfx' )
         ]

演示

  • 指定让 图片文件 也可以打包进去,当前目录下,有两个图片文件:

    images/alien.bmp
    images/ship.bmp
    
    
  • pyinstaller的官方提供了两种方式用来加入额外的文件:

添加二进制文件

二进制文件是指 DLL、动态库、共享对象文件等,PyInstaller 将搜索进一步的二进制依赖项。图像和 PDF 等文件应进入 .datas

使用 --add-binary 命令选项或将它们作为列表添加到 spec 文件中,从而将二进制文件添加到捆绑包中。

在 spec 文件中,创建描述所需文件的元组列表。将元组列表分配给 Analysis 的参数。binaries=

添加二进制文件的工作方式与添加数据文件类似。如添加二进制文件中所述,每个元组应具有两个值:

  • 第一个字符串指定当前在此系统中的一个或多个文件。
  • 第二个指定在运行时要包含文件的文件夹的名称。

PyInstaller通过分析导入的模块来了解和库。有时不清楚是否导入了模块;在这种情况下,请使用 --hidden-import 命令选项。但即便如此,也可能无法找到所有依赖项

用法同添加文件

打包单文件,提示找不到解决办法

使用单文件打包出来的exe会先解压再运行,所以打包出来的exe在运行时,它的工作路径和它解压到的路径

程序一般首先都是在工作路径查找你所指定的文件的。直接这样执行已打包的外部文件时,程序会报找不到文件

import os
import sys


def base_path(path):
    if getattr(sys, 'frozen', None):
        basedir = sys._MEIPASS
    else:
        basedir = os.path.dirname(__file__)
    return os.path.join(basedir, path)


tmd = base_path('')  # 这是解压路径
cwd = os.getcwd()  # 这是程序的所在路径

# 当需要调用打包的外部文件时
os.chdir(tmd)  # 先把工作路径变成解压路径
# ######do()  # 执行你要干的事情

# 当需要写出文件到程序所在目录时
os.chdir(cwd)  # 把工作路径切换回来
# #####do()  # 执行你要干的事情

或者,在程序中所有引用图片的路径,使用此函数处理

import sys
from os.path import join, abspath


def get_resource_path(relative_path):
    """
    根据传入相对路径获取资源路径
    在需要用到非py文件时用get_resource_path(path)替换原本直接使用相对路径方式即可
    此方法适用于,在进行pyinstaller打包加了-F参数情况,否则建议不使用此方法获得更小的包
    """
    if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
        return join(sys._MEIPASS, relative_path)
    return join(abspath(""), relative_path)

目录和树类

PyInstaller 使用(目录)类管理文件列表。它提供了该类作为从文件夹路径生成 的便捷方法。

目录类(目录)

类的对象用作在 spec 文件中创建的类的输入。例如,分析对象的成员是包含脚本列表的目录。成员是具有模块列表的目录,依此类推。

基本上,对象包含表单的元组列表TOC

目录的行为类似于列表,并支持相同的方法,如追加、索引等。目录的行为也像一个集合,并支持采用差异和交叉点。在所有这些操作中,元组列表可以用作一个参数。

以下表达式是将文件添加到成员的等效方法:a.datas

a.datas.append( [ ('README', 'src/README.txt', 'DATA' ) ] )
a.datas += [ ('README', 'src/README.txt', 'DATA' ) ]

树类

Tree 类是一种创建目录的方法,该目录描述目录中的部分或全部文件:

Tree(根运行时文件夹string_list代码|, prefix=, excludes=, typecode='DATA' )

  • 参数是目录的路径字符串。它可以是绝对的,也可以是相对于 spec 文件目录的。
  • 前缀参数(如果给定)是运行时文件夹中用于包含树文件的子文件夹的名称。如果省略前缀或 give ,则树文件将位于运行时文件夹的顶层。None
  • excludes 参数(如果给定)是一个或多个字符串的列表,这些字符串与目录中的文件匹配,应从树中省略这些文件。列表中的项目可以是:
    • 一个名称,这会导致排除具有此基名的文件或文件夹
    • *.ext,这会导致排除具有此扩展名的文件
  • 类型代码参数(如果给定)指定应用于树中所有项的 TOC 类型代码字符串。如果省略,则默认值为 ,这适用于大多数情况。DATA
extras_toc = Tree('../src/extras', prefix='extras', excludes=['tmp','*.pyc'])

将创建一个 TOC 对象,该对象列出相对路径中的所有文件,省略具有基名(或位于名为 的文件夹中)或具有 类型的文件。此目录中的每个元组都有:extras_toc``../src/extras``tmp``.pyc

  • 由 组成的名称extras/*filename*
  • 由文件夹中该文件的完整绝对路径组成的路径(相对于 spec 文件的位置)。../src/extras
  • 的类型代码(默认情况下)。DATA

一些二进制模块的目录的示例:

cython_mods = Tree( '..src/cy_mods', excludes=['*.pyx','*.py','*.pyc'], typecode='EXTENSION' )

建立虚拟环境打包

# 在需要打包文件目录下新建一个test_env文件夹并cmd进入,用于创建虚拟环境
cd test_dir
python -m venv env_dir

# 成功创建虚拟环境,cmd进入test_env
cd env_dir\Scripts

# 激活虚拟环境
./env_dir/Scripts/activate

# 安装需要的包,pyinstaller必须安装
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pyinstaller

# 切换到需要打包目录,进行打包
pyinstaller -F -w -i dog.ico CrazyClick.py

# 打包完成直接关闭或者exit退出该环境
exit

你可能感兴趣的:(python,开发语言)