PyInstaller 中文文档

PyInstaller 中文文档

"""
@author: Tingzhang H
@contact: [email protected]
@desc: Pyinstaller文档中文版
"""

版权归原作者所有 译作权归本人所有

版本 5.11.0+g7bc

目录

  • 1 快速入门
  • 2 目录:
    • 2.1 要求
    • 2.2 许可证
    • 2.3 如何贡献
    • 2.4 如何安装 PyInstaller
    • 2.5 PyInstaller 功能及使用方法
    • 2.6 使用 PyInstaller
    • 2.7 运行时信息
    • 2.8 使用 Spec 文件
    • 2.9 特性相关注意事项
    • 2.10 当出现问题时
    • 2.11 高级主题
    • 2.12 理解 PyInstaller 钩子
    • 2.13 钩子配置选项
    • 2.14 构建引导
    • 2.15 PyInstaller 更新日志
    • 2.16 鸣谢
    • 2.17 手册
    • 2.18 开发指南
    • 2.19 索引和表格
  • Python 模块索引
  • 索引

ii

版本 PyInstaller 5.11.0+g7bc
主页 https://pyinstaller.org/
联系邮箱 [email protected]
作者 David Cortesi,基于 Giovanni Bajo 和 William Caban 的结构,基于 Gordon McMil-
lan 的手册
版权 所有权已放弃。

PyInstaller 将 Python 应用程序及其所有依赖项打包成单个程序包。用户可以在没有安装 Python 解释器或任何模块的情况下运行打包的应用程序。PyInstaller 支持 Python 3.7 及更高版本,并正确地打包了许多重要的 Python 包,如 numpy、matplotlib、PyQt、wxPython 等。

PyInstaller 经过了 Windows、MacOS X 和 Linux 的测试。但它不是交叉编译器;要制作 Windows 应用程序,您需要在 Windows 上运行 PyInstaller,要制作 Linux 应用程序,需要在 Linux 上运行它,等等。PyInstaller 已成功地与 AIX、Solaris、FreeBSD 和 OpenBSD 一起使用,但测试并不是我们持续集成测试的一部分,开发团队不保证 PyInstaller 可以在这些平台上工作,或者它们将继续受到支持。

快速入门

确保已安装 “要求”,然后从 PyPI 安装 PyInstaller:

pip install -U pyinstaller

打开命令提示符/ shell 窗口,并导航到包含 .py 文件的目录,然后使用以下命令构建您的应用程序:

pyinstaller your_program.py

您打包的应用程序现在应该在 dist 文件夹中可用。

2.1 要求

2.1.1 Windows

PyInstaller 在 Windows 8 和更新版本上运行。它可以创建图形窗口应用程序 (不需要命令窗口)。

2.1.2 macOS

PyInstaller 在 macOS 10.15 (Catalina) 或更新版本上运行。它可以构建图形窗口应用程序 (不使用终端窗口)。PyInstaller 构建的应用程序与您运行它的 macOS 版本兼容,并且与后续版本兼容。它可以在 macOS 机器上构建 x86_64、arm64 或混合 universal2 二进制文件。有关详细信息,请参见“macOS 多架构支持”。

2.1.3 GNU/Linux

PyInstaller 需要 ldd 终端应用程序来发现每个程序或共享库所需的共享库。它通常在分发包 glibc 或 libc-bin 中找到。

它还需要 objdump 终端应用程序从对象文件中提取信息,以及 objcopy 终端应用程序将数据附加到 bootloader。这些通常在分发包 binutils 中找到。

2.1.4 AIX、Solaris、FreeBSD 和 OpenBSD

用户报告在这些平台上运行 PyInstaller 取得了成功,但未经过测试。需要 ldd 和 objdump 命令。

每个打包的应用程序包含一个引导程序,它设置应用程序并启动它 (请参见 “详细说明引导程序过程” )。

当您使用 pip 安装 PyInstaller 时,安装程序会尝试为该平台构建 bootloader。如果成功,则安装将继续,并准备使用 PyInstaller。

如果 pip 设置未能构建引导程序,或者您未使用 pip 进行安装,则必须手动编译引导程序。该过程在 “构建引导” 下进行了说明。

2.2 许可证

PyInstaller 采用双重许可方案,使用 GPL 2.0 许可证,并附加了一个例外,允许您使用它来构建商业产品 - 列在下面 - 和 Apache 许可证 2.0 版,仅适用于某些文件。要查看 Apache 许可证适用的文件以及 GPL 适用的文件,请参见 PyInstaller 源代码库中的“COPYING.txt”文件。

GPL 许可证例外的快速摘要:

  • 您可以使用 PyInstaller 通过源代码打包商业应用程序。
  • PyInstaller 从源代码生成的可执行包可以随附任何许可证,只要它符合您的依赖项的许可协议。
  • 您可以根据自己的需要修改 PyInstaller,但对 PyInstaller 源代码的更改受到 GPL 许可证的条款。也就是说,如果您分发您的修改,您必须按照 GPL 条款分发它们。

2.3 如何贡献

欢迎您的贡献! PyInstaller 是由一群志愿者维护的。所有贡献,如社区支持、错误报告、错误修复、文档改进、增强和想法都是受欢迎的。

PyInstaller 是一项由志愿者创建和维护的自由软件项目。它的生存和发展基于来自社区的支持,而您甚至考虑为 PyInstaller 贡献是非常慷慨的。

由于现在所有的核心开发人员都在业余时间里工作在 PyInstaller 上,您可以帮助我们(和项目)最好的方式是遵循一些简单的指南。贡献质量越高,我们合并它们的工作量就会越少,而我们合并它们的时间就会越早

如果您在任何时候遇到困难,可以在 GitHub 上创建一个支持工单。

关于我们的开发流程和方法的更多信息,请参见“开发指南”。

2.3.1 一些你可以提供帮助的想法

这里有一些你可以提供帮助的想法:

  • 回答支援票务: 通常用户只是需要指出手册中适合的部分。
  • 分类开放性问题,这意味着:阅读报告;要求问题请求者提供缺失信息并尝试使用最新开发版本;确保有一个最小的例子;确保问题报告人遵循了当事情出了问题时的所有步骤。如果你能够复现问题并追踪到错误,这将对核心开发人员非常有帮助。
  • 帮助改进文档: 这里有一份你可以从中选择的文档问题列表,请提供关于你更改的拉取请求。更多阅读»»
  • 选择需要拉取请求的问题,并提供拉取请求。
  • 审查拉取请求: 是否遵循指南“请编写好的提交信息”;所有新文件是否有版权标头(特别是钩子常常缺失);代码是否可以使用;等等。
  • 扫描开放性问题的列表并从中选择一些任务

6 第二章目录:

非常感谢!

如果您计划经常贡献,请申请对主Git仓库的写访问权限。我们很高兴能够欢迎您加入我们的团队!

2.4 如何安装 PyInstaller

PyInstaller作为常规Python包提供。发布版本的源代码存档可在PyPI上找到,但是使用pip安装最新版本更简单:

pip install pyinstaller

要升级现有的PyInstaller安装到最新版本,请使用:

pip install --upgrade pyinstaller

要安装当前的开发版本,请使用:

pip install https://github.com/pyinstaller/pyinstaller/tarball/develop

要直接使用pip的内置GIT检出支持进行安装,请使用:

pip install git+https://github.com/pyinstaller/pyinstaller

或者安装特定分支(例如develop):

pip install git+https://github.com/pyinstaller/pyinstaller@develop

2.4.1 从源存档安装

发布版本的PyInstaller的源代码存档可在PyPI和PyInstaller下载页面上找到。

**注意:**即使源存档提供了setup.py脚本,安装方式通过python setup.py install已经被弃用了,不再使用。相反,请从解压缩的源目录中运行pip install。如下所述。

安装程序是:

  1. 解压源存档。
  2. 移动到解压缩的源目录中。
  3. 从解压缩的源目录运行pip install。如果要安装到系统范围的Python安装中,则需要管理员权限。

相同的过程适用于从手动GIT检出安装:

git clone https://github.com/pyinstaller/pyinstaller
cd pyinstaller
pip install .

如果您打算对源代码进行更改并希望立即生效,而无需每次都重新安装包,则可以以可编辑模式安装它:

2.4. 如何安装 PyInstaller 7

pip install -e

对于Windows、GNU/Linux和macOS之外的平台,必须首先为您的平台构建引导程序:请参见“构建引导程序”。构建引导程序后,使用pip install .命令完成安装。

2.4.2 验证安装

在所有平台上,命令pyinstaller现在应该存在于执行路径上。要验证这一点,请输入以下命令:

pyinstaller --version

结果应类似于已发布版本的4.n,并且应开发分支的4.n.dev0-xxxxxx。

如果找不到该命令,请确保执行路径包括正确的目录:

  • Windows:C:\ PythonXY \ Scripts,其中XY代表主要和次要的Python版本号,例如C:\ Python38 \ Scripts适用于Python 3.8)
  • GNU / Linux:/ usr / bin /
  • macOS(使用默认的Apple提供的Python)/ usr / bin
  • macOS(使用homebrew安装的Python)/ usr / local / bin
  • macOS(使用macports安装的Python)/ opt / local / bin

要在Windows中显示当前路径,命令是echo % path%,在其他系统中,echo $ PATH。

**注意:**如果由于脚本目录不在PATH中而无法使用pyinstaller命令,则可以改InsteadInokePyInstaller模块,通过运行python -m PyInstaller(注意模块名,大小写敏感)来实现。
当您在多个Python环境中安装了PyInstaller,并且您无法确定pyinstaller命令将从哪个安装中运行时,这种调用形式也很有用。

2.4.3 已安装命令

完整的安装会将这些命令放在执行路径上:

  • pyinstaller是构建打包应用程序的主要命令。请参见“使用PyInstaller”。
  • pyi-makespec用于创建规范文件。请参见“使用Spec文件”。
  • pyi-archive_viewer用于检查打包的应用程序。请参见“检查存档”。
  • pyi-bindepend用于显示可执行文件的依赖项。请参见“检查可执行文件”。
  • pyi-grab_version用于从Windows可执行文件中提取版本资源。请参见“捕获Windows版本数据”。
  • pyi-set_version可用于将之前提取的版本资源应用于现有的Windows可执行文件。

8 第二章目录:

2.5 PyInstaller是什么以及它如何工作

本节介绍了PyInstaller的基本思想。这些思想适用于所有平台。特定选项和案例在下面讨论,详见“使用PyInstaller”。

PyInstaller读取由您编写的Python脚本。它分析您的代码以发现脚本在执行时需要的每个其他模块和库。然后它收集所有这些文件的副本-包括活动的Python解释器! -并将它们与您的脚本放在单个文件夹中,或者可选地放在单个可执行文件中。

对于绝大多数程序,可以用一个简短的命令完成这一过程:

pyinstaller myscript.py

或者,你可以通过添加一些选项使其成为单文件的可执行窗口应用程序:

pyinstaller --onefile --windowed myscript.py

你将这个捆绑文件夹或文件分发给别人,他们可以执行你的程序。对于你的用户来说,这个应用程序是自包含的。他们不需要安装任何特定版本的Python或任何模块。他们甚至无需安装Python。

注意:PyInstaller的输出是特定于操作系统和Python版本的。这意味着,如果要为:

  • 不同的操作系统
  • 不同版本的Python
  • 32位或64位操作系统

准备发行版,你必须在该操作系统下,在该Python版本下运行PyInstaller。执行PyInstaller的Python解释器是捆绑中的一部分,它特定于操作系统和字长。

2.5.1 分析:查找程序需要的文件

你的脚本还需要哪些模块和库才能运行?(有时这些称为“依赖项”。)

为了找出来,PyInstaller会查找你脚本中所有的import语句。它会找到导入的模块,并在其中查找import语句,以此递归下去,直到获得可能需要使用的代码模块清单。

PyInstaller理解常用于Python包的“egg”分布格式。如果你的脚本从“egg”导入模块,PyInstaller会将“egg”及其依赖项添加到所需文件集中。

PyInstaller还了解许多主要的Python包,包括GUI包Qt(通过PyQt或PySide导入)WxPython,TkInter,matplotlib和其他主要包。有关完整列表,请参见支持的包。

一些Python脚本以PyInstaller无法检测的方式导入模块:例如,使用可变数据的__import __()函数,使用importlib.import_module(),或在运行时操作sys.path值。如果你的脚本需要PyInstaller不知道的文件,你必须协助它:

  • 可以在pyinstaller命令行上提供其他文件。

  • 可以在命令行上提供其他导入路径。

  • 您可以编辑PyInstaller为您的脚本第一次运行时编写的myscript.spec文件,该spec文件可以告诉PyInstaller有关您脚本独有的代码模块。

  • 您可以编写“hook”文件来通知PyInstaller隐式导入的模块。如果您为其他用户可能也会使用的包创建“hook”文件,则可以将您的hook文件贡献给PyInstaller。

如果您的程序依赖于访问某些数据文件,还可以将它们包含在捆绑包中。这可以通过修改spec文件来实现,这是一个高级主题,在“使用spec文件”中介绍。

为了在运行时定位包含的文件,您的程序需要能够以一种方式在运行时学习其路径,无论它是否从捆绑中运行。这在“运行时信息”下介绍。

PyInstaller不会包含应该存在于此OS的任何安装库。例如,在GNU / Linux中,它不会捆绑任何/lib或/usr/lib文件,因为这些被认为会在每个系统中找到。

2.5.2 打包到一个文件夹

当你应用PyInstaller到myscript.py时,结果默认为单个名为myscript的文件夹。此文件夹包含所有脚本的依赖项,以及一个名为myscript的可执行文件(在Windows中为myscript.exe)。

你可以将该文件夹压缩为myscript.zip并传输给你的用户。他们只需解压缩即可安装程序。用户可以通过打开文件夹并在其中启动myscript可执行文件来运行你的应用程序。

使用一个文件夹模式调试出现的问题非常容易。你可以清楚地看到PyInstaller收集到的所有文件。

一个文件夹包的另一个优点是,当你更改代码时,只要它导入 完全相同的依赖项集,你可以发送仅更新的myscript可执行文件。这通常比整个文件夹小得多。 (如果你更改脚本,以便它导入更多或不同的依赖项,或者如果依赖项被更新,则必须重新分发整个捆绑。)

一个小的不利之处是,单个文件夹格式意味着一个文件夹包含大量文件。你的用户必须在一长串名称或大量图标数组中找到myscript可执行文件。此外,用户可以通过意外拖动文件出文件夹来创建问题。

2.5.3 一个文件夹程序是如何工作的

一个捆绑的程序始终从PyInstaller引导程序开始执行。这是文件夹中myscript执行文件的核心。

PyInstaller引导程序是特定于平台(Windows,GNU / Linux,macOS等)的二进制可执行程序。当用户启动您的程序时,就是引导程序在运行。引导程序创建一个临时的Python环境,使得Python解释器可以在myscript文件夹中找到所有导入的模块和库。

引导程序启动一个Python解释器的副本来执行你的脚本。如果所有必要的支持文件都包含在内,一切都会如常进行。

(这是一个概述。有关更多详细信息,请参见下面的“详细引导过程”。)

2.5.4 打包到一个文件

PyInstaller可以将你的脚本和所有依赖项捆绑到一个名为myscript的单个可执行文件中(在Windows中为myscript.exe)。

优点是,用户可以获得他们理解的单个可执行文件来启动应用程序。缺点是,任何相关文件,例如README,必须单独分发。此外,单个可执行文件的启动速度比一个文件夹更慢一些。

在尝试打包到一个文件之前,请确保你的应用程序在打包到一个文件夹时正常工作。在一个文件夹模式下,诊断问题要容易得多。

2.5.5 一个文件的程序是如何工作的

引导程序也是单个文件的捆绑。当它启动时,它在这个操作系统的适当的临时文件夹位置中创建一个临时文件夹。该文件夹的名称为_MEIxxxxxx,其中xxxxxx是一个随机数。

单个可执行文件包含所有你脚本使用的Python模块的嵌入式档案,以及任何非Python支持文件(例如.so文件)的压缩副本。引导程序解压缩支持文件并将副本写入临时文件夹中。这可能需要一些时间。这就是为什么一个单文件的应用程序启动比一个单文件夹慢一点的原因。

注意:目前PyInstaller不会保留文件属性,请参见#3926。

创建临时文件夹后,引导程序在临时文件夹的上下文中按照一个文件夹捆绑的方式进行,当捆绑的代码终止时,引导程序删除临时文件夹。

(在GNU/Linux及相关系统中,可以使用“no-execution”选项挂载/tmp文件夹。但该选项与PyInstaller的一文件打包不兼容。它需要在/tmp中执行代码。如果您了解目标环境,–runtime-tmpdir 可能会是一个解决方法。)

由于程序会创建一个带有唯一名称的临时文件夹,因此您可以运行多个应用程序副本;它们不会相互干扰。但是,运行多个副本会占用大量磁盘空间,因为没有共享。

如果程序崩溃或被终止(在Windows上由任务管理器终止,在macOS上选择“强制退出”,在Unix上使用“kill -9”命令),则_MEIxxxxxx临时文件夹不会被删除。因此,如果您的应用程序经常崩溃,用户将失去多个_MEIxxxxxx临时文件夹的磁盘空间。

可以通过使用–runtime-tmpdir命令行选项控制_MEIxxxxxx文件夹的位置。指定的路径存储在可执行文件中,引导程序将在指定文件夹内创建_MEIxxxxxx文件夹。有关详细信息,请参阅“定义提取位置”。

**注意:**不要在Windows上给单文件可执行文件赋予管理员权限(“以管理员身份运行此程序”)。有一种不太可能但不可能的方式可以使恶意攻击者在引导程序准备临时文件夹时破坏其中的共享库之一。在普遍情况下分发特权程序时,请确保文件权限防止共享库或可执行文件被篡改。否则,具有这些文件写访问权的未提升进程可能会通过修改这些文件来升级权限。

**注意:**使用os.setuid()的应用程序可能会遇到权限错误。捆绑应用程序运行的临时文件夹在调用setuid之后可能无法读取。如果您的脚本需要调用setuid,则最好使用单文件夹模式,以便更好地控制其文件的权限。

2.6使用PyInstaller

pyinstaller命令的语法为:

pyinstaller[options]script[script...]|specfile

在最简单的情况下,将当前目录设置为程序myscript.py的位置,然后执行:

pyinstaller myscript.py

PyInstaller会分析myscript.py并:

  • 在与脚本相同的文件夹中编写myscript.spec。
  • 如果路径不存在,则在与脚本相同的文件夹中创建一个build文件夹。
  • 在build文件夹中写入一些日志文件和工作文件。
  • 如果路径不存在,则在与脚本相同的文件夹中创建一个dist文件夹。
  • 在dist文件夹中写入myscript可执行文件夹。

在dist文件夹中,您会找到分发给用户的捆绑应用程序。

通常情况下,您只需要在命令行上命名一个脚本。如果命名了多个脚本,则所有脚本都会被分析并包含在输出中。但是,命名的第一个脚本提供的是.spec文件的名称以及可执行文件夹或文件的名称。运行时,其代码是第一个要执行的代码。

对于某些用途,您可以编辑mscript.spec的内容(在“使用规范文件”下进行描述)。完成此操作后,您将规范文件的名称命名为PyInstaller而不是脚本:

pyinstaller myscript.spec

myscript.spec文件包含大部分通过带脚本文件作为参数运行pyinstaller(或pyi-makespec)时指定的选项提供的信息。通常情况下,运行具有规范文件的pyinstaller时,无需指定任何选项。在从规范文件构建时,只有少数命令行选项会生效。

您可以为脚本或规范文件提供路径,例如

pyinstaller options... ~/myproject/source/myscript.py

或在Windows上:

pyinstaller "C:\Documents and Settings\project\myscript.spec"

2.6.1 选项

pyinstaller命令的完整选项列表如下:

位置参数

脚本名称
要处理的脚本文件的名称或一个.spec文件。如果指定了.spec文件,则大多数选项都不需要,不会起作用。

可选参数

-h,-help
显示此帮助消息并退出。

-v,--version
显示程序版本信息并退出。

--dispath DIR
放置捆绑应用程序的位置(默认值:./dist)。

--workpath WORKPATH
放置所有临时工作文件、.log、.pyz 等的位置(默认值:./build)。

-y,--noconfirm
替换输出目录(默认值:SPECPATH/dist/SPECNAME)而无需确认。

--upx-dirUPX_DIR
UPX实用程序的路径(默认值:搜索执行路径)。

-a,--ascii
不包括Unicode编码支持(默认情况下,如果可用,则包括Unicode编码支持)。

--clean
在构建前清除 PyInstaller 缓存和临时文件。

--log-level LEVEL
生成时间控制台消息的详细程度。LEVEL 可以是 TRACE、DEBUG、INFO、WARN、DEPRECATION、ERROR、FATAL(默认值:INFO)。也可以通过 PYI_LOG_LEVEL 环境变量设置并覆盖。

生成什么

-D,--onedir
创建一个包含可执行文件的单文件夹捆绑包(默认值)。

-F,--onefile
创建一个单文件捆绑可执行文件。

--specpath DIR
生成的 spec 文件存放的文件夹(默认值:当前目录)。

-n NAME,--name NAME
指定打包应用的名称和 spec 文件名称(默认值:第一个脚本的基本名称)。

2.6. 使用 PyInstaller 13

捆绑什么,在哪里搜索

--add-data 
添加非二进制文件或文件夹到可执行文件中。路径分隔符是平台特定的,使用 os.pathsep(在 Windows 上是‘;’,在大多数 Unix 系统上是‘:’)。该选项可以多次使用。

--add-binary 
添加二进制文件到可执行文件中。有关更多详细信息,请参见--add-data 选项。该选项可以多次使用。

-p DIR,--paths DIR
一个用于搜索导入路径的路径(类似于使用 PYTHONPATH)。可以使用多个路径,用':'分隔,或者多次使用此选项。相当于在 spec 文件中提供一个 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 HOOKS_PATH
用于搜索钩子的附加路径。该选项可以多次使用。

--runtime-hook RUNTIME_HOOKS
自定义运行时钩子文件路径。运行时钩子是与可执行文件捆绑的代码,并在任何其他代码或模块之前执行,以设置运行时环境的特殊特性。该选项可以多次使用。

--exclude-module EXCLUDES
忽略的可选模块或包(非路径名而是 Python 名称)。该选项可以多次使用。

--splash IMAGE_FILE
(实验性)向应用程序添加一个带有图像 IMAGE_FILE 的启动画面。在解压缩时,启动画面可以显示进度更新。

14 第 2 章 内容:

如何生成

-d {all,imports,bootloader,noarchive},--debug {all,imports,bootloader,noarchive}
提供帮助调试冻结应用程序。可多次提供此参数以选择以下多个选项。- all:所有三个选项。- imports:指定-v选项给基础 Python 解释器,使其在每次初始化模块时打印一条消息,显示从哪个位置(文件名或内置模块)加载模块。请参见 https://docs.python.org/3/using/cmdline.html#id4。 - bootloader:告诉启动程序在初始化和启动捆绑应用程序时发布进度消息。用于诊断缺失导入的问题。 - noarchive:存储所有冻结的 Python 源文件,而不是将它们存储为结果执行文件中的存档。

--python-option PYTHON_OPTION
指定要在运行时传递给 Python 解释器的命令行选项。当前支持“v”(等效于“--debug imports”)、“u”和“W ”。

-s,--strip
对可执行文件和共享库应用符号表削减(不建议在 Windows 上使用)。

--noupx
即使可用,也不要使用 UPX(在 Windows 和 *nix 之间的工作方式不同)。

--upx-exclude FILE
当使用 upx 时,防止对二进制文件进行压缩。如果在压缩期间 upx 损坏某些二进制文件,则通常使用此选项。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 
FILE.ico:将图标应用于 Windows 可执行文件。FILE.exe,ID:从 exe 中提取具有 ID 的图标。FILE.icns:将图标应用于 Mac OS 上的 .app 捆绑包。如果输入的图像文件不是平台格式(Windows 上的 ico、Mac 上的 icns),则 PyInstaller 尝试使用 Pillow 将图标转换为正确的格式(如果安装了 Pillow)。使用“NONE”来不应用任何图标,从而使操作系统显示一些默认值(默认值:应用 PyInstaller 的图标)。该选项可以多次使用。

--disable-windowed-traceback
禁用窗口(noconsole)模式下无处理异常的 traceback 转储(仅适用于 Windows 和 macOS),并显示一条消息,说明禁用了此功能。

**2.6. 使用 PyInstaller 15**

**仅适用于 Windows 的选项**

--version-fileFILE
将版本资源从FILE加入exe文件中。

-m ,--manifest 
加入manifest文件或XML到exe文件中。

--no-embed-manifest
生成外部的.exe.manifest文件而不是将manifest嵌入exe文件中。仅适用于onedir模式; 在onefile模式中,无论这个选项如何,manifest都会被嵌入。

-r RESOURCE,--resource RESOURCE
向Windows可执行文件添加或更新资源。RESOURCE有一到四个项,FILE[,TYPE[,NAME[,LANGUAGE]]]。FILE可以是数据文件或exe/dll。对于数据文件,至少必须指定TYPE和NAME。LANGUAGE默认为0,或可以指定为通配符*以更新指定类型和名称的所有资源。对于exe/dll文件,如果省略了TYPE、NAME和LANGUAGE,或将其指定为通配符*,所有来自FILE的资源都将添加/更新到最终可执行文件中。此选项可以多次使用。

--uac-admin
使用此选项创建一个请求在应用程序启动时提升权限的清单。

--uac-uiaccess
使用此选项可允许提升后的应用程序使用远程桌面。

Windows Side-By-Side Assembly Searching Options (Advanced)

--win-private-assemblies
将打包到应用程序中的任何共享组件更改为私有组件。这意味着这些组件的确切版本将始终被使用,并且在用户计算机上以系统级别安装的任何较新版本都将被忽略。

--win-no-prefer-redirects
在搜索共享或私有组件以打包到应用程序中时,PyInstaller将不喜欢遵循重定向到较新版本的策略,并会尝试打包组件的精确版本。

Mac Os Specific Options

--argv-emulation
启用macOS应用程序捆绑包的argv仿真。如果启用,初始打开文档/URL事件将由引导加载程序处理,并将传递的文件路径或URL附加到sys.argv中。

--osx-bundle-identifier BUNDLE_IDENTIFIER
Mac OS .app绑定标识符被用作用于代码签名的默认唯一程序名称。通常的形式是DNS反转表示法的分层名称。例如:com.mycompany.department.appname(default:firstscript’sbasename)

--target-architectureARCH,--target-arch ARCH
目标架构(仅适用于macOS;有效值:x86_64、arm64、universal2)。允许在通用2和单架构版本的冻结应用程序之间切换(只要python安装支持目标架构)。如果没有指定目标架构,就会以当前运行的架构为目标。

--codesign-identifier IDENTITY
代码签名标识符(仅适用于macOS)。使用提供的标识符对收集到的二进制文件和生成的可执行文件进行签名。如果没有提供签名标识符,则执行自发签名。

**第16章2.内容:**

--osx-entitlements-file FILENAME
在代码签名收集的二进制文件时使用的权限文件(仅适用于macOS)。

**Rarely Used Special Options**

--runtime-tmpdirPATH
在_onefile_ -mode中提取库文件和支持文件的位置。如果给出此选项,则引导程序将忽略运行时操作系统定义的任何临时文件夹位置。_MEIxxxxxx_-文件夹将在此处创建。只有当您知道自己在做什么时,请使用此选项。

--bootloader-ignore-signals
告诉引导程序忽略信号而不是将它们转发给子进程。在诸如监管进程向引导程序和子进程发送信号(例如通过进程组)的情况下非常有用,以避免向子进程发出两次信号。

2.6.2缩短命令

由于其众多选项,完整的pyinstaller命令可能会变得非常长。在开发脚本时,您将一遍又一遍地运行相同的命令。您可以将命令放入Shell脚本或批处理文件中,使用换行符使其可读。例如,在GNU/Linux中:

pyinstaller --noconfirm --log-level=WARN \
--onefile --nowindow \
--add-data="README:." \
--add-data="image1.png:img" \
--add-binary="libfoo.so:lib" \
--hidden-import=secret1 \
--hidden-import=secret2 \
--upx-dir=/usr/local/share/ \
myscript.spec

或在Windows中,使用鲜为人知的BAT文件行延续:

pyinstaller --noconfirm --log-level=WARN ^
--onefile --nowindow ^
--add-data="README;." ^
--add-data="image1.png;img" ^
--add-binary="libfoo.so;lib" ^
--hidden-import=secret1 ^
--hidden-import=secret2 ^
--icon=..\MLNMFLCN.ICO ^
myscript.spec

2.6.使用PyInstaller 17

2.6.3从Python代码中运行PyInstaller

如果您想要从Python代码运行PyInstaller,可以使用PyInstaller.__main__中定义的run函数。例如,以下代码:

import PyInstaller.__main__

PyInstaller.__main__.run([
'my_script.py',
'--onefile',
'--windowed'
])

等价于:

pyinstaller my_script.py --onefile --windowed

2.6.4使用UPX

UPX是一个免费的可执行文件和库文件压缩实用程序。它适用于大多数操作系统,可以压缩大量的可执行文件格式。请查看UPX主页进行下载,并查看支持的文件格式列表。

当UPX可用时,PyInstaller使用它来逐个压缩每个收集到的二进制文件(可执行文件、共享库或python扩展),以减少冻结应用程序(one-dir捆绑目录或one-file可执行文件)的总体大小。冻结应用程序的可执行文件本身没有经过UPX压缩(不管是one-dir还是one-file模式),因为其大部分大小包含了已经包含了经过压缩的文件的嵌入式档案。

PyInstaller 在标准可执行路径(由PATH环境变量定义)或通过–upx-dir 命令行选项指定的路径中查找 UPX。如果找到它,将自动使用。可以使用–noupx 命令行选项完全禁用 UPX。

注意: UPX 目前仅在 Windows 上使用。在其他操作系统上,即使找到 UPX,也不会处理收集的二进制文件。在现代 linux 发行版上构建的共享库(例如,Python 共享库)似乎在使用 UPX 处理时会破坏,导致无法运行的应用程序包。在 macOS 上,UPX 目前无法处理 dylib 共享库;此外,经过 UPX 压缩的文件未能通过codesign实用程序的验证检查,因此无法进行代码签名(这是 Apple M1 平台的要求)。

从 UPX 处理中排除有问题的文件

使用 UPX 可能最终会使收集的共享库损坏。已知的这种损坏的示例是启用 Control Flow Guard (CFG) 的 Windows DLL,以及 Qt5 和 Qt6 插件。在这种情况下,需要使用–upx-exclude 选项(或者在 .spec 文件 中使用 upx_exclude 参数)排除个别文件的 UPX 处理。

从版本 4.2 开始:PyInstaller 检测到启用了 CFG 的 DLL 并自动将其排除在 UPX 处理之外。

从版本 4.3 开始:PyInstaller 自动将 Qt5 和 Qt6 插件从 UPX 处理中排除。

尽管 PyInstaller 尝试自动检测和排除部分可能会有问题的文件,但仍有一些情况需要手动指定 UPX 排除。例如,据报告,来自 PySide2 软件包的 32 位 Windows 二进制文件(Qt5 DLL 和 Python 扩展模块)会被 UPX 破坏。

18 第 2 章 内容:

从版本 5.0 开始:与之前的版本不同,它将提供的 UPX 排除名称与收集二进制文件的基本名称进行比较(由于不完整的大小写规范化,在 Windows 上需要提供小写排除名称),现在 UPX 排除模式匹配使用 OS 默认的大小写敏感性,并支持通配符 (*) 运算符。它还支持指定文件的(完整或部分)父路径。

提供的 UPX 排除模式名称与收集的二进制文件的源路径进行匹配,并从右到左执行匹配。

例如,要排除来自 PySide2 软件包的 Qt5 DLL,请使用–upx-exclude “Qt*.dll”,要排除来自 PySide2 软件包的 Python 扩展,请使用–upx-exclude “PySide2*.pyd”。

2.6.5 起动画面(实验性)

**注意:**此功能与 macOS 不兼容。在当前设计中,启动画面在次要线程中运行,这是 macOS 上的 Tcl/Tk(或者更确切地说是底层 GUI 工具包)所不允许的。

一些应用程序可能需要在应用程序(引导程序)启动后尽快显示起动画面,因为特别是在单文件模式下,大型应用程序可能需要长时间的提取/启动时间,而引导程序准备所有这些时,用户不能判断应用程序是否成功启动。

引导程序能够显示一张单一的图像(即仅图像),该图像会在实际的主提取过程开始之前显示。启动画面支持不透明和硬剪切透明图像作为背景图像,因此也可以显示非矩形起动画面。

此启动画面基于 Tcl/Tk,这是 Python 模块 tkinter 使用的同一库。PyInstaller 在编译时将 tcl 和 tk 的动态库捆绑到应用程序中。这些库在启动应用程序时在引导程序中加载(如果程序已封装为单文件存档)。由于所需动态库的文件大小非常小,在应用程序启动和启动画面之间几乎没有延迟。启动画面所需文件的压缩大小约为 1.5 MB。

作为附加功能,可以在启动画面上选择性地显示文本。这可以从 Python 中更改/更新。这提供了在 Python 程序的较长启动过程(例如等待网络响应或将大型文件加载到内存中)中显示起动画面的可能性。您还可以在启动画面后启动一个 GUI,只有在完全初始化后才能关闭起动画面。可选择设置文本的字体、颜色和大小。然而,必须在用户系统上安装字体,因为它未捆绑。如果字型不可用,则使用备用字型。

如果已将起动画面配置为显示文本,则它将自动(作为单个文件存档)显示当前正在解压缩的文件名,这充当进度条。

2.6.6 pyi_splash 模块

起动画面由在 Python 内部控制的 pyi_splash 模块控制,该模块可以在运行时导入。此模块无法由包管理器安装,因为它是 PyInstaller 的一部分,会根据需要进行包含。此模块必须在 Python 程序中导入。用法如下:

import pyi_splash

# 更新起动画面上的文本
pyi_splash.update_text("PyInstaller is a great software!")
pyi_splash.update_text("Second time's a charm!")

# 关闭起动画面。调用此函数的时间不重要,直到此函数被调用或 Python 程序终止,起动画面将保持打开状态。
pyi_splash.close()

当然,为了防止程序被用作普通的 Python 脚本而没有引导程序,应将其导入放在 try … except 块内。有关详细描述,请参阅 pyi_splash 模块(详细)。

2.6.7 定义提取位置

在罕见情况下,当您将软件包捆绑为单个可执行文件(请参见 Bundling to One FileHow the One-File Program Works)时,您可能希望在编译时控制临时目录的位置。可以使用 --runtime-tmpdir 选项来做到这一点。如果给出此选项,则引导程序将忽略运行时 OS 定义的任何临时文件夹位置。请仅在您知道自己在做什么时使用此选项。

2.6.8 支持多个平台

如果您只为操作系统和 Python 的一个组合分发应用程序,请像安装任何其他程序包一样安装 PyInstaller,并在常规开发设置中使用它。

支持多个 Python 环境

当您需要将应用程序捆绑在一个操作系统中,但需要支持不同版本的Python和支持库,比如Python 3.6版本和Python 3.7版本,或者使用Qt4的支持版本和使用Qt5的开发版本,我们建议您使用venv。使用_venv_,您可以维护不同的Python和安装包的组合,并轻松切换一个组合到另一个组合。这些称为虚拟环境或短称为_venvs_。

使用_venv_创建任意数量的开发环境,每个环境都有其自己独特的Python和安装包的组合。

在每个虚拟环境中安装PyInstaller。

在每个虚拟环境中使用PyInstaller构建您的应用程序。

请注意,使用_venv_时,PyInstaller命令的路径是:

  • Windows:ENV_ROOT \ Scripts
  • 其他:ENV_ROOT / bin

在Windows下,pip-Win软件包使设置不同环境并在它们之间切换变得特别容易。在GNU/Linux和macOS下,您可以在命令行中切换环境。

有关Python虚拟环境的详细信息,请参阅PEP 405和官方的Python教程。

第20章2. 目录:

支持多个操作系统

如果您需要将应用程序分发给多个操作系统,例如Windows和macOS,则必须在每个平台上安装PyInstaller并分别捆绑应用程序。

您可以使用虚拟化从一台机器上执行此操作。免费的virtualBox或付费的VMWare和Parallels允许您作为“客户”运行另一个完整的操作系统。您为每个“客户”操作系统设置一个虚拟机。在其中,您安装Python,您的应用程序所需的支持软件包以及PyInstaller。

像NextCloud这样的文件同步和共享系统对于虚拟机非常有用。在每个虚拟机中安装同步客户端,所有客户端都连接到您的同步帐户。保持单个的脚本副本在一个同步文件夹中。然后您可以在任何虚拟机上运行PyInstaller,例如:

cd ~/NextCloud/project_folder/src# GNU/Linux, Mac – Windows类似
rm *.pyc#删除另一种Python编译的模块
pyinstaller --workpath=path-to-local-temp-folder
–distpath=path-to-local-dist-folder
…必要的其他选项…
./myscript.py

PyInstaller从共享的同步文件夹读取脚本,但将其工作文件和捆绑的应用程序写入本地虚拟机文件夹。

如果您在多个平台上共享相同的主目录,例如GNU/Linux和macOS,则需要在每个平台上设置PYINSTALLER_CONFIG_DIR环境变量,否则PyInstaller可能会为一个平台缓存文件并在另一个平台上使用它们,因为默认情况下,它使用你的主目录的子目录作为其缓存位置。

据说可以使用免费的Wine环境在GNU/Linux下进行Windows交叉开发。需要更多详细信息,请参见如何贡献。

第2.6.9节 捕获Windows版本数据

Windows应用程序可能需要一个版本资源文件。版本资源包含一组数据结构,有些包含二进制整数,有些包含字符串,用于描述可执行文件的属性。有关详细信息,请参见Microsoft版本信息结构页面。

版本资源很复杂,一些元素是可选的,另一些是必需的。在查看属性对话框的版本选项卡时,显示的数据与资源的结构之间没有简单的关系。因此,PyInstaller包括pyi-grab_version命令。它使用具有版本资源的任何Windows可执行文件的完整路径名调用:

pyi-grab_version executable_with_version_resource

该命令将以可读形式写入表示版本资源的文本,输出到标准输出。可以从控制台窗口复制它,也可以将其重定向到文件。然后,您可以编辑版本信息,以使其适应您的程序。使用pyi-grab_version,您可以查找显示所需信息的可执行文件,复制其资源数据,并修改以适应您的套餐。

版本文本文件采用UTF-8编码,可能包含非ASCII字符。 (版本资源字符串字段允许Unicode字符。) 除非您确定它仅包含ASCII字符串值,请一定使用UTF-8编辑和保存文本文件。

您编辑的版本文本文件可以使用–version-file选项提供给pyinstaller或pyi-makespec。文本数据被转换为版本资源,并安装在捆绑的应用程序中。

在版本资源中,有两个64位二进制值,FileVersion和ProductVersion。在版本文本文件中,这些值以四个元素的元组给出,例如:

第2.6章 使用PyInstaller 21

filevers=(2, 0, 4, 0),
prodvers=(2, 0, 4, 0),

每个元组的元素从最高位到最低位表示16位值。例如,值(2, 0, 4, 0)解析为16进制数0002000000040000。

您还可以在捆绑的应用程序创建后使用pyi-set_version命令将版本资源从文本文件安装:

pyi-set_version version_text_file executable_file

pyi-set_version实用程序读取由pyi-grab_version编写的版本文本文件,将其转换为Version资源,并将该资源安装在指定的_executable_file_中。

对于高级使用,检查由pyi-grab_version编写的版本文本文件。您会发现它是创建VSVersionInfo对象的Python代码。
VSVersionInfo的类定义在PyInstaller发行版文件夹utils/win32/versioninfo.py中。您可以编写导入versioninfo的程序。在该程序中,您可以eval版本信息文本文件的内容以生成VSVersionInfo对象。您可以使用该对象的.toRaw()方法以二进制形式生成版本资源。或者,您可以应用unicode()函数到对象以重现版本文本文件。

2.6.10 构建macOS应用程序包

在macOS下,PyInstaller始终在dist中构建一个UNIX可执行文件。如果您指定了–onedir,则输出是一个名为myscript的文件夹,其中包含支持文件和名为myscript的可执行文件。如果您指定了–onefile,则输出是一个名为myscript的单个UNIX可执行文件。任何一个可执行文件都可以从终端命令行启动。标准输入和输出通过该终端窗口正常工作。

如果您使用–windowed和任意一个选项,则dist文件夹还包含名为myscript.app的macOS应用程序。

如您所知,应用程序是一种特殊的文件夹类型。由PyInstaller构建的应用程序包含一个名为Contents的文件夹,该文件夹始终存在,并包含:

  • 一个空的Frameworks文件夹。
  • 一个包含图标文件的Resources文件夹。
  • 一个描述应用程序的fileInfo.plist文件。
  • 一个包含可执行文件和支持文件的MacOS文件夹,就像–onedir文件夹中的一样。

使用–icon参数指定自定义应用程序图标。它将被复制到Resources文件夹中。
(如果不指定图标文件,PyInstaller将提供一个带有PyInstaller标志的fileicon-windowed.icns文件。)

使用–osx-bundle-identifier参数添加应用程序包标识符。这将成为用于代码签名的CFBundleIdentifier(请参见PyInstaller代码签名食谱,以及更多细节,请参见Apple代码签名概览技术说明)。

您可以通过编辑spec文件来向Info.plist添加其他项目。有关macOS包的_Spec文件选项_,请参阅下文。

第二十二章 2. 目录:

2.6.11 平台特定注释

GNU/Linux

使GNU/Linux应用程序向前兼容

在GNU/Linux下,PyInstaller不会将C标准库(通常是Gnu版本的glibc)与应用程序捆绑在一起。相反,应用程序期望动态链接到运行它的本地操作系统中的libc。任何应用程序与libc之间的接口都是向前兼容的,但是它不向后兼容较旧的版本。

因此,如果您在当前版本的GNU/Linux上捆绑应用程序,则在较旧版本的GNU/Linux上执行时可能会失败(通常会出现运行时动态链接错误)。

解决方案是始终在您打算支持的_最旧_版本的GNU/Linux上构建您的应用程序。它应该继续使用在较新版本中发现的libc工作。

GNU/Linux标准库(例如glibc)分为64位和32位版本,它们不兼容。因此,您无法在32位系统上捆绑应用程序并在64位安装上运行它,反之亦然。您必须为每个支持的字长制作唯一的应用程序版本。

请注意,PyInstaller确实捆绑了通过依赖关系分析发现的其他共享库,例如libstdc++.so.6、libfontconfig.so.1、libfreetype.so.6。这些库可能在可用较旧(因此不兼容)版本的这些库的系统上需要。另一方面,捆绑的库可能会在尝试加载与较新版本的系统提供的库链接的系统提供的共享库时出现问题。

例如,系统安装的mesa DRI驱动程序(例如radeonsi_dri.so)依赖于系统提供的libstdc++.so.6版本。如果冻结的应用程序捆绑了较旧版本的libstdc++.so.6(如从构建系统收集的版本),这通常会导致缺少符号错误并防止DRI驱动程序加载。在这种情况下,应删除捆绑的libstdc++.so.6。然而,这可能在提供的libstdc++.so.6旧于构建系统的情况下不起作用;在这种情况下,应保留捆绑版本,因为系统提供的版本可能缺少其他依赖于libstdc++.so.6的收集二进制文件所需的符号。

Windows

开发人员需要特别注意包括Visual C++运行时.dll文件:Python 3.5+使用Visual Studio 2015运行时,该运行时已更名为“通用CRT”,并成为Windows 10的一部分。对于Windows Vista到Windows 8.1,有Windows Update包,可能已安装在目标系统中。因此,您有以下选项:

  1. Windows 7 上构建,已有人报告过可以工作。
  2. 将VCRedist包之一(可再分发包文件)包含在应用程序安装程序中。这是微软的推荐方法,请参见上述链接中的“分发使用通用CRT的软件”,2和3号。
  3. 安装Windows 10的Windows软件开发工具包(SDK),并扩展.spec文件以包括所需的DLL文件,请参见上述链接中的“分发使用通用CRT的软件”,第6号。如果您认为PyInstaller应该自己完成此操作,请_帮助改进_ PyInstaller。

2.6. 使用PyInstaller 23

macOS

使macOS应用程序向前兼容

在macOS上,来自OS一个版本的系统组件通常与后续版本兼容,但是可能无法与较旧版本兼容。虽然PyInstaller不会收集OS的系统组件,但收集的第三方二进制文件(例如Python扩展模块)是根据特定版本的OS库构建的,可能支持或不支持较旧的OS版本。

因此,确保您的冻结应用程序支持旧版OS的唯一方法是在您希望支持的最旧版本的OS上冻结它。这特别适用于使用Homebrew Python构建时,因为其二进制文件通常明确地针对正在运行的OS。

例如,要确保与“Mojave”(10.14)和更高版本兼容,您应该在macOS 10.14的副本中设置完整环境(即,在必要时使用虚拟机安装python、PyInstaller、应用程序的代码和其所有依赖项)。然后使用PyInstaller在该环境中冻结您的应用程序;生成的冻结应用程序应与该版本以及更高版本的macOS兼容。

在macOS中构建32位应用程序

**注意:**此节大部分已经过时,因为在macOS 10.15 Catalina中删除了对32位应用程序的支持(有关现代版本的macOS的64位多体系结构支持,请参见_此处_)。然而,PyInstaller仍支持构建32位启动加载程序,并且仍然可以从python.org获取32位/64位Python安装程序(某些版本的Python 3.7)。

较旧版本的macOS支持32位和64位可执行文件。PyInstaller使用用于执行它的Python的字长构建应用程序。那通常是Python的64位版本,导致生成64位可执行文件。要创建32位可执行文件,请在32位Python下运行PyInstaller。

要验证安装的Python版本是否支持以64位或32位模式执行,请使用file命令对Python可执行文件进行如下操作:

$ file /usr/local/bin/python3
/usr/local/bin/python3: Mach-O universal binary with 2 architectures
/usr/local/bin/python3 (for architecture i386): Mach-O executable i386
/usr/local/bin/python3 (for architecture x86_64): Mach-O 64-bit executable x86_64

操作系统选择要运行的架构,并且通常默认为64位。您可以使用arch命令按名称强制使用任一体系结构:

$ /usr/local/bin/python3
Python 3.7.6 (v3.7.6:43364a7ae0, Dec 18 2019, 14:12:53)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys; sys.maxsize
>>> 9223372036854775807

$ arch -i386 /usr/local/bin/python3
Python 3.7.6 (v3.7.6:43364a7ae0, Dec 18 2019, 14:12:53)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys; sys.maxsize
>>> 2147483647

第二章 第24节 内容:

注意: PyInstaller 不再为 macOS 提供预编译的 32 位 bootloader,如果要使用 PyInstaller 和 32 位 Python,需要自己构建 bootloader,使用支持编译 32 位的 XCode 版本。根据编译器/工具链的不同,您还需要显式传递–target-arch=32bit参数给waf命令。

获取已打开的文档名称

当用户双击已注册应用程序的某种类型的文档或将其拖放到应用程序图标上时,macOS 会启动应用程序并以 OpenDocument AppleEvent 的形式提供打开文档的名称。

这些事件通常通过应用程序中安装的事件处理程序来处理(例如,使用 CarbonAPI 通过 ctypes,或者使用 UI 工具包提供的工具,例如 tkinter 或 PyQt5)。

或者,PyInstaller 还支持将打开的文档/URL 事件转换为附加到 sys.argv 的参数。这仅适用于在应用程序启动期间接收到的事件,即在启动冻结代码之前。要处理已在应用程序运行时分派的事件,需要设置相应的事件处理程序。

有关详情,请参阅本节。

AIX

根据 Python 是作为 32 位还是 64 位可执行文件构建的,您可能需要设置或取消设置环境变量 OBJECT_MODE。以下命令可用于确定大小:

$ python -c "import sys; print(sys.maxsize <= 2**32)"
True

当回答是 True(如上所示)时,Python 是作为 32 位可执行文件构建的。

在使用 32 位 Python 可执行文件时,请按以下步骤进行操作:

$ unset OBJECT_MODE 
$ pyinstaller  

在使用 64 位 Python 可执行文件时,请按以下步骤进行操作:

$ export OBJECT_MODE=64 
$ pyinstaller  

2.7 运行时信息

您的应用程序应在包中正常运行,就像从源代码运行时一样。但是,您可能需要在运行时了解应用程序是从源代码运行还是捆绑(“冻结”)。您可以使用以下代码来检查“我们是否已捆绑?”:

import sys 
if getattr(sys,'frozen',False) and hasattr(sys,'_MEIPASS'): 
    print('running in a PyInstaller bundle') 
else: 
    print('running in a normal Python process')

当捆绑的应用程序启动时,引导程序设置了sys.frozen属性并将捆绑文件夹的绝对路径存储在sys._MEIPASS中。对于一个文件夹捆绑,这是该文件夹的路径。对于一个单文件捆绑,这是引导程序创建的临时文件夹的路径(见单文件程序的工作方式)。

当您的应用程序正在运行时,可能需要访问以下位置之一中的数据文件:

  • 已捆绑的文件(请参阅添加数据文件)。
  • 用户将文件与应用程序捆绑在一起,例如在相同的文件夹中。
  • 用户当前工作目录中的文件。

程序可以访问这些用途的几个变量。

2.7.1 使用__file__

当您的程序未捆绑时,Python 变量__file__是指所包含模块的当前路径。从捆绑的脚本导入模块时,PyInstaller 引导程序将设置模块的__file__属性为相对于捆绑文件夹的正确路径。

例如,如果从捆绑的脚本导入mypackage.mymodule,则该模块的__file__属性将是sys._MEIPASS+‘mypackage/mymodule.pyc’。因此,如果在mypackage/file.dat中添加了数据文件并将其添加到捆绑中,以下代码将获取其路径(在非捆绑和捆绑情况下):

from os import path 
path_to_dat = path.abspath(path.join(path.dirname(__file__),'file.dat')) 

在主脚本(即__main__模块)本身中,__file__变量包含脚本文件的路径。在 Python 3.8 及更早版本中,此路径是绝对或相对的(取决于如何将脚本传递给 python 解释器),而在 Python 3.9 及更高版本中,它始终是绝对路径。在捆绑脚本中,PyInstaller 引导程序总是将__file__变量设置在__main__模块内的绝对路径中,就像字节编译的入口点脚本在那里存在一样。

例如,如果你的入口点脚本名为program.py,则捆绑脚本内的__file__属性将指向sys._MEIPASS+‘program.py’。因此,相对于主脚本定位数据文件可以直接使用sys._MEIPASS,或通过主脚本内__file__的父路径。

如果没有捆绑,则以下示例将获取位于主脚本旁边的文件other-file.dat的路径,如果被捆绑,则位于捆绑文件夹内:

from os import path 
bundle_dir = path.abspath(path.dirname(__file__)) 
path_to_dat = path.join(bundle_dir,'other-file.dat') 

或者,如果您愿意使用 pathlib:

from pathlib import Path 
path_to_dat = Path(__file__).resolve().with_name("other-file.dat") 

4.3 版更改:以前,入口点脚本(__main__模块)的__file__属性仅设置为其基本名称,而不是其位于捆绑目录中的完整(绝对或相对)路径。因此,PyInstaller 文档过去通常建议使用sys._MEIPASS来定位相对于捆绑入口点脚本的资源。现在,__file__始终设置为绝对完整路径,并且是定位此类资源的首选方式。

第二章 第26节 内容:

将数据文件放置在捆绑包中预期的位置

为了将数据文件放置在您的代码期望的位置(即相对于主脚本或捆绑目录),您可以使用–add-data=source:dest命令行开关的dest参数。假设您通常可以在名为my_script.py的文件中使用以下代码来定位同一文件夹中的file.dat文件:

from os import path
path_to_dat = path.abspath(path.join(path.dirname(__file__),'file.dat'))

或者使用pathlib的等效代码:

from pathlib import Path
path_to_dat = Path(__file__).resolve().with_name("file.dat")

如果my_script.py是包的一部分(不在包含__init__.py的文件夹中),则__file__将是[app root]/my_script.pyc,这意味着如果您将file.dat放置在您的包的根目录中,则使用:

PyInstaller --add-data=/path/to/file.dat:.

在运行时可以正确找到而且不需要修改my_script.py。

**注意:**Windows用户应该在上述行中使用;而不是:。

如果__file__是从包或库(例如my_library.data)内部检查的,则__file__将是[app root]/my_library/data.pyc,并且–add-data应该与之相反:

PyInstaller --add-data=/path/to/my_library/file.dat:./my_library

然而,在这种情况下,更容易切换到_spec文件_并使用PyInstaller.utils.hooks.collect_data_files()辅助函数:

from PyInstaller.utils.hooks import collect_data_files

a = Analysis(...,
datas=collect_data_files("my_library"),
...)

2.7.2 使用sys.executable和sys.argv[0]

当普通的Python脚本运行时,sys.executable是执行的程序的路径,即Python解释器。在冻结的应用程序中,sys.executable也是执行的程序的路径,但它不是Python,而是在单文件应用程序或单文件夹应用程序中的可执行文件。这为您提供了一种可靠的方式来定位用户实际启动的冻结可执行文件。

sys.argv[0]的值是用户命令中使用的名称或相对路径。它可能是相对路径,也可能是绝对路径,具体取决于平台和应用程序如何启动。

如果用户通过符号链接启动应用程序,则sys.argv[0]将使用该符号名称,而sys.executable是实际路径。有时相同的应用程序会链接到不同的名称,并且希望根据用于启动其名称而表现出不同的行为。针对这种情况,您将测试os.path.basename(sys.argv[0])。

2.7.运行时信息 27

另一方面,有时用户被告知将可执行文件存储在与其操作的文件相同的文件夹中,例如应存储在与其播放音频文件相同的文件夹中的音乐播放器。针对此情况,您将使用os.path.dirname(sys.executable)。

以下小程序探讨了这些可能性。将其保存为directories.py。将其作为Python脚本执行,然后作为一个文件夹应用程序捆绑,然后将其捆绑为一个文件夹应用程序,并通过符号链接直接启动它和启动它:

#!/usr/bin/env python3
import sys, os
frozen ='not'
if getattr(sys,'frozen',False):
# we are running in a bundle
frozen ='ever so'
bundle_dir = sys._MEIPASS
else:
# we are running in a normal Python environment
bundle_dir = os.path.dirname(os.path.abspath(__file__))
print( 'we are',frozen,'frozen')
print( 'bundle dir is', bundle_dir )
print( 'sys.argv[0] is', sys.argv[0] )
print( 'sys.executable is', sys.executable )
print( 'os.getcwd is', os.getcwd() )

2.7.3 LD_LIBRARY_PATH / LIBPATH 记录

此环境变量用于发现库,即库搜索路径 - 在GNU / Linux和* BSD上,使用_LD_LIBRARY_PATH_,在AIX上,使用_LIBPATH_。

如果存在,PyInstaller将原始值保存为_*ORIG,然后修改搜索路径,以便捆绑的代码首先发现捆绑的库。

但是,如果您的代码执行系统程序,则通常不希望该系统程序加载您捆绑的库(这些库可能与您的系统程序不兼容),而应该从系统位置加载正确的库,就像通常一样。

因此,您需要在创建子进程与系统程序之前恢复原始路径。

env = dict(os.environ) # 复制环境
lp_key ='LD_LIBRARY_PATH' # 适用于GNU / Linux和* BSD。
lp_orig = env.get(lp_key +'_ORIG')
if lp_origis not None:
env[lp_key] = lp_orig # 恢复原始、未修改的值
else:
# 这发生在未设置LD_LIBRARY_PATH时。
# 仅作为最后一手:
env.pop(lp_key, None)
p = Popen(system_cmd, ..., env=env) # 创建进程

第2.8节 使用Spec文件

当您执行

pyinstaller options ..myscript.py

PyInstaller执行的第一件事就是构建一个spec(specification)文件myscript.spec。该文件存储在–specpath目录中,默认为当前目录。

spec文件告诉PyInstaller如何处理您的脚本。它对pyinstaller命令给出的脚本名称和大多数选项进行编码。实际上,spec文件是可执行的Python代码。PyInstaller通过执行spec文件的内容来构建应用程序。

对于许多使用PyInstaller的情况,您不需要检查或修改spec文件。通常,仅需将所有所需的信息(例如隐藏导入)作为pyinstaller命令的选项提供,并让其运行即可。

有四种情况下,修改spec文件会很有用:

  • 当您想要通过应用程序捆绑数据文件时
  • 当您想要包括运行时库(.dll或.sofiles),PyInstaller没有从任何其他来源获取的库时
  • 当您想要向可执行文件添加Python运行时选项时
  • 当您想要创建具有合并常见模块的多程序捆绑包时

这些用途在以下主题中介绍。

您可以使用以下命令创建一个spec文件:

pyi-makespec 选项 文件名.py [其他脚本...]

_options_是pyinstaller命令中文档化的选项。此命令将创建name.spec文件,但不会继续构建可执行文件。

创建spec文件并根据需要进行修改后,将spec文件传递给pyinstaller命令来构建应用程序:

pyinstaller 选项 name.spec

创建spec文件时,大多数命令选项都编码在spec文件中。构建来自spec文件时,这些选项无法更改。如果在命令行中给出这些选项,则会被忽略并替换为spec文件中的选项。

仅当从spec文件进行构建时,以下命令行选项才会生效:

  • –upx-dir
  • –distpath
  • –workpath
  • –noconfirm
  • –ascii
  • –clean
  • –log-level

2.8.使用Spec文件29

2.8.1 Spec文件操作

在PyInstaller创建spec文件或在给定脚本之外提供spec文件时,pyinstaller命令会将spec文件作为代码执行。您的绑定应用程序是通过执行spec文件来创建的。下面是一个最小、单文件夹应用程序的spec文件缩略版示例:

block_cipher = None
a = Analysis(['minimal.py'],
             pathex=['/Developer/PItests/minimal'],
             binaries=None,
             datas=None,
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None,
             excludes=None,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
          cipher=block_cipher)
exe = EXE(pyz, ...)
coll = COLLECT(...)

spec文件中的语句创建四个类(Analysis、PYZ、EXE和COLLECT)的实例。

  • 类Analysis的新实例以脚本名称列表作为输入。它分析所有导入和其他依赖项。结果对象(分配给a)包含以类成员命名的依赖项列表:
    - scripts:命名在命令行上的python脚本;
    - pure:脚本所需的纯python模块;
    - pathex:搜索导入的路径列表(类似于使用PYTHONPATH),包括–pathsoption给定的路径。
    - binaries:脚本所需的非python模块,包括–add-binaryop-tion给定的名称;
    - datas:包括–add-data选项给定的名称在内的应用中包含的非二进制文件。
  • 类PYZ的实例是一个.pyz档案(在下面的“检查存档”中描述),其中包含a.pure中的所有Python模块。
  • 从分析脚本和PYZ存档构建的EXE实例。此对象创建可执行文件。
  • COLLECT实例从所有其他部分创建输出文件夹。

在单文件模式下,不存在对COLLECT的调用,并且EXE实例收到所有脚本、模块和二进制文件。

您可以修改spec文件以向Analysis和EXE传递其他值。

第2.8.2节 将文件添加到bundle

要添加文件到bundle,您需要创建一个描述文件的列表,并将其提供给Analysis调用。当打包到单个文件夹(参见“打包到单个文件夹”)时,添加的数据文件将复制到具有可执行文件的文件夹中。当您将打包到单个可执行文件(参见“打包到单个文件”)时,添加文件的副本将压缩到可执行文件中,并在执行之前扩展到_MEIxxxxxx临时文件夹中。这意味着,当应用程序结束时,一个文件应用程序对添加的文件所做的任何更改都将丢失。

在任一情况下,要在运行时查找数据文件,请参阅“运行时信息”。

添加数据文件

您可以通过使用–add-data命令选项或将它们作为列表添加到spec文件来添加数据文件。

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

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

例如,要向单文件夹应用程序的顶级添加单个README文件,您可以修改spec文件如下:

a = Analysis(...
             datas=[ ('src/README.txt','.') ],
             ...
            )

并且命令行等效项(有关特定平台的详细信息,请参见“What To Bundle, Where To Search”):

pyinstaller --add-data 'src/README.txt:.' myscript.py

您已经将datas=参数设置为一个单项列表。该项是一个元组,在该元组的第一个字符串中指定现有文件是src/README.txt。该文件将被查找(相对于spec文件的位置),并复制到打包应用程序的顶层。

字符串可以使用/或\作为路径分隔符字符。您可以使用“glob”缩写来指定输入文件。例如,要包括某个文件夹中的所有.mp3文件:

a = Analysis(...
    datas= [ ('/mygame/sfx/*.mp3','sfx' ) ],
...
)

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

如果在spec文件中创建添加文件的清单,则spec文件更易于阅读:

added_files = [
( 'src/README.txt', '.' ),
( '/mygame/sfx/*.mp3','sfx' )
]
a = Analysis(...
             datas=added_files,
             (continues on next page)
             ...
)

你也可以包含文件夹的全部内容:

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

文件夹/mygame/data将会在bundle中以名为data的文件夹复制出来。

**从模块中使用数据文件 **

如果要添加的数据文件包含在Python模块中,你可以使用pkgutil.get_data()来检索它们。

例如,假设您的应用程序的一部分是一个名为helpmod的模块。 在您的脚本和其规范文件的同一文件夹中,您有以下文件夹设置:

helpmod
__init__.py
helpmod.py
help_data.txt

因为您的脚本包括语句import helpmod,PyInstaller会在您的bundled app中创建这个文件夹结构。 但是,它只会包括.py文件,数据文件help_data.txt不会自动包含。 要使它也被包括,您需要在spec文件中添加一个数据元组:

a = Analysis(...
datas= [ ('helpmod/help_data.txt','helpmod') ],
...
)

当您的脚本执行时,您可以使用其基础文件夹路径找到help_data.txt,如上一节所述。 但是,这个数据文件是模块的一部分,因此您也可以使用标准库函数pkgutil.get_data()来检索其内容:

import pkgutil
help_bin = pkgutil.get_data( 'helpmod','help_data.txt' )

这将返回help_data.txt文件的内容作为二进制字符串。 如果它实际上是字符,则必须对其进行解码:

help_utf = help_bin.decode('UTF-8','ignore')

第2章 内容:32

添加二进制文件

注意:“二进制”文件是指DLL,动态库,共享对象文件等,PyInstaller将进一步搜索这些“二进制”依赖项。 像图像和PDF之类的文件应该放在datas中。

您可以通过使用–add-binary命令选项或将其作为列表添加到spec文件来将二进制文件添加到bundle中。 在spec文件中,制作描述所需文件的元组列表。 将元组列表分配给Analysis的binaries=参数。

添加二进制文件的方法与添加数据文件的方法类似。 如_Adding Binary Files_所述,每个元组都应该有两个值:

  • 第一个字符串指定文件或文件在此系统中的状态。
  • 第二个指定在运行时包含文件的_folder_的名称。

通常,PyInstaller通过分析导入的模块了解.so和.dll库。 有时,不清楚该模块是否被导入; 在这种情况下,您使用–hidden-import命令选项。 但是即使如此,它也可能找不到所有依赖项。

假设您有一个使用Python C-API编写的名为special_ops.so的模块。 您的程序importsspecial_ops,并且PyInstaller找到并includesspecial_ops.so。 但是可能special_ops.solinks到libiodbc.2.dylib。 PyInstaller找不到此依赖项。 您可以通过以下方式将其添加到bundle中:

a = Analysis(...
binaries=[ ('/usr/lib/libiodbc.2.dylib', '.' ) ],
...

或通过命令行(再次,请参阅_What To Bundle,Where To Search_以获取特定平台的详细信息):

pyinstaller --add-binary'/usr/lib/libiodbc.2.dylib:.' myscript.py

如果要将libiodbc.2.dylib存储在bundle内的特定文件夹中,例如vendor,则可以将其指定为元组的第二个元素:

a = Analysis(...
binaries=[ ('/usr/lib/libiodbc.2.dylib', 'vendor' ) ],
...

与数据文件一样,如果您有多个二进制文件要添加,为了提高可读性,请在单独的语句中创建列表并按名称传递列表。

添加文件的高级方法

PyInstaller支持一种更高级(和更复杂)的方法来向bundle中添加文件,这对于特殊情况可能有用。 见 下面的目录(TOC)列表和树类。

2.8.使用spec文件33

2.8.3提供运行时Python选项

您可以向Python解释器传递命令行选项。 解释器接受许多命令行选项,但仅支持以下选项:

  • v每次初始化模块时将消息写入stdout。
  • u表示无缓冲stdio。
  • Wand更改警告行为的选项:W ignore或W once或W error。

要传递其中一个或多个选项,请创建一个元组列表,每个元组对应一个选项,并将列表作为EXE调用的附加参数传递。每个元组都有三个元素:

  • 选项作为字符串,例如vorW ignore。
  • 字符串OPTION

例如,按以下方式修改spec文件:

options = [ ('v',None, 'OPTION'), ('W ignore',None,'OPTION') ]
a = Analysis( ...
)
...
exe = EXE(pyz,
a.scripts,
options, <--- added line
exclude_binaries=...
)

**注意:**无缓冲的stdio模式(选项u)在所有受支持的Python版本上启用了不带缓冲区的stdout和stderr流的二进制层。 无缓冲的文本层需要Python 3.7或更高版本。

2.8.4 macOS Bun的规范文件选项

当您构建一个窗口的macOS应用程序(也就是在macOS上运行,并指定–windowed选项)时,spec文件包含一个额外的语句来创建macOS应用程序包或应用程序文件夹:

app = BUNDLE(exe,
name='myscript.app',
icon=None,
bundle_identifier=None)

BUNDLE的icon参数将指定您使用–icon选项指定的图标文件的路径。bundle_identifier将具有您使用–osx-bundle-identifier选项指定的值。

Info.plist文件是macOS应用程序包的重要组成部分。 (有关Info.plist内容的讨论,请参见苹果捆绑概述。)

PyInstaller创建了一个最小的Info.plist。version选项可用于使用CFBundleShortVersionString Core基础键设置应用程序版本。

您可以通过将info_plist参数传递给BUNDLE调用来添加或覆盖plist中的条目。它的参数应该是一个Python字典,其中包括要包含在Info.plist文件中的键和值。 PyInstaller使用Python标准库模块plistlib从info_plist字典创建Info.plist。 plistlib可以处理嵌套的Python对象(这被转换为嵌套的XML),并将Python数据类型转换为适当的Info.plist XML类型。以下是一个示例:

app = BUNDLE(exe,
name='myscript.app',
icon=None,
bundle_identifier=None,
version='0.0.1',
info_plist={
'NSPrincipalClass':'NSApplication',
'NSAppleScriptEnabled':False,
'CFBundleDocumentTypes': [
{
'CFBundleTypeName':'My File Format',
'CFBundleTypeIconFile':'MyFileIcon.icns',
'LSItemContentTypes': ['com.example.myformat'],
'LSHandlerRank': 'Owner'
}
]
},
)

在上述示例中,键/值’NSPrincipalClass’: 'NSApplication’对于允许macOS使用视网膜分辨率呈现应用程序是必需的。键“NSAppleScriptEnabled”被分配Python布尔值False,将正确输出到Info.plist易于。最后,Key CFBundleDocumentTypes告诉macOS您的应用程序支持的文件类型(请参见Apple文档类型)。

2.8.5 POSIX特定选项

默认情况下,所有所需的系统库都已捆绑。要从捆绑中排除所有或大多数非Python共享系统库,请向Analysis类中添加exclude_system_libraries函数的调用。系统库定义为来自/lib或/usr/lib下的文件,这是在POSIX和相关操作系统上的情况。该函数接受一个可选参数,该参数是文件通配符异常列表,以不排除匹配这些通配符的库文件在bundle中。例如,要排除所有非Python系统库,除了“libexpat”和包含“krb”的任何内容,请使用以下内容:

a = Analysis(...)

a.exclude_system_libraries(list_of_exceptions=['libexpat*', '*krb*'])

2.8.6 Splash Target

要显示引导加载程序的闪屏,请在构建时调用Splash目标。可以在创建规格文件时使用命令行选项–splash IMAGE_FILE添加此类。默认情况下,不启用显示可选文本的选项(text_pos = None)。有关闪屏的更多信息,请参见闪屏屏幕(实验性)部分。SplashTarget如下所示:

a = Analysis(...)

splash = Splash('image.png',
binaries=a.binaries,
datas=a.datas,
(在下一页继续)

该Splash将闪屏所需的资源捆绑到一个文件中,该文件将包含在CArchive中。

Splash有两个输出,一个是它本身,另一个存储在splash.binaries中。为了启用闪屏,请将两者传递给其他构建目标。要在onefile应用程序中使用闪屏,请按照以下示例进行操作:

a = Analysis(...)

splash = Splash(...)

#### onefile
exe = EXE(pyz,
a.scripts,
splash, # <-- both, splash target
splash.binaries, # <-- and splash binaries
...)

要在onedir应用程序中使用闪屏,只需要做出一些小更改即可。由于不需要将闪屏二进制文件包含在可执行文件中,因此必须将splash.binaries属性移动到COLLECT目标中:

a = Analysis(...)

splash = Splash(...)

#### onedir

exe = EXE(pyz, splash, # <-- splash target
a.scripts,
…)
coll = COLLECT(exe,
splash.binaries, # <-- splash binaries
…)


在Windows / macOS图像上支持每像素透明度。这允许非矩形闪屏图像。在Windows上,图像的透明边界是硬切的,这意味着不支持淡化透明值。在Linux上,没有关于非矩形窗口的普遍实现,因此不支持每个像素的透明度图像。

Splash目标可以以各种方式进行配置。 Splash目标的构造函数如下所示:

Splash.init( image_file , binaries , datas , **kwargs )


参数
  • image_file(str) – 图像文件的路径对象。仅支持PNG文件格式。

注意:如果提供了不同的文件格式并且安装了PIL(Pillow),则文件将被自动转换。

注意:Windows系统下:图像或文本中不能使用颜色“magenta”/“#ff00ff”,因为这被启动界面用于指示透明区域。请使用相似的颜色(例如“#ff00fe”)代替。

注意:如果安装了PIL(Pillow),并且图像大于“max_img_size”,则该图像将被调整大小以适合指定的区域。

- binaries(list) – Analysis构建目标发现的扩展模块及其二进制依赖项的TOC列表。这是确定用户程序是否使用_tkinter_所必需的。
- datas(list) – Analysis构建目标发现的数据文件的TOC列表。此TOC包括模块的所有数据文件依赖项。这是用于检查是否可以捆绑所有闪屏屏幕的要求所必需的。
    **关键字参数**
- text_pos– 可选的两个整数元组,表示闪屏屏幕图像上的文本起点。文本的原点是其左下角。在相应的坐标系中,一个单位是图像的一个像素,其原点位于图像的左上角。该参数还充当文本功能的开关。如果省略,则闪屏屏幕上不会显示任何文本。此文本将用于在单个文件模式下显示文本进度。
- text_size– 字体的期望大小。如果大小参数是正数,则将其解释为点大小。如果大小为负数,则将其绝对值解释为像素大小。默认值:12。
- text_font– 文本字体的可选名称。此字体必须安装在用户系统上,否则使用系统默认字体。如果省略此参数,则也使用默认字体。
- text_color– 文本的可选颜色。支持HTML颜色代码(“#40e0d0”)和颜色名称(“turquoise”)。默认值:“black”(Windows系统下,颜色“magenta”/“#ff00ff”用于表示透明度,不应使用)。
- text_default– 开始提取之前将显示的默认文本。默认值:“Initializing”。
- full_tk– 默认情况下,Splash仅捆绑了闪屏屏幕所需的文件(一些tk组件)。此选项启用添加完整的tk并将其设置为要求,这意味着在启动闪屏屏幕之前将解压缩所有tk文件。这在闪屏屏幕脚本开发过程中非常有用。默认值:False。
- minify_script– 闪屏屏幕是通过执行一个Tcl/Tk脚本创建的。此选项启用脚本的最小化,即从脚本中删除所有非必要部分。默认情况下为True。
- rundir– Tcl/tk在运行时将被提取的文件夹名称。在应用程序中不应有匹配的文件夹,以避免冲突。默认值:“__splash”。
- name– .res文件的可选替代文件名。如果未指定,则会生成一个名称。
- script_name– 将生成的Tcl脚本的可选替代文件名。如果未指定,则会生成一个名称。

**2.8. 使用Spec文件**

- max_img_size– 闪屏屏幕图像的最大尺寸。如果提供的图像超出此限制,则会调整大小以适合最大宽度(保持原始长宽比)。可以通过将其设置为None来禁用此选项。默认值:(760,480)。
- always_on_top– 强制闪屏屏幕始终置于其他窗口之上。如果禁用,其他窗口(例如来自其他应用程序的窗口)可以通过用户将它们置于前面来覆盖闪屏屏幕。这对于启动时间长的固定应用程序可能很有用。默认值:True。

**2.8.7 多包捆绑**

一些产品由多个不同的应用程序组成,每个应用程序可能依赖于一组第三方库或以其他方式共享代码。当打包这样的产品时,将每个应用程序隔离处理,将其与所有依赖项捆绑在一起将导致存储重复的代码和库。

您可以使用多包装功能捆绑一组可执行应用程序,以便它们共享库的单个副本。您可以使用单文件或单文件夹应用程序执行此操作。

**使用单文件应用程序进行多包装**

每个依赖项(例如DLL)仅在其中一个应用程序的包中打包。其他集合中依赖此DLL的任何其他应用程序都具有对它的“外部引用”,告诉它们从包含它的应用程序的可执行文件中提取该依赖项。

这样做可节省磁盘空间,因为每个依赖项仅存储一次。但是,在启动应用程序时,跟随外部引用需要额外的时间。集合中的所有应用程序,除一个之外,都将具有稍慢的启动时间。

二进制文件之间的外部引用包括硬编码的路径到输出目录,不能重排。当安装应用程序时,必须将所有相关应用程序放置在同一目录中。

要构建这样的应用程序集合,必须编写自定义spec文件,其中包含对MERGE函数的调用。此函数接受已分析脚本的列表,查找它们的公共依赖项,并修改分析以最小化存储成本。

参数列表中的分析对象的顺序很重要。MERGE函数将每个依赖项打包到从左到右的第一个需要该依赖项的脚本中。在列表中后来的需要相同文件的脚本将具有对列表中前面脚本的外部引用。您可以对这些脚本进行排序,将最常使用的脚本放在列表的前面。

用于多包装捆绑的自定义spec文件包含对MERGE函数的一次调用:

MERGE(*args)

MERGE在分析阶段之后并在EXE之前使用。其变量长度的参数列表由一个元组列表组成,每个元组具有三个元素:

- 第一个元素是Analysis对象,是类Analysis的一个实例,应用于一个应用程序。
- 第二个元素是分析应用程序的脚本名称(不包括“.py”扩展名)。
- 第三个元素是可执行文件的名称(通常与脚本相同)。

MERGE检查Analysis对象以了解每个脚本的依赖项。它修改这些对象以避免库和模块的重复。结果生成的包将是连接的。

**示例 MERGE spec 文件**

构建多包捆绑包的规范文件的一种方法是首先为包中每个应用程序构建一个规范文件。假设您有一个由三个应用程序组成的产品,分别命名为(因为我们没有想像力)foo,bar和zap:

pyi-makespec 选项适当… foo.py
pyi-makespec 选项适当… bar.py
pyi-makespec 选项适当… zap.py


检查警告并单独测试每个应用。 处理任何隐藏导入和其他问题。 当所有三个应用程序正常工作时,将三个文件foo.spec、bar.spec和zap.spec的语句组合如下:

首先从每个规范中复制 Analysis 语句,将其更改以为每个 Analysis 对象产生唯一的名称:

foo_a = Analysis(['foo.py'],
pathex=['/the/path/to/foo'],
hiddenimports=[],
hookspath=None)

bar_a = Analysis(['bar.py'], etc., etc...

zap_a = Analysis(['zap.py'], etc., etc...

现在调用MERGE方法以处理三个Analysis对象:

MERGE((foo_a,'foo','foo'),(bar_a,'bar','bar'),(zap_a,'zap','zap'))

将修改Analysis对象foo_a、bar_a和zap_a,使后两个对象引用第一个对象以实现共同依赖性。

接下来,您可以从原始的三个规范文件中复制PYZ,EXE和COLLECT语句,并在原始规范文件使用a的位置替换Analysis对象的唯一名称。修改EXE语句以传递Analysis.dependencies,以及传递给原始EXE语句的所有其他参数。例如:

foo_pyz = PYZ(foo_a.pure)
foo_exe = EXE(foo_pyz, foo_a.dependencies, foo_a.scripts, ... etc.

bar_pyz = PYZ(bar_a.pure)
bar_exe = EXE(bar_pyz, bar_a.dependencies, bar_a.scripts, ... etc.

将组合的规范文件保存为foobarzap.spec然后构建它:

pyinstaller foobarzap.spec

dist文件夹中的输出将是所有三个应用程序,但是appsdist/bar和dist/zap会引用dist/foo的共享依赖项。

请记住,规范文件是可执行的Python文件。您可以在创建 Analysis 对象并执行 PYZ、EXE 和 COLLECT 语句时使用所有 Python 工具 (与sys和io的成员for和with)。您还可以了解并使用下面描述的_目录(TOC)列表和Tree Class 。_

**2.8 用于规范文件的 Notable 特性**

**2.8.8 规范文件中可用的全局变量**

规范文件在执行时可以访问一组有限的全局名称。 这些名称包括由 PyInstaller 定义的类: Analysis,BUNDLE,COLLECT,EXE,MERGE,PYZ,TOC,Tree 和 Splash,这些类在前面的部分中进行了讨论。

其他全局变量包含有关构建环境的信息:

DISTPATH应用程序将存储的rel相对路径。 默认路径相对于当前目录。 如果使用--distpath选项,DISTPATH包含该值。

HOMEPATH PyInstaller 分发的绝对路径,通常在当前 Python site-packages 文件夹中。

SPEC给定给pyinstaller命令的完整规范文件参数,例如myscript.spec或source/myscript.spec。

SPECPATH按os.path.split()返回的SPEC值的路径前缀。

specnm 规范文件的名称,例如myscript。

workpath 到 build 目录的路径。 默认路径相对于当前目录。 如果使用workpath=选项,workpath包含该值。

WARNFILE建议的目录中警告文件的完整路径,例如build/warn-myscript.txt。

### 2.9 关于特定功能的注释

**2.9.1 Ctypes 依赖关系**

Ctypes 是 Python 的外部函数库,允许调用共享库中存在的函数。这些库未作为 Python 包导入,因为它们不是通过 Python 导入捕获的。其中传递的路径实际上传递给 ctypes;这导致 PyInstaller 的导入检测机器无法检测到这些库,从而无法构建独立的 PyInstaller 可执行文件:

from ctypes import *
### 2.10 这将在 PyInstaller 检测机器下不被检测到,
#因为它不是直接导入的。

handle = CDLL(“/usr/lib/library.so”)
handle.function_call()

**PyInstaller 中的解决方案**

PyInstaller 包含 Ctypes 依赖项的实用的实现:它将搜索 ctypes 的简单标准用法并自动跟踪和捆绑引用的库。 将正确检测以下用法:

CDLL(“library.so”)
WinDLL(“library.so”)
ctypes.DLL(“library.so”)
cdll.library# 仅在 Windows 下有效-是 ctypes 的限制,而不是 PyInstaller 的
windll.library# 仅在 Windows 下有效-是 ctypes 的限制,而不是 PyInstaller 的
cdll.LoadLibrary(“library.so”)
windll.LoadLibrary(“library.so”)

更详细地说,以下限制适用:

- **仅处理通过裸文件名(例如无前导路径)引用的库**;处理绝对路径是不可能的,因为必须对字节码进行修改(请记住,当运行 frozen 时,ctypes 会继续在该绝对位置上搜索库,而无法保证在主机系统上存在该位置),而处理相对路径则需要在冻结的可执行文件中重新创建导向库的相同目录层次结构,另外还需要跟踪当前工作目录是什么;
- **仅会检测由字符串表示的库路径并包含在最终的可执行文件中**:PyInstaller 的导入检测是通过检查原始 Python 字节码来完成的,而由于可以通过字符串将库路径传递给 ctypes(可以由代码中的文字表示,也可以由变量、任意复杂函数的返回值等表示),因此不可能合理地检测**所有** ctypes 依赖项;
- 仅会处理在 ctypes 调用的相同上下文中引用的库。

我们认为这足以涵盖大多数 ctypes 用法,并且在您的代码中需要进行很少或没有修改。

如果 PyInstaller 未检测到某个库,则可以通过将相应信息传递给--add-binary 选项或 _将其列出在.spec 文件中_将其添加到捆绑包中。不能保证冻结的应用程序将能够在运行时拾取库,因为这取决于详细实现。 

**警告**

在“分析时间”,`ctypes`检测系统基于`ctypes.util.find_library()`。这意味着您必须确保,在执行分析并运行冻结程序时,`find_library()`用于搜索库的所有环境值都与运行非冻结程序时的环境值相一致。例如,使用`LD_LIBRARY_PATH`或`DYLD_LIBRARY_PATH`来扩大`find_library()`的范围。

**2.9.2 SWIG支持**

PyInstaller尝试检测由SWIG创建的二进制模块。此检测需要:

- 在你的应用程序中的任何模块中导入Python包装模块。
- 包装模块必须作为源代码可用,并且第一行必须包含SWIG自动生成的文本。
- C模块必须与包装模块具有相同的名称,前缀为下划线(_)。 (这已经是SWIG限制了。)
- C模块必须坐在包装模块旁边(因此相对导入将有效)。

此外,由于SWIG包装器的实现方式,也适用一些限制:

- C模块将变成全局模块。因此,您不能使用两个具有相同基本名称的SWIG模块(例如pkg1._cmod和pkg2._cmod),因为一个将覆盖另一个。

**2.9.3 Cython支持**

PyInstaller可以跟踪引用Cython C对象模块并打包它们的import语句,就像对于任何其他用C实现的模块一样。

但是-就像对于任何其他用C实现的模块一样-PyInstaller无法确定Cython C对象模块是否在导入某些Python模块。这些通常会显示在回溯中(注意.pyx扩展名):

回溯(最近的调用最先):

[…]
File “myapp\cython_module.pyx”, line 3, in init myapp.cython_module
ModuleNotFoundError: No module named ‘csv’

**2.9.关于特定功能的注意事项41**

因此,如果您正在使用导入Python模块的Cython C对象模块,则必须将其列为--hidden-import。

**2.9.4 macOS多架构支持**

随着苹果Silicon M1的引入,现在有几个针对Python可用的架构选项:

- 使用细二进制文件的单架构x86_64:旧版_python.org_构建、在M1 Mac上本地运行的Homebrew python或在rosetta2下运行
- 使用细二进制文件的单架构arm64:在M1 macs上本地运行的Homebrew python
- 包含x86_64和arm64片段的多架构universal2瘦二进制文件:最近的universal2_python.org_构建

PyInstaller旨在支持源于上述选项的所有可能的组合:

- 使用相应单架构Python创建的单架构应用程序
- 使用universal2python创建的universal2应用程序
- 使用universal2python创建的单架构应用程序(即将universal2fat二进制文件缩减为x86_64或arm64细二进制文件)

**默认情况下,PyInstaller针对当前正在运行的体系结构并生成单架构二进制文件**(在Intel Mac上运行时为x86_64或在M1 Mac上运行rosetta2时为x86_64,或在M1 Mac上运行时为arm64)。这是因为即使在universal2python环境下,一些软件包可能最终只提供单架构二进制文件,从而使创建功能性universal2frozen应用程序变得不可能。

因此,必须明确启用替代选项,例如创建冻结应用程式的universal2版本,或使用universal2环境创建非本机单架构版本。可以通过在.spec文件中通过EXE()的target_arch参数或通过--target-arch开关在命令行中指定目标架构来完成。有效值为x86_64、arm64和universal2。

**二进制收集期间的架构验证**

为了防止二进制文件中缺少或不匹配的架构片段引起的运行时问题,二进制文件收集过程执行严格的架构验证。它检查收集的二进制文件是否包含所需的架构片段,如果没有,则构建过程将中止并出现有关问题二进制文件的错误消息。

在这种情况下,除非手动解决缺少架构片段的问题(例如,通过下载与缺少的架构相对应的wheel,并使用lipoutility将有问题的二进制文件粘合在一起),否则将无法为所选目标架构创建冻结应用程序。

从版本4.10开始:在早期的PyInstaller版本中,架构验证是在所有收集的二进制文件(例如python扩展模块和由这些扩展引用的共享库)上执行的。从PyInstaller4.10开始,架构验证仅限于python扩展模块。

多架构universal2扩展中的单独架构片段可以链接到(由)universal2共享库的(片段)中,也可以链接到不同的单架构细共享库中。后一种情况使得无法可靠地验证收集的共享库的架构相对于目标应用程序架构。

但是,扩展模块确实需要与目标应用程序架构完全兼容。因此,它们的持续验证应该足以检测尝试使用不兼容的单架构Python软件包的企图* ^ 0。

(^0)尽管实际上没有什么阻止一个软件包有不同的、具有特定于架构的扩展模块......

**42第2章 内容:删除单架构目标的厚二进制文件片段**

当目标一个架构时,构建过程从任何收集的fat二进制文件中提取相应的架构片段,包括引导加载程序。这将导致即使在构建universal2python环境中也会产生完全细的构建。

**2.9.5 macOS二进制代码签名**

随着Apple Silicon M1体系结构的引入,即使是无实际代码签名标识,macOS也引入了强制性的代码签名。这意味着收集的二进制文件中的arm64架构片段(但可能也是universal2二进制文件中的x86_64片段)始终带有签名。

PyInstaller处理二进制文件的处理(例如,在二进制文件头中重写库路径)会使它们的签名无效。因此,必须重新生成签名,否则操作系统将拒绝加载二进制文件。

**默认情况下,PyInstaller会对所有收集的二进制文件和生成的可执行文件进行ad-hoc(重新)签名。**可以使用实际的代码签名标识,而不是adhoc签名。要这样做,可以通过spec文件的codesign_identity参数或通过--codesign_identity开关在命令行中指定身份验证。

能够提供codesign标识符使用户能够确保所有在onefile或onedir build中收集的二进制文件都使用其标识符进行了签名。这很有用,因为对于onefile构建,无法在后处理步骤中执行嵌入二进制文件的签名。

**注意:** 当指定 codesign 身份时,PyInstaller 也通过 --options=runtime 将 _硬化运行时_ 打开给 codesign 命令。这要求 codesign 身份必须是有效的由 Apple 发布的代码签名证书,而自签名证书将无法使用。

尝试使用自签名证书作为codesign身份将导致共享库加载失败,并报告以下原因:

[libname]:代码签名([libname])无法在使用库验证的进程中使用:映射的文件没有 Team ID,也不是平台二进制文件(使用自定义身份或adhoc签名


此外,在签名收集的二进制文件和可执行文件时,还可以指定要使用的授权文件。这可以通过在.spec文件中使用 entitlements_file=argument toEXE() 或通过命令行使用 --osx-entitlements-file 开关来完成。

**程序包**

PyInstaller 还自动尝试使用 _adhoc_ 身份或实际的签名身份来签名 _.app 包_,如果通过 --codesign-identity 开关提供。除传递与签名收集的二进制文件相同的选项(identity、hardened runtime、entitlement)、通过通过向 codesign 实用程序传递 --deep 选项启用深层签名。

如果无论何种原因,该包的签名失败,从 codesign 实用程序收到的错误消息将打印到控制台,并提示需要手动干预和手动签名包的警告。

**2.9. 特定功能的注意事项43**


**2.9.6 macOS 应用程序包中的事件转发和参数模拟**

macOS 应用程序包的用户交互是通过所谓的 Apple 事件进行的。当用户双击应用程序图标时,应用程序启动并接收到一个“开放应用程序”('oapp')事件。将文档拖动到应用程序图标上或尝试打开应用程序注册的文件会生成“打开文档”('odoc')事件。类似地,使用应用程序注册模式启动 URL 会生成启动 / 获取 URL ('GURL') 事件。通常,长时间运行的 UI 应用程序在其运行时安装Carbon或Cocoa事件处理程序(或由更高级别的 UI 工具包提供的等效处理程序)来处理这些请求。

PyInstaller 为 macOS 事件处理提供了两个方面的支持:自动事件转发,它使冻结的应用程序能够在onefile模式下接收事件,以及可选的_argv模拟_,用于将初始打开事件转换为sys.argv参数。这两个方面仅适用于应用程序包(即,windowedbootloader 变体),而不适用于 POSIX(命令行)冻结应用程序。

在版本5.0中更改:在早期的 PyInstaller 版本中,argv 模拟总是在 onefile 模式下启用,并且在 onedir 模式下不可用。随着 PyInstaller 5.0,必须显式选择 argv 模拟,并且在 onefile 和 onedir 模式下都可用。

**事件转发**

在 PyInstaller onedir 包中,应用程序作为单个进程运行,因此像其他 macOS 应用程序一样正常接收 Apple 事件。

在onefile包中,应用程序有一个父启动器进程和一个子进程;由用户生成的打开文档请求由父进程接收,并自动转发到子进程,其中运行冻结的 Python 代码。

对以下类型的 Apple 事件实现了事件转发:

- kAEOpenDocuments('odoc'):打开文档请求
- kAEGetURL('GURL'):打开 / 启动 URL 请求
- kAEReopenApplication('rapp'):重新打开应用程序
- kAEActivate('actv'):激活应用程序(置于前端)

**可选参数模拟**

PyInstaller 实现了一个名为 argv 模拟的可选功能,可通过在 _.spec 文件_ 中使用argv_emulation=argument toEXE()来切换,或通过命令行使用--argv-emulation标志启用。

如果启用,引导加载程序执行初始的 Apple 事件处理,以在应用程序的启动序列期间拦截事件,并将通过打开文档 / URL('odoc' 和 'GURL')事件接收到的文件路径或 URL 追加到 sys.argv 中,就像它们是通过命令行接收到的一样。

此功能适用于不实现事件处理但仍希望处理初始打开文档请求的简单应用程序。仅适用于初始打开事件;在启动冻结的 Python 代码后发生的事件通过事件队列分派(在 onedir 模式下直接分派,在 onefile 模式下转发到子进程。),因此需要通过事件处理程序处理。

**注意:** 此功能不适合需要在其生命周期中处理多个打开请求的长时间运行的应用程序。这种应用程序需要适当的事件处理,因此不受由 _argv 模拟_ 处理初始事件影响的影响。

**44 第 2 章 内容:**


警告:引导程序在 onedirmode 中执行的初始事件处理可能会干扰冻结 Python 应用程序使用的 UI 工具包,例如 Tcl/Tk 或 viatkinter 模块。症状可能从窗口未被置于前端的应用程序启动到应用程序崩溃和分段错误。虽然 PyInstaller 尝试在其端缓解问题,但我们建议不要结合使用 UI 工具包使用 argv 模拟。


**实际示例**

本节提供一些实际示例,展示如何通过在简单的一次性程序中使用 _argv 模拟_ 或通过在 GUI 应用程序中安装事件处理程序来处理 macOS 应用程序包中的文件和 URL 打开事件。

**注册支持的文件类型和自定义 URL 模式**

为了使 macOS 应用程序包能够处理对文件和自定义 URL 模式的打开操作,需要向操作系统通知应用程序支持哪些文件类型和哪些 URL 模式。这是通过包的 Info.plist 文件完成的,通过CFBundleDocumentTypes 和 CFBundleURLTypes 条目完成:

[...]

2.9. Notes about specific Features 45

(continued from previous page)

在上面的示例中,应用程序声明自己为.mcf文件和以my-url://开头的URL的查看器。

PyInstaller会自动生成一个Info.plist文件用于您的应用程序包。要将上面显示的条目包含在其中,请将info_plist参数添加到.spec文件中的BUNDLE()指令中,并将其内容设置如下:

app = BUNDLE(

[…]

info_plist={
‘CFBundleURLTypes’: [{
‘CFBundleURLName’:‘MyCustomUrlSchema’,
‘CFBundleTypeRole’:‘Viewer’,
‘CFBundleURLSchemes’: [‘my-url’, ],
}],
‘CFBundleDocumentTypes’: [{
‘CFBundleTypeName’:‘MyCustomFileType’,
‘CFBundleTypeExtensions’: [‘mcf’, ],
‘CFBundleTypeRole’: “Viewer”,
}],
}
)

使用argv模拟的打开事件处理

考虑以下Python脚本,最初是作为从终端调用的命令行实用程序而创建的:

python3 img2gray.py image1.png image2.png …

该脚本对传递的每个图像进行处理,将其转换为灰度并将其保存在原始文件旁边,并在文件名后面添加_gray:

img2gray.py

import sys
import os

import PIL.Image

if len(sys.argv) < 2:
print(f"Usage:{sys.argv[0]} [filenames…]")
sys.exit(1)

Convert all given files

forinput_filenamein sys.argv[1:]:
filename, ext = os.path.splitext(input_filename)
output_filename = filename + ‘-gray’+ ext

img = PIL.Image.open(input_filename)
(continues on next page)

46 Chapter 2. Contents:

(continued from previous page)
img_g = img.convert('L')
img_g.save(output_filename)

如果生成应用程序包(而不是命令行POSIX应用程序),与该包的图标拖放图像文件或使用“打开方式…”操作相比,用户交互的最可能方式将是从图像文件的上下文菜单中生成打开文件事件。此类交互将生成打开文件事件,并且通常需要您的应用程序代码实现事件处理。

在PyInstaller中启用argv模拟可使其引导加载程序在应用程序启动期间处理事件,并通过任何文件路径或URL扩展sys.argv,这些路径或URL可能已通过打开文件或URL请求接收到。这使得您的应用程序可以处理接收到的文件名,就像它们是通过命令行传递的一样,而无需对代码本身进行任何修改。

以下的.spec文件提供了一个完整的例子,用于一个one-directory应用程序包,允许转换.png和.jpg图像:

img2gray.spec

a = Analysis([‘img2gray.py’], )

pyz = PYZ(a.pure, a.zipped_data)

exe = EXE(
pyz,
a.scripts,
exclude_binaries=True,
name=‘img2gray’,
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
console=False,
argv_emulation=True, # enable argv emulation
)

coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=False,
upx_exclude=[],
name=‘img2gray’
)

app = BUNDLE(
coll,
name=‘img2gray.app’,

将.png和.jpg注册为支持的文件类型

info_plist={
‘CFBundleDocumentTypes’: [{
‘CFBundleTypeName’: “可转换图片类型”,
‘CFBundleTypeExtensions’: [
(续下页)
‘png’, ‘jpg’,
],
‘CFBundleTypeRole’: “浏览器”,
}],
}
)

现在用户可以将图像文件拖到生成的img2gray应用程序包图标上,或在图像文件的上下文菜单中选择Open with...中的img2gray。

注意:_argv模拟仅处理初始打开事件,在启动冻结的Python代码之前接收到该事件。如果您希望在应用程序仍在运行时处理后续打开请求,则需要在Python代码中实现适当的事件处理。

在基于tkinter的GUI应用程序中处理打开事件
tkinter使用的Tcl/Tk框架允许应用程序通过注册macOS特定的命令为预定义的Apple事件类型提供事件处理程序。

打开文件事件的处理程序可以通过```:: tk :: mac :: OpenDocument```命令进行注册,而打开URL事件的处理程序可以通过```:: tk :: mac :: LaunchURL```命令进行注册。后者从Tcl/Tk 8.6.10开始†^0可用。

以下应用程序说明了使用tkinter的事件处理程序,通过将所有接收到的打开文件/URL事件记录到可滚动的文本小部件中:

```# eventlogger_tk.py
import sys

import tkinter
import tkinter.scrolledtext

class Application:
    def __init__(self):
    	# 创建UI
        self.window = tkinter.Tk()
        self.window.geometry('800x600')
        self.window.title("基于Tk的事件记录器")

        self.text_view = tkinter.scrolledtext.ScrolledText()
        self.text_view.pack(fill=tkinter.BOTH, expand=1)
        self.text_view.configure(state='disabled')
        
        # 注册事件处理程序
        # 请参见https://tcl.tk/man/tcl/TkCmd/tk_mac.html了解
        # macOS特定命令的列表
        self.window.createcommand(":: tk :: mac :: OpenDocument", self.open_document_handler)
        self.window.createcommand(":: tk :: mac :: LaunchURL", self.open_url_handler) #␣ works with Tcl/Tk >= 8.6.10
写作时,python.org builds使用Tcl/Tk 8.6.5,除了Python 3.9.x _macOS 64位universal2 installer_ builds使用
Tcl/Tk 8.6.10。Homebrew Python requirestkinter显式安装为python-tk,并使用最新版本的Tcl/Tk 8.6.11。注册
:: tk :: mac :: LaunchURLcommand与早于8.6.10的Tcl/Tk版本基本无操作。

第48章。 内容:


        
    def append_message(self, msg):
        """将消息附加到文本视图。"""
        self.text_view.configure(state='normal')
        self.text_view.insert('end', msg + '\n')
        self.text_view.configure(state='disabled')
        
    def run(self):
        """运行主循环。"""
        app.append_message("Application started!")
        app.append_message(f"Args:{sys.argv[1:]}")
        self.window.mainloop()
        
    # 事件处理程序
    def open_document_handler(self, *args):
        app.append_message(f"打开文档事件:{args}")
        
    def open_url_handler(self, *args):
        app.append_message(f"打开URL事件:{args}")

if __name__ == '__main__':
    app = Application()
    app.run()

对应的_.spec文件_,构建了一个onedir应用程序包,其中包含自定义文件关联(.pyi_tk)和自定义URL模式(pyi-tk://):

a = Analysis(['eventlogger_tk.py'])

pyz = PYZ(a.pure, a.zipped_data)

exe = EXE(
pyz,
a.scripts,
exclude_binaries=True,
name='eventlogger_tk',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
console=False,
argv_emulation=False, # 不必要,因为应用程序处理事件
)

coll = COLLECT(
exe,
a.binaries,
a.zipfiles,

2.9. 特定功能的注释 49


(接上一页)
a.datas,
strip=False,
upx=False,
name='eventlogger_tk'
)

应用程序运行后,它将记录所有接收的打开文件和打开URL请求。这些请求是通过使用UI打开带有.pyi_tk扩展名的文件或从终端使用open命令生成的:

$ touch file1.pyi_tk file2.pyi_tk file3.pyi_tk file4.pyi_tk

$ open file1.pyi_tk
$ open file2.pyi_tk

$ open pyi-tk://test1
$ open pyi-tk://test2

$ open file3.pyi_tk file4.pyi_tk

**在基于Qt的GUI应用程序中处理打开事件**

在基于Qt的应用程序中,安装应用范围的事件过滤器以处理打开文件和打开URL请求的QFileOpenEvent。

此事件抽象了打开文件和打开URL请求,其中文件打开请求具有file://URL模式。事件包含单个文件名或URL,因此包含多个目标的打开请求会生成相应数量的QFileOpenEvent事件。

以下是一个示例应用程序及其对应的_.spec文件_:

# eventlogger_qt.py
import sys
(接上一页)

import signal

from PySide2 import QtCore, QtWidgets

class Application(QtWidgets.QApplication):
"""
带有针对macOS打开文档/URL事件的额外处理的QtWidgets.QApplication。
"""
openFileRequest = QtCore.Signal(QtCore.QUrl, name='openFileRequest')
defevent(self, event):
if event.type() == QtCore.QEvent.FileOpen:
self.openFileRequest.emit(event.url())
return True
returnsuper().event(event)
class MainWindow(QtWidgets.QMainWindow):
"""
主窗口。
"""
def__init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.resize(800, 600)
self.setWindowTitle("基于Qt的事件记录器")
# 构造UI界面
self.scroll_area = QtWidgets.QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.setCentralWidget(self.scroll_area)
self.text_edit = QtWidgets.QTextEdit()
self.scroll_area.setWidget(self.text_edit)
self.text_edit.setReadOnly(True)
def append_message(self, msg):
"""
在文本视图中追加消息。
"""
self.text_edit.append(msg)
def handle_open_file_request(self, url):
self.append_message(f"打开请求:{url.toString()}")
(续下一页)

2.9. 特定功能说明 51

(接上页)
if __name__ =='__main__':
# 使Ctrl+C正常工作
signal.signal(signal.SIGINT, signal.SIG_DFL)

app = Application(list(sys.argv))
window = MainWindow()
window.show()

window.append_message("应用程序已启动!")
window.append_message(f"参数:{sys.argv[1:]}")

app.openFileRequest.connect(window.handle_open_file_request)

app.exec_()
eventlogger_qt.spec
a = Analysis(['eventlogger_qt.py'])

pyz = PYZ(a.pure, a.zipped_data)

exe = EXE(
pyz,
a.scripts,
exclude_binaries=True,
name='eventlogger_qt',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
console=False,
argv_emulation=False, # 因为应用程序处理事件,所以不需要
)

coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=False,
name='eventlogger_qt'
)

app = BUNDLE(
coll,
name='eventlogger_qt.app',
# 注册自定义协议处理程序和自定义文件扩展名
info_plist={
'CFBundleURLTypes': [{
'CFBundleURLName':'MyCustomUrlSchemaQt',
'CFBundleTypeRole':'Viewer',
'CFBundleURLSchemes': ['pyi-qt'],
}],
'CFBundleDocumentTypes': [{
'CFBundleTypeName':'MyCustomFileTypeQt',
'CFBundleTypeExtensions': [
'pyi_qt',
],
'CFBundleTypeRole': "Viewer",
}],
}
)

该应用程序的行为方式与Tkinter为基础的同类应用程序相同,只是相关的文件扩展名和URL模式已被调整,以防止两个示例应用程序之间的干扰。

打开事件

本节介绍了应用程序收到的初始打开事件的行为,这是由冻结的Python代码(或其使用的UI工具包)观察到的。

当正常打开应用程序时,这是通过打开应用程序(‘oapp’)事件完成的,它是应用程序接收到的第一个事件。如果以响应于打开文档或打开URL请求(即在进行请求时应用程序尚未运行)打开应用程序,则首先接收到的事件是“odoc”或“GURL”。

在PyInstaller-frozenonefilebundles中,子进程始终以“oapp”事件开始,无论如何启动应用程序。这是因为子进程始终是以“正常方式”启动的,而实际的打开事件是由父进程接收的;如果父进程以“odoc”或“GURL”事件打开,则事件将被转发到子进程或转换为传递给子进程的sys.argv,这取决于是否启用了_argv模拟。

因此,在单个文件模式下,“argv仿真”对于初始打开事件的直接影响是没有的(由冻结的python代码控制),初始打开事件始终为“oapp”。

在单个目录束中,应用程序由单个进程接收事件。如果没有“argv仿真”,初始打开事件(由冻结的python代码控制)可能是“oapp”、“odoc”或“GURL”,具体取决于应用程序的启动方式。

但是,在单个目录束中启用“argv仿真”时,它对初始事件的处理会使事件队列为空。缺少初始打开事件似乎会在Tcl/Tk 8.6.11和Homebrew Python 3.9.6(#5581)中导致分段错误。作为解决方法,引导加载程序尝试向自身提交“oapp”事件,这样当冻结的python代码检查事件队列时,它就会发现初始打开事件(即“oapp”)。这些“argv仿真”对UI工具包的潜在副作用是我们建议不要将它们结合使用的原因。

2.9.7 控制台Windows应用程序和单个文件应用程序中的信号处理

清除

在Windows中,控制台应用程序中的信号处理与基于POSIX的操作系统(如Linux和macOS)不同。虽然由异常情况生成的信号(例如由C代码调用Abort引起的异常终止的信号,SIGFPE(浮点错误)和SIGSEGV(非法存储器访问)),可以使用通过signal函数安装的处理程序处理,但对于与程序中断和终止相关联的信号,则不是这种情况。

具体来说,通过按“Ctrl + C”中断启用控制台的程序不会生成SIGINT信号,而是生成一种特殊的“控制台控制信号”,称为CTRL_C_EVENT,其可以通过通过SetConsoleCtrlHandler win32 API函数安装的处理程序来处理。

同样地,如MSDN文档中关于信号的注释所示,在Windows下,不会生成SIGTERM信号。相反,存在几种控制台控制信号:

  • CTRL_C_EVENT:通过“Ctrl + C”键组合中断
  • CTRL_BREAK_EVENT:通过“Ctrl + Break”键组合中断
  • CTRL_CLOSE_EVENT:关闭父控制台窗口
  • CTRL_LOGOFF_EVENT:用户注销
  • CTRL_SHUTDOWN_EVENT:系统关闭

当生成控制台控制信号时,由SetConsoleCtrlHandler安装的处理程序(如果有)在程序进程中由操作系统产生的单独线程中执行。换句话说,处理程序函数与主程序线程并行执行,这是必要的,因为后者可能正在等待阻塞操作或执行无限循环。

如此提醒,在接收到CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT或CTRL_SHUTDOWN_EVENT时,处理程序函数可以执行任何必要的清除,并且:

  • 调用ExitProcess来终止该进程。
  • 返回FALSE(0)。其他注册的处理程序被调用,如果没有一个返回TRUE,则默认处理程序通过调用ExitProcess来终止进程。
  • 返回TRUE(非零)。系统立即终止进程,而不调用任何其他注册的处理程序。

换句话说,所有选项都会最终终止程序。

另一方面,默认的CTRL_C_EVENT和CTRL_BREAK_EVENT处理程序也会终止进程,但是可以通过在用户安装的处理程序中返回TRUE来修改此行为,以抑制默认处理程序。

控制台控制信号的另一个重要方面是,处理CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT和CTRL_SHUTDOWN_EVENT是受系统强制的超时限制的(例如,对于CTRL_CLOSE_EVENT是5秒)。如果进程未在超时限制内退出,则操作系统本身会无条件终止该进程。

上述实际上意味着一旦程序接收到这样的控制信号,其终止是不可避免的(即无法忽略该信号)。最好的办法是将终止延迟到执行任何必要的清除,但即使这样,也必须在系统规定的时间限制内完成清除。

在Python应用程序中处理控制台控制信号的示例

以下代码演示了优雅控制台应用程序关闭的基本实现。如果应用程序由用户按“Ctrl + C”或“Ctrl + Break”中断,或由于用户关闭控制台窗口而关闭,则应用程序的状态将存储到文件中,以便在后续运行中可以恢复。

console_counter.py
import sys
import time
import pathlib

import win32api # pip install pywin32
(^1)较高级的编程语言(如Python)可能会模拟标准信号;但底层机制仍涉及本节中讨论的控制台控制信号。
(^2)注意,此时程序本质上是一个多线程程序,因此可能适用于通常的多线程注意事项。

#安装控制台处理程序

win32api.SetConsoleCtrlHandler(console_handler, 1)

#恢复状态,如果有

state_file = pathlib.Path.home() / 'counter_state.txt'
if state_file.is_file():
    print(f"从{state_file}还原状态...", file = sys.stderr)
    try:
        with open(state_file,'r')as fp:
            counter = int(fp.readline())
    except Exception:
        print("无法从文件中恢复状态!", file = sys.stderr)
        counter = 0
else:
    print("不存在状态文件!", file = sys.stderr)
    counter = 0

print(f"初始计数器值:{counter}", file = sys.stderr)

#主循环
while keep_running:
    print(f"计数器值:{counter}")
    counter += 1
    time.sleep(1)

#清理
print(f"将状态存储到{state_file}中...", file = sys.stderr)
try:
    with open(state_file,'w') as fp:
        print(f"{counter}", file = fp)
except Exception:
    print(f"无法将状态存储到{state_file}中!", file = sys.stderr)

print("再见!")
time.sleep(1)  # 延迟1秒后退出

上面的代码中的控制台控制信号处理程序处理所有控制台信号。这包括_Ctrl+C_事件,否则将在程序的主线程中生成aKeyboardInterruptexception
通过用全局布尔变量信号循环通知退出,处理程序会睡眠“forever”。此方法有效,因为处理程序在单独的线程中执行,而该线程在进程结束时终止,无论是由于主
线程到达其末尾,还是由于操作系统终止进程。

当作为未冻结的python脚本执行时,上述代码应该按预期工作,当作为onefile应用程序冻结时,PyInstaller也应该按预期工作。然而,onefile应用程序
被PyInstaller版本5.3之前的版本冻结时会遇到问题;由于父应用程序进程中缺少控制台控制信号处理,它总是立即终止,并留下了解压后的临时目录。

从版本5.3开始更改:在冻结应用程序的父进程中实现了控制台控制信号处理,这允许我们将其终止延迟到子进程被终止之后,并清理解压后的临时目录。但是,
仍然存在各种注意事项,后面的小节将进行讨论。

onefile模式和临时目录清理

在PyInstaller的onefile模式下,使用两个进程。启动应用程序时,父进程将嵌入式存档的内容解压缩到临时目录中,设置环境和库搜索路径,并启动子进程。
子进程设置嵌入式python解释器并运行冻结的python应用程序。同时,父进程等待子进程退出;当发生这种情况时,它清理提取的临时数据,然后退出。

从父进程的角度来看,无论子进程干净地退出(即成功代码),或者以错误代码退出(例如,python代码抛出未处理的异常),或者异常退出(例如,由于异常操作引起的崩溃
引发SIGABRTsignal),或者被操作系统终止(例如,从任务管理器中)。在所有情况下,在子进程退出或终止后,父进程执行清理,然后以从子进程返回的退出代码退出。

因此,为了清理应用程序的临时目录,父进程不能被强制终止(例如,通过TerminateProcess函数)。如果发生这种情况,清理代码没有机会运行,并留下了临时目录。另一方面
,从临时目录清理的角度来看,子进程可以以任何方式终止,甚至强制终止。为了在通过控制台控制信号(例如,在按_Ctrl+C_或由于关闭控制台窗口而触发时)触发的正常关机期间进行适当的清理
触发,PyInstaller 5.3及更高版本中的引导程序尝试延迟父进程关闭,以便子进程有时间退出,父进程的主线程有机会运行清理代码。

以下各节为不同情况下的此行为提供了附加详细信息。

通过Ctrl+C或Ctrl+Break中断

在控制台窗口中按_Ctrl+C或_Ctrl+Break_时,CTRL_C_EVENTorCTRL_BREAK_EVENT发送给所有连接到该控制台的进程。^4.

在onefile冻结应用程序中,父进程忽略/抑制信号,因此结果取决于子进程中的冻结python代码如何处理信号。如果python代码退出(例如,没有安装handler和KeyboardInterruptexception中断程序流程),则父进程执行清理并退出。如果子进程中的python代码处理信号而没有关闭子进程,则该应用程序将继续运行。

任何PyInstaller版本都可以使用此行为;在版本5.3之前的版本中,父进程显式忽略了SIGABRT和SIGBREAK信号,从而实现了与处理相应控制台控制信号的相同结果,这在5.3版本中得以实现。

(4)如果从控制台启动windowed/noconsole应用程序,则该应用程序在具有窗口的情况下完全独立于控制台。如果应用程序没有窗口(即,“隐藏”应用程序),则其进程不会收到响应
_Ctrl+C_和_Ctrl+Break_按下时发出的CTRL_C_EVENT和CTRL_BREAK_EVENT信号,但是在关闭控制台时仍然被终止。终止似乎是立即而无条件的,即,不存在CTRL_CLOSE_EVENT信号。

关闭控制台窗口

当关闭控制台窗口(通过在标题栏上按_X_按钮)时,CTRL_CLOSE_EVENT发送到连接到该控制台的所有进程。?

在onefile冻结应用程序中,父进程接收信号并暂停处理程序的执行线程20秒。这种方法,父进程的终止被延迟,以便子进程(也接收到该信号)有时间退出,并且父进程的主线程执行清理和退出(然后也终止处理程序的执行线程)。在PyInstaller 5.3中实现了这种行为,以确保关闭控制台窗口可清除应用程序的临时目录。

在5.3版本之前的版本中,CTRL_CLOSE_EVENT不被处理。父进程立即终止,无法执行清理,留下应用程序的临时目录。

**注:**子进程(即冻结的Python应用程序代码)可能会安装自己的控制台控制信号处理程序,以执行自己的清理(例如保存应用程序状态)。 如果是这样,则重要的是要记住系统规定的五秒超时时间,并且父进程只能在子进程退出后执行临时目录清理。 换句话说,如果子进程中的清理接近五秒钟,那么在操作系统终止进程之前,父进程可能没有机会执行自己的清理。

通过任务管理器终止应用程序

通过任务管理器终止应用程序有些不可预测,因为“应用”和“后台进程”之间存在区别。

“应用”通过向应用程序发送关闭请求来关闭。如果这些应用程序在响应请求时关闭其窗口,或者如果它们有控制台,它们处理CTRL_CLOSE_EVENT控制台控制信号,则这些应用程序可以正常关闭。

“后台进程”使用TerminateProcess无条件终止,没有希望进行优雅的关机和清理。

这两者之间的区别是基于程序是否具有可见窗口,但实际上,有关控制台启用的应用程序和具有多个进程的应用程序存在额外的细微差别。

要在每个进程基础上查看详细分类,请右键单击任务管理器中进程列表视图的标题,并启用Type列的显示。 新添加的列将显示每个进程的进程分类,而不仅仅是整个进程组。

在以下子部分中,我们详细说明与冻结应用程序相关的不同进程关闭行为。 粗略地说,行为高度取决于以下因素:

  • 构建类型:onedir(单进程)vs.onefile(两进程)PyInstaller构建选项。
  • 是否启用控制台:console vs.noconsole / windowed PyInstaller构建选项。
  • 应用程序是否具有窗口:无论应用程序是否启用控制台,它都可能具有窗口(窗口+控制台)或不具有窗口(纯控制台应用程序;或作为后台进程运行的“隐藏”,无窗口无控制台的应用程序)。
  • 应用程序的启动方式:通过双击可执行文件(带有自己的控制台窗口的“独立”应用程序)或在已打开的命令提示符中运行它。

2.9. 特定功能的注释 57

有窗口/无控制台单进程应用程序

在有窗口/无控制台的单进程应用程序中,没有控制台的单进程应用程序是最容易理解任务管理器和关闭行为的应用程序。

如果应用程序具有窗口(例如基于Qt的GUI),则它被视为“应用程序”。它在“应用程序”下列出,并且其进程名称列在列表中的顶级条目旁边。通过“结束任务”关闭它会导致窗口关闭事件被发布,从而允许进行优雅的应用程序关闭。

如果应用程序没有窗口(无窗口和无控制台的“隐藏”应用程序),则它被视为“后台进程”,并且在“后台进程”下列出。通过“结束任务”关闭它会导致其被无条件终止,没有希望进行优雅的应用程序关闭。

如早期部分所述,无论是不是从控制台启动,有窗口/无控制台应用程序都不依赖于控制台,只要它们有窗口。另一方面,如果应用程序没有窗口,则控制台进程的关闭会导致立即和无条件地终止应用程序进程(控制台内的后台进程)。

由于onedir应用程序不需要将其内容解压缩到临时目录,因此终止模式从PyInstaller的角度并不会影响清理。但是,如果应用程序希望执行一些清理工作(例如在关机期间保存当前状态,如前面的示例所示),则可能会引起关注。

启用控制台单进程应用程序

任务管理器和启用控制台的单进程应用程序的关闭行为取决于应用程序本身是否具有窗口(例如启用控制台的基于Qt的GUI应用程序)或无窗口(“纯”控制台应用程序),以及应用程序是否拥有控制台窗口。

通过双击运行纯控制台onedir应用程序

通过双击可执行文件运行纯控制台应用程序将打开一个新的控制台,其中应用程序在其中运行。 进程列表中的顶级条目被放置在“应用程序”下之下; 然而,它没有进程名称列在其旁边。相反,它是一个由“控制台窗口宿主”(一个“Windows进程”)和实际的应用程序进程组成的组,后者分类为“应用程序”。

通过“结束任务”关闭整个组(即顶级条目)会导致一切被无条件终止。

关闭应用程序进程会导致它接收CTRL_CLOSE_EVENT进行优雅和安全的关闭。

通过现有控制台运行纯控制台onedir应用程序

打开新的命令提示符会导致在“应用程序”下添加一个新的“Windows命令处理器”组条目。它由“控制台窗口宿主”(一个“Windows进程”)和“命令提示符”(一个“应用程序”)组成。从打开的命令提示符中运行纯控制台应用程序会导致新进程添加在现有的“Windows命令处理器”组中,并且在进程分类为“后台进程”。

因此,关闭整个组会导致一切被无条件终止。

关闭应用程序进程会导致它被无条件终止。

关闭“命令提示符”进程会导致应用程序进程接收CTRL_CLOSE_EVENT优雅和安全的关闭。

在双击运行的有窗口/启用控制台单进程应用程序

通过双击运行具有窗口的启用控制台的应用程序类似于对应的纯控制台应用程序情况。所得到的进程列表条目被放置在“应用程序”下,是一个由“控制台窗口宿主”(一个“Windows进程”)和实际应用程序进程组成的组,后者分类为“应用程序”。

通过关闭整个组,会导致一切被无条件终止。

关闭应用程序进程会导致它接收CTRL_CLOSE_EVENT进行优雅和安全的关闭。

通过现有控制台运行有窗口/启用控制台单进程应用程序

从现有命令提示符中运行带窗口的启用控制台的应用程序不会将应用程序进程放到现有的“Windows命令处理器”组中,而是结果是在进程列表中添加一个新的“应用程序”顶级条目。此条目的行为类似于windowed onedircase;它在其旁边列出进程名称,通过“结束任务”关闭它可以发布窗口关闭事件,从而允许进行优雅的应用程序关闭。

关闭整个“Windows命令处理器”会关闭控制台,但应用程序本身仍在运行(尽管其控制台句柄可能无效)。

关闭“Windows命令处理器”组内的“命令提示符”进程结果应用程序进程接收到CTRL_CLOSE_EVENT以进行优雅的关闭。

启用控制台的单文件应用程序

启用控制台的单文件应用程序的关闭行为变得复杂是因为涉及两个进程,并且应用程序内容需要提取到临时目录中,该目录在关闭应用程序时应理想地进行清理。

通过双击运行的纯控制台单文件应用程序

通过双击可执行文件运行纯控制台应用程序会在其中运行应用程序的新控制台中打开。进程列表中的顶级条目位于“应用程序”下方,其中包括:

  • “控制台窗口主机”(一个“Windows进程”)
  • 父进程,被分类为“应用程序”
  • 子进程,被分类为“后台进程”

关闭整个组会导致所有内容被无条件终止。临时目录保留在系统中。

关闭子进程会导致其立即无条件终止。在子进程终止后,父进程执行临时目录清除并退出,也会关闭控制台。这种情况的唯一潜在缺点是应用程序代码无法执行自己的清理操作。

关闭父进程会导致父进程和子进程都接收到CTRL_CLOSE_EVENT。在子进程执行其清理操作(如果有的话)并退出后,父进程也会执行临时目录清除并退出。这是最理想的情况。

(^5)句柄无效的控制台可能会导致应用程序代码尝试使用它们时出错,例如向(现在不存在的)控制台打印消息。

(^6)假设应用程序代码中的潜在清理操作不会延迟关闭到操作系统在父进程有机会执行临时目录清理之前杀死父进程的时候……

通过现有控制台运行的纯控制台单文件应用程序

在打开的命令提示符中运行纯控制台应用程序会导致在其中添加两个新进程的“Windows命令处理器”组中,两个进程都被分类为“后台进程”。

关闭整个“Windows命令处理器”组会导致其中的所有内容被无条件终止,并留下临时目录。

关闭父进程会导致其立即无条件终止。控制台再次接受输入,而子进程(实际应用程序)仍在后台运行(即仍将其输出写入控制台)。由于父进程在执行清理操作之前被终止,因此临时目录被保留。

关闭子进程同样会导致其立即无条件终止。在子进程终止后,父进程执行临时目录清除并退出。这种情况的唯一潜在缺点是应用程序代码无法执行自己的清理操作。

关闭“命令提示符”进程是最佳选择,因为它会导致父进程和子应用程序进程都接收到CTRL_CLOSE_EVENT进行优雅的关闭。

但是,在这种情况下,最可靠的关闭应用程序的方法可能是使用Ctrl +C或Ctrl + Break,甚至关闭控制台窗口。

通过双击运行的具有窗口的启用控制台的单文件应用程序

通过双击运行带有窗口的启用控制台应用程序会导致在进程列表中出现两个顶级条目。

第一个条目是属于父级进程的组;其中包含一个“控制台窗口主机”(一个“Windows进程”)和被分类为“应用程序”的父进程。

子进程被列为单独的顶级条目,也被分类为“应用程序”,其进程名称在旁边列出。

关闭整个父进程组会导致其中的所有事物被无条件终止,而子进程(实际应用程序)仍在运行。临时目录保留在系统中。

关闭父进程会导致父进程和子进程都接收到CTRL_CLOSE_EVENT。在子进程执行其清理操作(如果有的话)并退出后,父进程执行临时目录清除并退出。这是最理想的情况。

关闭子进程会导致其接收到CTRL_CLOSE_EVENT以进行优雅的关闭。在子进程执行其清理操作(如果有的话)并退出后,父进程执行临时目录清除并退出。这是最理想的情况;在这种情况下,即使子进程超出信号处理超时并被操作系统强制终止,父进程也会执行临时目录清除。

在打开的命令提示符中运行具有窗口的启用控制台应用程序会将父进程添加到现有的“Windows命令处理器”组中,作为“后台进程”。

子进程被列为单独的顶级条目,被分类为“应用程序”,其进程名称在旁边列出。

关闭整个“Windows命令处理器”会关闭控制台,并导致父进程立即无条件终止。子进程(应用程序本身)继续运行(尽管其控制台句柄可能无效)。临时目录保留在系统中。

关闭父进程会导致其立即无条件终止。控制台保持打开并再次接受输入,而子进程(实际应用程序)仍在后台运行(即仍将其输出写入控制台)。由于父进程在执行清理操作之前被终止,因此临时目录被保留。

关闭子进程会导致其接收到CTRL_CLOSE_EVENT以进行优雅的关闭。在子进程执行其清理操作(如果有的话)并退出后,父进程执行临时目录清除并退出。这是最理想的情况;在这种情况下,即使子进程超出信号处理超时并被操作系统强制终止,父进程也会执行临时目录清除。

关闭“命令提示符”进程会导致父进程和子应用程序进程都接收到CTRL_CLOSE_EVENT以进行优雅的关闭。这是最理想的情况。

带窗口/不带控制台的单文件应用程序

对于带窗口/不带控制台的单文件应用程序,应用程序的父进程通常被分类为“后台进程”。子进程的分类取决于应用程序是否具有窗口。

没有窗口的不带控制台单文件应用程序,通过双击运行

通过双击可执行文件运行“隐藏”应用程序(没有控制台/没有窗口的应用程序)会导致父进程和子进程作为两个不同的顶级条目添加到进程列表中,在“后台进程”下方。

关闭父进程会导致它立即且无条件地终止。子进程(即实际应用程序)继续运行。由于父进程在执行清理之前就被终止了,所以临时目录被留下。

关闭子进程也会导致其立即且无条件地终止。在子进程被终止后,父进程执行临时目录清理并退出。这种情况唯一的潜在缺陷是应用程序代码无法执行自己的清理。

在已存在的控制台窗口中运行无窗口一文件应用程序

从已打开的命令提示符运行“隐藏”的应用程序会产生两个新进程,都被归类为“后台进程”,并添加到现有的“Windows命令处理器”组中。

关闭整个“Windows命令处理器”组会导致一切被无条件地终止,并且临时目录被留下。

关闭父进程会导致它立即且无条件地终止。子进程(即实际应用程序)作为后台进程继续运行。由于父进程在执行清理之前就被终止了,所以临时目录被留下。

同样地,关闭子进程会导致其立即且无条件地终止。在子进程被终止后,父进程执行临时目录清理并退出。这种情况唯一的潜在缺陷是应用程序代码无法执行自己的清理。

关闭“命令提示符”进程会关闭控制台,但父进程和子进程仍会作为后台进程运行。它们的条目被移动到“后台进程”下的新组条目中,而被移除的“Windows命令处理器”组中不再存在。

2.9. 特殊功能的注意事项 61

带有窗口的无控制台一文件应用程序,通过双击运行

通过双击运行常规的GUI无控制台应用程序会导致父进程被归类为“后台进程”,子进程被归类为“应用程序”。它们都在进程列表中拥有自己的顶级条目(分别在“后台进程”和“应用程序”下),并且它们的进程名称会在它们旁边列出。

关闭父进程会导致它立即且无条件地终止。子进程(即实际应用程序)继续运行。由于父进程在执行清理之前就被终止了,所以临时目录被留下。

关闭子进程会导致向子进程发送一个窗口关闭请求(以及CTRL_CLOSE_EVENT信号)以进行优雅的关闭。在子进程执行其清理(如果有的话)并退出之后,父进程执行临时目录清理并退出。这是理想的情况;在这种情况下,即使子进程超过信号处理超时并被操作系统强制终止,父进程也会执行临时目录清理。

带有窗口的无控制台一文件应用程序,通过已有的控制台运行

从现有控制台运行常规的GUI无控制台应用程序与通过双击运行它类似,只是父进程(归类为“后台进程”)在“Windows命令处理器”组中的“应用程序”下而不是在“后台进程”下拥有独立条目。

关闭整个“Windows命令处理器”会关闭控制台并导致父进程被立即且无条件地终止。子进程(即应用程序本身)继续运行。临时目录被留下。

关闭父进程会导致它立即且无条件地终止。这不会对控制台或子进程产生影响,它们两个都会继续运行。由于父进程在执行清理之前就被终止了,所以临时目录被留下。

关闭子进程会导致它接收CTRL_CLOSE_EVENT以进行优雅的关闭。在子进程执行其清理(如果有的话)并退出之后,父进程执行临时目录清理并退出。这是理想的情况;在这种情况下,即使子进程超过信号处理超时并被操作系统强制终止,父进程也会执行临时目录清理。

关闭“命令提示符”进程会关闭控制台并导致父进程立即且无条件地终止。由于父进程在执行清理之前就被终止了,所以临时目录被留下。

2.10 当事情出错时

上述信息涵盖了PyInstaller的大多数正常用途。然而,Python和第三方库的变化是无法预测的。当您尝试捆绑应用程序时,可能会出现PyInstaller本身或捆绑的应用程序中止Python回溯的情况。此时,请依次考虑以下操作,再寻求技术帮助。

62第2章.目录:

2.10.1 针对特定问题的配方和示例

PyInstaller FAQ页面提供了一些常见问题的解决方案。我们的PyInstaller Recipes页面提供了一些高级使用和一些常见问题的代码示例。其中一些菜谱包括:

  • 一种更复杂的收集数据文件的方法(添加文件到捆绑包)。
  • 捆绑典型的Django应用程序。
  • 使用运行时挂钩设置PyQt5 API级别。
  • 在Windows下解决多处理约束的解决方法。

以及其他。其中许多配方是由用户贡献的。请随时贡献更多的食谱!

2.10.2 查找出错原因

构建时的信息

当运行Analysis步骤时,它会产生错误和警告信息。如果–log-level选项允许,这些信息将显示在命令行之后。Analysis还会在名为build / name / warn-name.txt的警告文件中,放置信息。

当检测到导入并且命名的模块找不到时,Analysis会创建一条消息。当在包中声明一个类或函数(即__init__.py模块),并且导入指定了包名称时,可能也会产生消息。在这种情况下,分析无法确定名称是否应该引用子模块或包。

"找不到模块"消息不被归类为错误,因为通常情况下会有许多这样的消息。例如,许多标准模块会有条件地导入可能存在或可能不存在的不同平台的模块。

所有“模块未找到”的消息都写入到build / name / warn-name.txt文件中。它们不会显示在标准输出中,因为有许多这样的消息。检查警告文件,通常会有许多未找到的模块,但它们的缺失没有影响。

当您运行捆绑的应用程序并且它因导入错误而终止时,那就是检查警告文件的时候了。然后,请查看下面的_帮助PyInstaller找到模块_以了解如何继续。

构建时依赖关系图

在每次运行PyInstaller时,PyInstaller会将有关依赖关系的交叉引用文件写入build/name/目录下。xref-name.html文件在work-path目录下,它是一个html文件,列出了导入图的完整内容,显示哪些模块是由哪些模块导入的。您可以在任何Web浏览器中打开它。查找一个模块名称,然后不断点击“导入自”的链接,直到找到导致该模块被包含的最高级别导入为止。

如果您将–log-level=DEBUG指定给pyinstaller命令,则PyInstaller还会生成表示依赖关系图的Graphviz输入文件。该文件是build/name/graph-name.dot在work-path=directory中。您可以使用任何GraphViz命令,例如dot,处理它,以生成导入依赖项的图形显示。

这些文件非常大,因为即使是最简单的“hello world” Python程序,也最终包括大量的标准模块。因此,在此版本中,图形文件并不是非常有用。

2.10. 当事情出了问题 63

构建时的Python错误

PyInstaller有时会通过引发Python异常来终止。在大多数情况下,异常消息中的原因是清楚的,例如“您的系统不受支持”,或“Pyinstaller需要至少Python 3.7”。其他明显指出应报告的错误存在。

然而,其中一个错误可能令人困惑:IOError(“找不到Python库!”)PyInstaller需要打包Python库,这是Python解释器的主要部分,作为动态加载库链接。该文件的名称和位置因使用的平台而异。某些Python安装默认情况下不包括动态Python库(可能存在静态链接的库,但不能使用)。您可能需要安装某种开发包。或者,库可能存在,但不在PyInstaller正在搜索的文件夹中。

PyInstaller寻找python库的位置在不同操作系统中是不同的,但/lib和/usr/lib在大多数系统中都会被检查。如果您无法将python库放在那里,请尝试在GNU/Linux中的环境变量LD_LIBRARY_PATH或macOS中的DYLD_LIBRARY_PATH中设置正确的路径。

获取调试消息

–debug=all选项(及其_choices_)提供了大量诊断信息。这在开发复杂包或应用程序看起来不起作用时很有用,或者仅了解运行时如何工作。

通常,调试进度消息会发送到标准输出。如果在打包Windows应用程序时使用了–windowed选项,则会将它们发送到任何附加的调试器。如果您没有使用调试器(或没有调试器),则可以使用DebugView免费(啤酒)工具来显示此类消息。它必须在运行打包的应用程序之前启动。

对于–windowedmacOS应用程序,它们不会被显示。

考虑为您的生产版本打包而不使用–debug。调试消息需要系统调用并对性能产生影响。

获取Python的Verbose Imports

您可以使用–debug=imports(请参见_获取Debug消息_上面)构建应用程序,这将向嵌入式Python解释器传递-v(详细导入)标志。这可能非常有用。即使是表面上工作良好的应用程序,也可能会提供信息,以确保它们从装捆包中获得所有导入,而不会泄漏到本地安装的Python中。

Python冗长和警告消息始终进入标准输出,并且在使用–windowed选项时不可见。请记住,不要将其用于您的生产版本。

弄清楚为什么您的GUI应用程序无法启动

如果您使用了–windowed选项,则打包应用程序可能无法启动,并显示类似“Failedtoexecute script my_gui”的错误消息。在这种情况下,您需要获取更多详细的输出以了解情况。

  • 对于macOS,您可以在命令行中运行应用程序,即./dist/my_gui在终端(_Terminal中)而不是点击my_gui.app。
  • 对于Windows,您需要重新打包应用程序,并删除–windowed选项。然后,您可以从命令行运行生成的可执行文件,即my_gui.exe。
  • 对于Unix和GNU/Linux,没有–windowed选项。无论如何,如果GUI应用程序失败,则可以在命令行中运行您的应用程序,即…/dist/my_gui。

这应该为您提供阻止应用程序初始化的相关错误,然后您可以继续进行其他调试步骤。

64 第2章。 内容:

操作不允许的错误

如果您使用–onefile并且它无法运行,您的程序将出现错误,例如:

./hello: errorwhile loading shared libraries: libz.so.1:
failed to map segmentfrom sharedobject: Operationnotpermitted

这可能是由/tmp目录的错误权限引起的(例如,文件系统使用noexec标志进行挂载)。

解决此问题的简单方法是,在环境变量TMPDIR中设置一个在没有noexec标志挂载的文件系统中的目录的路径,例如:

export TMPDIR=/var/tmp/

2.10.3 帮助PyInstaller查找模块

扩展路径

如果分析识别到需要模块却找不到该模块,则通常是因为脚本正在操作sys.path。在这种情况下,最简单的方法是使用–paths选项列出脚本可能搜索导入的所有其他位置:

pyi-makespec --paths=/path/to/thisdir \
--paths=/path/to/otherdir myscript.py

这些路径将在spec文件中以pathex参数的形式被记录下来。它们将被添加到当前分析期间的sys.path中。

列出隐藏的导入

如果分析认为已找到所有导入项,但应用程序却以导入错误失败,则问题是隐藏导入项;也就是说,在分析阶段不可见的导入项。

当代码使用__import__(),importlib.import_module()或可能使用exec()或eval()时,可能会出现隐藏导入项。当扩展模块使用Python/C API执行导入时,也可能会出现此情况。发生这种情况时,分析不能检测到任何东西。没有警告,只有运行时的ImportError。

要找到这些隐藏的导入项,请使用–debug=imports标志(请参见_获取Python的Verbose Imports_上面)构建应用程序并运行它。

知道需要哪些模块之后,您可以使用–hidden-import命令选项、编辑spec文件或使用钩子文件(请参见_理解PyInstaller Hooks_以下)将所需的模块添加到包中。

扩展软件包的__path__

Python允许脚本通过__path__机制扩展导入时使用的搜索路径。通常,导入模块的__path__只有一个入口点,即找到__init__.py的目录。但__init__.py可以自由地扩展它的__path__来包括其他目录。例如,win32com.shell.shell模块实际上解析为win32com/win32comext/shell/shell.pyd。这是因为win32com/init.py将…/win32comext附加到它的__path__中。

因为导入模块的__init__.py在分析过程中实际上不会被执行,它对__path__所做的更改不会被PyInstaller所看到。我们使用与隐藏导入使用的相同的hook机制来解决这个问题,再加上一些附加逻辑;请参阅下文中的了解PyInstaller Hooks。

请注意,以这种方式挂钩__path__的操纵仅适用于分析。在运行时,所有导入都会拦截并从包内部满足。win32com.shell解决方法与win32com中的其他任何东西相同,而win32com.__path__对…/win32comext一无所知。

偶尔并不足够。

改变运行时行为

更奇怪的情况可以通过运行时挂钩来容纳。这些是操作环境的小脚本,使您的脚本运行之前提供附加的顶级代码。

有两种提供运行时挂钩的方法。您可以使用选项–runtime-hook= _path-to-script_来命名它们。

其次,一些运行时挂钩是提供的。在分析结束时,由分析阶段产生的模块列表中的名称在PyInstaller安装文件夹中查找loader/rthooks.dat。这个文本文件是一个Python字典的字符串表示形式。键是模块名称,值是挂接脚本路径名的列表。如果有匹配,这些脚本将被包含在捆绑应用程序中,并在启动您的主脚本之前调用。

使用选项命名的挂钩按给定顺序执行,并在任何安装的运行时挂钩之前执行。如果您指定–runtime-hook=file1.py --runtime-hook=file2.py,那么运行时的执行顺序将是:

  1. file1.py的代码。
  2. file2.py的代码。
    3.在rthooks/rthooks.dat中找到的包含模块的任何指定钩子。
    4.您的主脚本。

以这种方式调用的挂钩虽然需要小心其导入内容,但几乎可以做任何事情。编写运行时钩子的一个原因是覆盖一些模块的某些函数或变量。 Django运行时钩子的一个很好的例子(请参阅PyInstaller文件夹中的loader/rthooks/pyi_rth_django.py)。 Django动态地导入一些模块,并寻找一些.py文件。但是,在单个文件捆绑中,.py文件不可用。我们需要以返回值列表的方式重写函数django.core.management.find_commands。运行时挂钩如下所示:

import django.core.management
def_find_commands(_):
return """cleanup shell runfcgi runserver""".split()
django.core.management.find_commands = _find_commands

2.10.4获取最新版本

如果您有某种原因认为在PyInstaller中发现了一个错误,则可以尝试下载最新的开发版本。这个版本可能具有尚未在PyPI中的修复或功能。您可以从PyInstaller下载页面下载最新的稳定版本和最新的开发版本。

您也可以直接使用pip安装PyInstaller的最新版本:

pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip

2.10.5寻求帮助

当上述建议都无法帮助时,请在PyInstaller电子邮件列表上寻求帮助。

然后,如果您认为您发现了PyInstaller中的BUG,参考如何报告BUG页面。

2.11高级主题

下面的讨论涵盖了PyInstaller内部方法的详细信息。您不应该需要这个级别的细节来正常使用,但是如果您想调查PyInstaller代码并可能为其做出贡献,则这些细节是有帮助的,如如何做出贡献所述。

2.11.1详细介绍引导过程

在打包的脚本可以开始执行之前,必须执行许多步骤。概述了这些步骤(单文件和单文件夹程序的工作方式部分)。以下是更多细节,以帮助您了解引导程序做了什么以及如何解决问题。

引导程序

引导程序为运行Python代码准备了一切。它开始设置,然后在另一个进程中返回自己。这种使用两个进程的方法允许了很大的灵活性,并且在Windows的单文件夹模式以外的所有捆绑中都使用。因此,如果在您的系统任务管理器中看到捆绑的应用程序作为两个进程,请不要感到惊讶。

引导程序执行期间会发生什么:

A.第一个进程:启动引导程序。

1.如果是单文件模式,请将捆绑的文件提取并复制到temppath/_MEIxxxxxx。
2.修改各种环境变量:
- GNU / Linux:如果设置了,则将LD_LIBRARY_PATH的原始值保存到LD_LIBRARY_PATH_ORIG中。将我们的路径前缀添加到LD_LIBRARY_PATH中。
- AIX:做同样的事情,但使用LIBPATH和LIBPATH_ORIG。
- OSX:取消设置DYLD_LIBRARY_PATH。
3.设置以处理两个进程的信号。
4.运行子进程。
5.等待子进程完成。
6.如果是单文件模式,请删除temppath/_MEIxxxxxx。
B.第二个进程:引导程序本身作为子进程启动。
1.在Windows上设置激活上下文。
2.加载Python动态库。动态库的名称嵌入在可执行文件中。
3.初始化Python解释器:设置sys.path、sys.prefix和sys.executable。
4.运行python代码。

运行Python代码需要执行几个步骤:

2.11.高级主题 68

1.运行Python初始化代码,它为运行用户的主脚本准备了一切。初始化代码只能使用Python内置模块,因为一般的导入机制还不可用。它设置Python导入机制,只从嵌入在可执行文件中的存档中加载模块。它还将frozen和_MEIPASS属性添加到sys内置模块中。
2.执行任何运行时钩子:先是用户指定的钩子,然后是任何标准钩子。
3.安装python“egg”文件。当一个模块是一个zip文件(.egg)的一部分时,它已经被捆绑到./eggs目录中。安装意味着将.egg文件名附加到sys.path。Python自动检测sys.path中的项是zip文件还是目录。
4.运行主脚本。

Python在捆绑的应用程序中导入

PyInstaller将已编译的Python代码(.pyc文件)嵌入可执行文件中。PyInstaller将它的代码注入到正常的Python导入机制中。Python允许这样做;该支持在PEP 302“新的导入钩子”中有所描述。

PyInstaller实现了PEP 302规范,用于导入内置模块、导入“冻结”模块(与应用程序捆绑的已编译Python代码)和C扩展。该代码可以在./PyInstaller/loader/pyi_mod03_importers.py中进行阅读。

在运行时,PyInstaller的PEP 302钩子被附加到variables中的sys.meta_path变量上。在尝试导入模块时,解释器将首先尝试使用sys.meta_path中的PEP 302钩子,然后才会在sys.path中进行搜索。因此,Python解释器从捆绑的可执行文件中嵌入的存档中加载导入的python模块。

这是捆绑的应用程序中导入语句的解决顺序:

  1. 它是内置模块吗?内置模块的列表在variablesys.builtin_module_names中。
  2. 它是嵌入到可执行文件中的模块吗?然后从嵌入式存档中加载它。
  3. 它是C扩展吗?应用程序将尝试查找名为package.subpackage.module.pyd或package.subpackage.module.so的文件。
  4. 然后检查sys.path中的路径。可能会有任何附加位置的python模块或.egg文件名
  5. 如果未找到该模块,则引发ImportError。

启动画面

注意: 此功能与MacOS不兼容。在当前设计中,启动画面在一个次要线程中运行,在MacOS上不允许使用Tcl/Tk(或者说底层GUI工具包)。

如果应用程序中捆绑了启动画面,则引导程序的启动过程和线程模型会更加复杂。如果捆绑了启动画面,以下是操作顺序:

  1. 引导程序检查它是否作为最外层应用程序运行(不是引导程序所生成的子进程)。
  2. 如果捆绑了启动画面资源,则尝试提取它们(onefile模式)。提取路径位于temppath/_MEIxxxxxx/__splashx内。如果在onedir模式下,则应用程序假设资源相对于可执行文件。
  3. 将tcl和tk共享库加载到引导程序中。
    • Windows:tcl86t.dll/tk86t.dll
  • Linux:libtcl.so/libtk.so
  1. 用以下函数替换/修改Tcl/Tk解释器的最小环境:
    1. ::tclInit:调用此命令以找到tcl的标准库。我们替换此命令以强制tcl仅加载/执行捆绑的模块。
    2. ::tcl_findLibrary:Tk使用此函数来获取其所有组件。覆盖的功能设置所需的环境变量并评估请求的文件。
    3. ::exit:修改此函数以确保正确退出启动画面线程。
  2. ::source:此命令执行传递文件的内容。由于我们运行在最小环境中,我们模拟执行未捆绑文件的执行,并执行那些被绑定的文件。
  3. 启动tcl解释器并执行由PyInstaller的构建目标Splash在构建时生成的启动画面脚本。该脚本创建了环境变量_PYIBoot_SPLASH,并且该变量对Python解释器也是可用的。它还初始化一个tcp服务器套接字,以接收来自Python的命令。

注意: Tcl解释器在单独的线程中启动。仅在Tcl解释器执行了启动画面脚本之后,负责提取/启动Python解释器的引导程序线程才会恢复。

2.11.2 pyi_splash模块(详细)

该模块连接到引导程序以向启动界面发送消息。

它旨在充当提供的引导程序功能的RPC接口,例如显示文本或关闭。这使用户的Python程序与如何实现与引导程序通信无关,因为提供了一致的API。

要连接到引导程序,它连接到一个本地tcp服务器套接字,套接字的端口通过环境变量_PYIBoot_SPLASH传递。引导程序通过Python模块_socket连接到套接字。尽管该套接字是双向的,但该模块仅配置为发送数据。由于在启动时需要os模块才能请求环境变量,因此该模块在初始化之前不建立连接。

该模块不支持在显示闪屏时重新加载,即无法重新加载(例如通过importlib.reload()),因为与此模块实例的连接断开时,闪屏自动关闭。

函数

注意: 请注意,如果_PYIBoot_SPLASH环境变量不存在或在连接过程中发生错误,则模块将不会引发错误,但仅仅是不初始化自己(即pyi_splash.is_alive()将返回False)。在向启动画面发送命令之前,应检查模块是否正确初始化,否则将引发RuntimeError。

is_alive()
指示模块能否使用。
如果模块未初始化或通过关闭启动画面被禁用,则返回False; 否则,该模块可用。

update_text(msg)
更新闪屏窗口上的文本。

**参数msg(str)- 要显示的文本
引发

  • ConnectionError-如果操作系统无法写入套接字
  • RuntimeError-如果未初始化模块

close()
关闭与ipc tcp服务器套接字的连接
这将关闭启动画面并使该模块无法使用。调用此函数后,无法再次打开与闪屏的连接,并且如果此模块的所有函数都变得无法使用

(dest_name, src_name, typecode)

其中,dest_name 是目标文件名(即冻结应用程序中的文件名;因此,必须始终是相对名称),src_name 是源文件名(从哪个位置收集文件的路径),而 typecode 是表示文件或条目类型的字符串。

在内部,PyInstaller 使用许多 typecode 值,但对于普通情况,您只需知道以下值:

type-code
说明 dest_name src_name
'DATA' 任意(数据)文件。 在冻结的应用程序中的名称。 在构建系统上文件的完整路径。
'BINARY'
共享库。 在冻结的应用程序中的名称。 在构建系统上文件的完整路径。
'EXTENSION'

Python 二进制扩展。

在冻结的应用程序中的名称。 在构建系统上文件的完整路径。
'OPTION'

PyInstaller/Python 运行时选项。

选项名称(以及可选值,由空格分隔)。

目标名称对应于冻结的应用程序中的最终文件名,相对于顶级应用程序目录的名称。 它可以包括路径元素,例如 extras/mydata.txt。

第 2.1 章. 内容:

类型为 BINARY 和 EXTENSION 的条目假定表示包含可加载可执行代码的文件,例如动态库。 通常,EXTENSION 用于表示 Python 扩展模块,例如由 Cython 编译的模块。 这两种文件类型以相同的方式进行处理; PyInstaller 扫描它们以获取任何发现的附加链接时间依赖项,并收集它们。 在某些操作系统上,二进制文件和扩展会经历额外的处理(例如针对链接时间依赖项的路径重写和在 macOS 上的代码签名)。

在将 TOC 列表传递给构建目标之前,Analysis 生成的 TOC 列表可以在 spec 文件中进行修改,以包括附加条目(虽然最好通过 Analysis 的 binaries 或 datas 参数传递要包括的额外文件)或删除不需要的条目。

在 PyInstaller 5.11 版本中更改:在 PyInstaller 版本 5.11 之前,TOC 列表实际上是 TOC 类的实例,它在内部执行了隐式条目去重; 例如,尝试插入具有现有目标名称的条目将导致列表不发生更改。

但是,由于 TOC 类存在松散定义和冲突语义而导致的缺陷,TOC 类的使用已被弃用。 TOC 列表现在是普通列表的实例,并且 PyInstaller 执行显式列表归一化(条目去重)。 在 Analysis 实例化结束时,存储列表于类的属性中 (例如 Analysis.datas 和 Analysis.binaries)。 类似地,在构建目标(EXE, PYZ, PKG, COLLECT, BUNDLE)将输入的 TOC 列表整合为最终列表之后,也会执行显式列表规范化。

Tree 类

Tree 类提供了一种方便的方法来创建描述给定目录内容的 TOC 列表:

Tree(root, prefix=runtime-folder, excludes=string_list, typecode=code| 'DATA')
  • root 参数是一个字符串,表示目录的路径。它可以是绝对路径或相对于 spec 文件目录的路径。
  • prefix 参数是应用程序目录中子目录的名称,其中文件要收集。 如果未指定或设置为 None,则将文件收集到顶层应用程序目录中。
  • excludes 参数是要从 Tree 中省略的根目录中匹配的一个或多个文件的列表。列表中的项目可以是:
    - 一个名称,导致排除具有此基本名称的文件或文件夹
    - glob 模式(例如,*.ext),它会导致匹配的文件被排除。
  • typecode 的可选参数指定分配给 TOC 列表中所有条目的 TOC 类型码字符串。 默认值是 DATA,适用于大多数情况。

例如:

extras_toc = Tree (‘…/src/extras’,prefix =‘extras’,excludes =[‘tmp’,‘*.pyc’)

这将创建 extras_to 作为一个 TOC 列表,其中包含来自相对路径 …/src/extras 的所有文件的条目,省略具有名称为 tmp 或具有 .pyc 扩展名的文件(或位于一个名为 tmp 的文件夹中)。 这个 TOC 中的每个元组都有:

  • 格式为 file: extras/{filename} 的 dest_name。
  • 对应于…/src/extras 文件夹中文件的完整绝对路径的 src_name(相对于 spec 文件所在位置)。
  • DATA(默认值)的 typecode。

创建列表一些二进制模块的示例:

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

这将创建一个 TOC 列表,其中包含文件夹 cy_mods 中每个文件的条目,排除扩展名为 .pyx、.py 或 .pyc 的文件(因此,可能仅收集 Cython 创建的 .pyd 或 .so 模块)。 这个 TOC 中的每个元组都有:

  • 与文件基本名称相对应的 dest_name(所有文件都收集在顶级应用程序目录中)。
  • 对应于…/src/cy_mods 文件夹中该文件的完整绝对路径的 src_name(相对于 spec 文件的位置)。
  • EXTENSION(也可以使用 BINARY)的 typecode。

2.11.4 检查 archive

档案是包含其他文件的文件,例如 .tar 文件、.jar 文件或 .zip 文件。 PyInstaller 中使用两种类型的档案。一种是 ZlibArchive,它允许有效地存储 Python 模块,并且通过一些 import 钩子可以直接导入。 另一个是 CArchive,类似于 .zip 文件,是一种通用的打包(和可选压缩)任意数据块的方式。 它由于易于从 C 以及 Python 中轻松操纵而得名。 两者都源自共同的基类,因此相对容易创建新的档案类型。

ZlibArchive

ZlibArchive包含已压缩的.pyc或.pyo文件。在规范文件中,PYZ类的调用将创建一个ZlibArchive。

ZlibArchive中的目录是一个Python字典,将一个键(即在import语句中给出的成员名称)与ZlibArchive中的位置和长度相关联。ZlibArchive的所有部分都存储在序列化格式中,因此是与平台无关的。

在运行时,ZlibArchive用于导入捆绑的Python模块。即使使用最大压缩,这也比正常导入更快。在字典中进行查找,而不是在sys.path中搜索。没有目录操作和不需要打开文件(文件已经打开)。只需搜索、读取和解压缩。

Python错误跟踪将指向创建存档条目的源文件(__file__属性来自编译.pyc的时间,捕获并保存在存档中)。这不会告诉用户任何有用的信息,但如果他们向你发送了Python错误跟踪,你可以理解它。

CArchive

CArchive可以包含任何类型的文件。它非常类似于.zip文件。它们在Python中很容易创建,并且从C代码中很容易解压缩。CArchive可以附加到其他文件中,例如ELF和COFF可执行文件。为了允许这样做,归档文件是在文件末尾附带其目录的,只有一个cookie告诉目录从哪里开始,存档本身从哪里开始。

CArchive可以嵌入其他CArchive中。可以在不必解压它的情况下打开并使用内部归档。

每个目录条目具有可变长度。条目中的第一个字段给出条目的长度。最后一个字段是相应打包文件的名称。名称以空字符结尾。压缩对于每个成员是可选的。

每个成员还有一个类型代码。自解压可执行文件使用这些类型代码。如果将CArchive用作.zip文件,则无需担心代码。

ELF可执行文件格式(Windows、GNU/Linux和其他一些操作系统)允许将任意数据连接到可执行文件的末尾,而不会破坏其功能。因此,CArchive的目录位于存档文件的末尾。可执行文件可以将自身作为二进制文件打开,寻找到末尾并“打开”CArchive。

72章2.目录:

图1:ZlibArchive的结构
图2:CArchive的结构

2.11. 高级主题73:

图3:自解压可执行文件的结构

使用pyi-archive_viewer

使用pyi-archive_viewer命令检查任何类型的存档文件:

pyi-archive_viewer archivefile

使用此命令,可以检查使用PyInstaller(即PYZ或PKG)构建的任何存档文件,或者任何可执行文件(.exe文件或ELF或COFF二进制文件)。可以使用以下命令浏览归档文件:

  • O name: 打开嵌入式归档名称(如果省略,则提示)。例如,在查看单个文件的可执行文件时,可以打开其中的PYZ-00.pyz存档文件。
  • U: 返回上一级(查看包含的归档文件)。
  • X name: 提取_name_(如果省略,则提示)。提示输出文件名。如果没有给出,该成员将被提取到stdout。
  • Q: 退出。

pyi-archive_viewer命令具有以下选项:

-h, --help 显示帮助信息。
-l, --log 快速内容日志。
-b, --brief 打印Python可评估的内容文件名列表。
-r, --recursive 与-l或-b一起使用,应用递归行为。

74章2.目录:

2.11.5检查可执行文件

可以使用pyi-bindepend检查任何可执行文件:

pyi-bindepend executable_or_dynamic_library

pyi-bindepend命令分析您指定的可执行文件或DLL,并将所有二进制依赖项写入stdout。这很方便,可以查找可执行文件或其他DLL需要哪些DLL。

PyInstaller在分析过程中使用pyi-bindepend跟踪二进制扩展的依赖链。

2.11.6创建可再现的构建

在某些情况下,重要的是当您使用完全相同的依赖项构建相同的应用程序时,两个程序包应完全、逐比特相同。

通常情况下不是这样的。Python使用随机哈希来生成字典和其他散列类型,这影响已编译的字节码以及PyInstaller内部数据结构。因此,即使应用程序包的所有组件相同并且两个应用程序以相同的方式执行,两个构建也可能不会产生位对位相同的结果。

您可以通过在运行PyInstaller之前将PYTHONHASHSEED环境变量设置为已知的整数值来确保构建将产生相同的位。这将强制Python使用相同的随机哈希序列,直到PYTHONHASHSEED未设置或设置为"random"。例如,可以在以下脚本中执行PyInstaller(适用于GNU/Linux和macOS):

# 将种子设置为已知的可重复整数值
PYTHONHASHSEED=1
export PYTHONHASHSEED
# 创建一个名为myscript的单文件生成
pyinstaller myscript.spec
# 创建检验和
cksum dist/myscript/myscript | awk'{print $1}'> dist/myscript/checksum.txt
# 让Python再次变得不可预测
unset PYTHONHASHSEED

版本4.8中已更改:在生成的Windows可执行文件的PE标头中,构建时间戳设置为汇编过程中的当前时间。SOURCE_DATE_EPOCH环境变量可以指定自定义时间戳值,以实现可重复的构建。

2.12 理解PyInstaller Hooks

注意: 我们强烈建议程序包开发人员为其程序包提供钩子。有关如何轻松实现此方法,请参阅“提供PyInstaller钩子”部分。

总之,“钩子”文件扩展了PyInstaller,使其适应Python包使用的特殊需求和方法。
“钩子”一词用于两种类型的文件。一个运行时钩子帮助引导程序启动应用程序。更多关于运行时钩子的信息,请参见“更改运行时行为”。其他钩子在分析应用程序时运行。它们帮助分析阶段找到所需的文件。

大多数Python包使用正常的依赖项导入方法,PyInstaller可以轻松定位它们的所有文件。但有些软件包对Python导入机制的使用方式较为不同或在运行时做出了聪明的更改。因此,PyInstaller无法可靠地找到所有必需的文件,或者可能包含太多的文件。钩子可以告诉我们需要补充导入的其他源文件或者数据文件,或者需要排除的文件。

钩子文件是一个Python脚本,并且可以使用所有Python功能。它还可以从PyInstaller.utils.hooks 中导入辅助方法以及从PyInstaller.compat中导入有用的变量。这些辅助程序在下面有文档记录。

钩子文件的名称是hook-full.import.name.py,其中_full.import.name_是引入的脚本或模块的完全限定名称。您可以在PyInstaller发行版文件夹的hooks文件夹中浏览现有的钩子,并查看为哪些软件包编写了钩子的名称。例如hook-PyQt5.QtCore.py是一个钩子文件,它告诉我们模块PyQt5.QtCore所需的隐藏导入项。当您的脚本包含import PyQt5.QtCore或from PyQt5 import QtCore时,分析注意到hook-PyQt5.QtCore.py的存在,然后调用它。

许多钩子只包含一个语句,即对hiddenimports的赋值。例如,针对dnspython软件包的钩子,称为hook-dns.rdata.py,只有以下语句:


hiddenimports = [
"dns.rdtypes.*",
"dns.rdtypes.ANY.*"
]

当Analysis看到import dns.rdata或from dns import rdata时,它会调用hook-dns.rdata.py并检查其中hiddenimports的值。结果,就好像您的源文件也包含以下内容:

import dns.rdtypes.*
import dsn.rdtypes.ANY.*

钩子还可以导致添加数据文件,并且可以导致某些文件不被导入。下面是这些操作的示例。

当需要这些隐藏导入的模块仅对您的项目有用时,请将钩子文件存储在靠近源文件的位置。然后使用–additional-hooks-dir选项将其位置指定给pyinstaller或pyi-makespec命令。如果钩子文件与脚本位于同一级别,则该命令可以简单地为:

pyinstaller --additional-hooks-dir=. myscript.py

如果您为他人使用的模块编写了钩子,请请求程序包开发人员将该钩子包含在她/他的软件包中或发送钩子文件给我们,以便我们可以使其可用。

钩子是在分析对象查找钩子的文件夹中命名为hook-full.import.name.py的模块。每次Analysis检测到一个import时,它都会查找有匹配名称的钩子文件。当找到一个钩子文件时,Analysis将其代码导入Python命名空间。这将导致执行钩子源中的所有顶部语句,例如import语句,全局名称的分配和函数定义。这些语句定义的名称以命名空间属性的形式对Analysis可见。

因此,钩子是一个普通的Python脚本,可以使用所有正常的Python工具。例如,它可以测试sys.version并根据其调整对hiddenimports的分配。PyInstaller安装中有许多钩子,但社区钩子包中可以找到更大的集合。请浏览它们以获取示例。

作为软件包开发人员,您可以在软件包内为PyInstaller提供钩子。这样做的主要好处是,当您的软件包更改时,您可以轻松地采用这些钩子。因此,您的软件包的用户不需要等待PyInstaller可能跟上这些更改。如果PyInstaller和您的软件包为某个模块提供了钩子,则优先使用您的软件包的钩子,但仍可以通过命令行选项–additional-hooks-dir进行覆盖。

您可以通过在软件包中定义一些简单的setuptools入口点来告诉PyInstaller有关其他钩子。因此,请将以下条目添加到您的setup.cfg中:

[options.entry_points]
pyinstaller40 =
hook-dirs = pyi_hooksample.__pyinstaller:get_hook_dirs
tests = pyi_hooksample.__pyinstaller:get_PyInstaller_tests

这定义了两个入口点:

  • pyinstaller40.hook-dirs用于钩子注册。此入点引用将使用不带参数调用的函数。它必须返回一个字符串序列,其中每个元素都提供要搜索用于挂钩的附加绝对路径。这相当于为序列中的每个字符串传递–additional-hooks-dir命令行选项以供PyInstaller使用。在这个例子中,函数是get_hook_dirs()-> List[str]。
  • pyinstaller40.tests用于测试注册。此入点引用将使用不带参数调用的函数。它必须返回一个字符串序列,其中每个元素都提供要搜索用于测试发现的附加绝对路径,可以是目录树或Python源文件。然后将这些路径传递给pytest进行测试发现。这允许通过此软件包和PyInstaller进行测试。在该项目中,函数是get_PyInstaller_tests()-> List[str]。

一个提供PyInstaller钩子和测试的指南的示例项目可在https://github.com/pyinstaller/hooksample中找到。本项目演示了如何定义包括PyInstaller钩子及其钩子的测试以及用于集成到CD/CI测试的示例文件的库。有关此示例项目的详细文档,请访问https://pyinstaller-sample-hook.readthedocs.io/en/latest/。

绝大多数现有的钩子都完全由一个或多个以下全局变量的值分配组成。如果钩子定义了其中任何一个,Analysis将采纳它们的值并将其应用于正在创建的绑定。

  • hiddenimports:模块名称(相对或绝对)的列表,应该是捆绑应用程序的一部分。这具有与–hidden-import命令行选项相同的效果,但它可以包含一个名称列表,并且仅在导入挂钩模块时自动应用。例如:
hiddenimports = ['_gdbm', 'socket','h5py.defs']

hiddenimports是一个绝对模块名称列表,应该不包括在打包的应用程序中。如果一个被排除的模块仅由被hook模块或其子模块引用,则被排除的名称及其子模块将不会成为bundle的一部分。 (如果在源文件中或某个其他模块中明确导入了被排除的名称,它将被保留。)几个hook使用此功能以防止自动添加thetkinter module。例如:

excludedimports = ['tkinter']

2.12.理解PyInstaller Hooks 77

datas是要作为数据与应用程序捆绑的文件列表。列表中的每个条目是包含两个字符串的元组。第一个字符串指定该系统中的文件(或文件“glob”),第二个字符串指定文件在bundle中所需的名称(这与datas = argument中使用的格式相同,请参见_Adding Data Files_)。例如:

datas = [('/usr/share/icons/education_*.png','icons')]

如果需要收集多个目录或嵌套目录,则可以使用PyInstaller.utils.hooks模块中的helper函数来创建此列表(请参见下文),例如:

datas = collect_data_files('submodule1')
datas + = collect_data_files('submodule2')

在极少数情况下,您可能需要应用逻辑以在文件系统中定位特定文件,例如因为文件在不同平台或不同版本下处于不同位置。然后,您可以编写一个hook()函数,如下所述 在The hook(hook_api) Function下。

binaries是要捆绑为二进制文件的文件或目录列表。格式与datas相同(具有指定源和目标的字符串元组)。二进制文件是datas的一种特殊情况,因为PyInstaller将检查每个文件是否依赖于其他动态库。例如:

binaries = [('C:\\ Windows \\ System32 \\ * .dll','dlls')]

许多hooks使用PyInstaller.utils.hooks模块中的小助手来创建此列表(请参见下文):

binaries = collect_dynamic_libs('zmq')

warn_on_missing_hiddenimports是一个布尔标志,指示是否应该生成缺失的隐藏导入(通过hiddenimports设置)警告。默认情况下,缺少的隐藏导入会生成警告,但是单个hooks可以选择退出此行为,方法是将此变量设置为False。例如:

warn_on_missing_hiddenimports = False

module_collection_mode是控制模块的集合模式的设置。该变量的值可以是字符串或字典。

当设置为字符串时,该变量控制被挂起的包/模块的收集模式。有效的值为:

  • ‘pyz’:将编译的字节编译模块收集到嵌入式PYZ归档中。当未指定收集模式时,这是默认行为。如果使用noarchive标志Analysis,则不使用PYZ存档,而pyz collection mode会自动变成pycone。
  • ‘pyc’:将编译的字节编译模块作为外部数据文件收集(与将它们收集到PYZ存档中不同)。
  • ‘py’:将源.py文件作为外部数据文件收集。不要收集编译的字节编译模块。
  • ‘pyz + py’ 或 ‘py + pyz’:将编译的字节编译模块收集到嵌入式PYZ归档中,并将相应的源.py文件作为外部数据文件收集。
    如果启用了noarchive标志,则将编译的字节编译模块作为外部数据文件收集,这会导致由于源文件被放置在其旁边而导致python忽略它们。
    该设置适用于所有子模块和子包,除非被其相应的hook中的设置覆盖。
    或者,该变量可以设置为包含模块/包名称和相应收集模式字符串的字典。这允许一个hook为其主要包和子包指定不同的设置,但也允许为其他包设置设置。当多个hooks为相同的模块名称提供设置时,最终结果取决于hook执行顺序。

第78章。 内容:

例子:
# hook-mypackage.py
# 由于这个包在文件系统上搜索 .py 文件,必须以源代码形式收集……
module_collection_mode ='py'
例子:
# hook-mypackage.py
# 仅收集一个子包/模块作为源代码
# (不创建子包的钩子)。
module_collection_mode = {
'mypackage.src_subpackage ':'py'
}
例子:
# hook-mypackage.py
# 将整个包作为源代码收集,但一个子包除外
# (不创建子包的钩子)。
module_collection_mode = {
'mypackage': 'py',
'mypackage.bin_subpackage':'pyz'
}
例子:
# hook-mypackage.py
# 强制以源代码形式收集其他包。
module_collection_mode = {
'myotherpackage1':'py',
'myotherpackage2':'py'
}
能够从给定的钩子控制其他模块/包的收集模式是为那些钩子提供功能的情况而设计的,这些功能需要那些其他模块以源代码形式收集(例如某些深度学习框架中可用的JIT编译)。但是,通过字节码扫描检测特定的函数导入和调用需要访问模块图,因此需要使用hook_api函数。在这种情况下,可以使用thehook_api对象的set_module_collection_mode方法来修改收集模式,而不是设置全局的hook变量。

2.12.理解PyInstaller的钩子79

2.12.4 PyInstaller.compat中的有用项

提供一些与之前的Python版本向后兼容的各种类和函数。

钩子可以从 PyInstaller.compat中导入以下名称,例如:

from PyInstaller.compat importbase_prefix, is_win

is_py36, is_py37, is_py38, is_py39, is_py310 is_py311
当Python的当前版本至少为3.6、3.7、3.8、3.9或3.10、3.11时,值为True。

is_win
在Windows系统中为True。

is_cygwin
当sys.platform == 'cygwin’时,值为True。

is_darwin
在 macOS 中为True。

is_linux
在任何 GNU/Linux 系统中为True。

is_solar
在Solaris中为True。

is_aix
在AIX中为True。

is_freebsd
在FreeBSD中为True。

is_openbsd
在OpenBSD中为True。

is_venv
在任何虚拟环境(virtualenv或venv)中为True。

base_prefix
字符串,正确的基础Python安装路径,无论安装是本地的还是虚拟的环境。

EXTENSION_SUFFIXES
Python C 扩展名列表。用于在文件夹中查找所有二进制依赖项;参见hook-cryptography.py的示例。

2.12.5 PyInstaller.utils.hooks中的有用项

钩子可以从 PyInstaller.utils.hooks 中导入有用的函数。使用完全限定的导入语句,例如:

from PyInstaller.utils.hooks import collect_data_files, eval_statement

此处列出的函数通常是有用的,并在许多现有的钩子中使用。

exec_statement(_statement_)
在外部生成的解释器中执行单个Python语句,并将结果的标准输出作为字符串返回。
例子:

80第2章 内容:

tk_version = exec_statement("from _tkinter import TK_VERSION; print(TK_VERSION)")
mpl_data_dir = exec_statement("import matplotlib; print(matplotlib.get_data_path())
˓→")
datas = [(mpl_data_dir, "")]

说明

自 v5.0 开始,不再建议使用此函数,而是使用新的 PyInstaller.isolatedmodule。

eval_statement( _statement_ )

在外部生成的解释器中执行单个 Python 语句,并评估其输出(如果有)。
例如:

databases = eval_statement('''
import sqlalchemy.databases
print(sqlalchemy.databases.__all__)
''')
fordb indatabases:
hiddenimports.append("sqlalchemy.databases." + db)

说明

自 v5.0 开始,不再建议使用此函数,而是使用新的 PyInstaller.isolatedmodule。

is_module_satisfies( _requirements_ , _version=None_ , _version_attr='__version__'_ )

测试是否安装了符合 PEP 0440 的要求。
参数

- requirements(str) - 以 _pkg_resources.Requirements.parse()_ 格式表示的要求。
- version(str) - 可选的 PEP 0440 兼容版本(例如,_3.14-rc5_ ),用于替代此模块的当前版本。如果非 _None_ ,则此函数忽略此模块的所有 _setuptools_ 发行版,而是将此版本与传递的要求中嵌入的版本进行比较。这将忽略传递的要求中嵌入的模块名称,从而以健壮的方式比较任意版本。请参见下面的示例。
- version_attr(str) - 此模块定义的版本属性的可选名称,默认为 ___version___。如果此模块存在 _setuptools_ 分发(通常是这样),并且 _version_ 参数为 _None_(通常是这样),则将忽略此参数。
    **返回** 所需验证的布尔结果。
    **返回类型** bool
    **引发**
- AttributeError - 如果此模块不存在 _setuptools_ 分发并且此模块未定义其名称为传递的 _version_attr_ 参数的属性。
- ValueError - 如果传递的规范不符合 pkg资源。_resources_要求语法。

2.12. 理解 PyInstaller 钩子 81

示例

# 假设已安装 PIL 2.9.0、Sphinx 1.3.1 和 SQLAlchemy 0.6。
>>>from PyInstaller.utils.hooks import is_module_satisfies
>>> is_module_satisfies('sphinx >= 1.3.1')
True
>>> is_module_satisfies('sqlalchemy != 0.6')
False
>>> is_module_satisfies('sphinx >= 1.3.1; sqlalchemy != 0.6')
False
# 比较两个任意版本。在这种情况下,模块名称 “sqlalchemy” 被忽略了。
>>> is_module_satisfies('sqlalchemy != 0.6', version='0.5')
True
# 由于提供 PIL 的“pillow”项目通过自定义的 “PILLOW_VERSION” 属性发布其版本
# (而不是标准的“__version__”属性),因此通过传递属性名称作为回退来验证 PIL
# 当未由 setuptools 安装时。由于 PIL 通常是由 setuptools 安装的,因此此
# 可选参数通常会被忽略。
>>> is_module_satisfies('PIL == 2.9.0', version_attr='PILLOW_VERSION')
True
另请参阅:
pkg_resources.Requirements 的语法详细信息。
collect_all( _package_name_ , _include_py_files=True_ , _filter_submodules=None_ , _exclude_datas=None_ ,
_include_datas=None_ , _on_error='warn once'_ )

收集给定包名称的所有内容。
参数

- package_name -可导入的包名称。
- include_py_files - 转发给collect_data_files()。
- filter_submodules - 转发给collect_submodules()。
- exclude_datas - 转发给collect_data_files()。
- include_datas - 转发给collect_data_files()。
- on_error - 转发到collect_submodules()。

返回

元组(datas,binaries,hiddenimports),其中包含:
- 所有数据文件,原始 Python 文件(如果包括 **include_py_files** ),以及包元数据文件夹。
- collect_dynamic_libs() 返回的所有动态库。
- **packagename** 及其依赖项的所有子模块。

返回类型 元组
典型用法:

82 第2章 内容:

datas, binaries, hiddenimports = collect_all('my_module_name')

collect_submodules( package , filter= , on_error=‘warn once’ )
列出给定包的所有子模块。
参数

  • package(str) – 一个可导入的包。
  • filter(Callable[[str], bool]) – 过滤找到的子模块:一个可调用对象,接受一个子模块名称并返回True则包含该子模块。
  • on_error(str) – 当子模块无法导入时采取的操作。可以是:
    - raise:将错误重新抛出并终止构建。
    - warn:将错误降级为警告。
    - warn once:第一个错误发出警告,但忽略所有后续错误以最小化_stderr污染_。这是默认值。
    - ignore:跳过所有错误。不要对任何事情发出警告。
    Return 获取所有子模块以分配给钩子的隐藏导入的列表。
    此函数旨在被钩子脚本使用,而不是由主PyInstaller代码使用。
    例子:
# 收集Sphinx的所有子模块不包含单词``测试``。
hiddenimports = collect_submodules(
"Sphinx",`filter=lambda name:'test' not in name)

版本4.5中的更改:添加on_error参数。

is_module_or_submodule(_name_, _mod_or_submod_)
此辅助函数旨在通过返回True,以集合子模块(collect_submodules())的filter参数使用给定名称是否为模块或mod_or_submod的子模块。

例子

以下排除foo.test和foo.test.one但不排除foo.testifier。
collect_submodules('foo', lambda name: not is_module_or_submodule(name,'foo.test
˓→'))
is_package(_module_name_)

检查Python模块是否真正是包含其他模块的模块或包,而不导入主进程中的任何内容。
参数 module_name(str) – 要检查的模块名称。
Return 如果模块是软件包,则返回True,否则返回False。

collect_data_files(_package_, _include_py_files=False_, _subdir=None_, _excludes=None_, _includes=None_)

此函数生成在包中存储的(source,dest)非Python(即数据)文件的列表。它的输出可以直接分配给钩子脚本中的datas;例如,见hook-sphinx.py。
参数:

  • package参数是指定包名的字符串。

2.12.了解PyInstaller Hooks 83

  • 默认情况下,不会收集所有Python可执行文件(以.py,.pyc等结尾);将
    include_py_files参数设置为True也会收集这些文件。这通常与Python一起使用
    函数(例如pkgutil中的函数)搜索给定目录中的Python可执行文件并将其加载
    作为扩展或插件。
  • 将subdir参数设置为package相对的子目录进行搜索非常有用,当子模块被运行时从缺少__ init__ .py的目录中导入时。
  • excludes参数包含字符串或路径序列。它们提供要从收集的数据文件中排除的文件列表;如果一个目录与提供的模式匹配,则它包含的所有文件也将被排除。所有元素必须是相对路径,相对于提供的包的路径(/如果子目录则为subdir)。
    因此,*.txt仅排除package目录中的.txt文件,而**/ * .txt将排除所有
    package路径和subdir的txt文件。同样,** / __ pycache__将排除所有文件
    包含在任何名为__ pycache__的子目录中。
  • includes功能类似于excludes,但只包括匹配的路径。excludesoverrideincludes:在两个列表中的文件或目录将被排除。
    此功能无法在压缩的Python egg上运行。
    此函数旨在被钩子脚本使用,而不是由主PyInstaller代码使用。

collect_dynamic_libs(_package_, _destdir=None_, _search_patterns =['*.dll','*.dylib','lib*.so']_)
此函数生成在package中存储的动态库文件(源,dest)的列表。其输出可以直接分配给钩子脚本中的binaries。package参数必须是指定包名的字符串。
参数

  • destdir – 应将库放置在./dist/APPNAME的相对路径。
  • search_patterns – 要收集的动态库文件名模式列表。

get_module_file_attribute(package)
获取指定模块或包的绝对路径。
分析期间不得直接导入模块和包。因此,为避免漏洞,此函数在需要导入模块并获取其__ file__属性时使用隔离的子过程。
参数 package(str) – 模块或包的完全限定名称。
Returns 此模块的绝对路径。
Return type str

get_module_attribute(module_name, attr_name)
如果指定模块定义此属性或否则引发_AttributeError,则从指定模块中获取传递属性的字符串值。
由于无法在分析期间直接导入模块,因此此函数会生成导入此模块并返回此模块中此属性的字符串值的子过程。
参数

  • module_name(str) – 此模块的完全限定名称。
  • attr_name(str) – 要检索的此模块中的属性的名称。
    返回 传递属性的字符串值。
    Return type str

84第2章. 内容:

引发AttributeError - 如果未定义此属性。

get_package_paths(package)
给定一个包,返回存储在此计算机上的包的路径,并返回此特定包的路径。例如,如果pkg.subpkg位于/ abs / path / to / python / libs中,则此函数返回(/ abs /路径/ python / libs,/ abs /路径/ python / libs / pkg / subpkg)。
注意:由于向后兼容性问题,此函数仅返回一个包路径及其基本目录。对于具有多个位置的PEP 420命名空间包,仅返回第一个位置。要获取所有包路径,请使用get_all_package_paths函数,并使用package_base_path帮助程序获得相应的基本目录。

copy_metadata(package_name, recursive=False)
收集分发元数据,以便pkg_resources.get_distribution()可以找到它。
该函数返回list应该分配给datas全局变量。这个列表指示PyInstaller将给定包的元数据复制到冷冻应用程序的数据目录中。
参数

  • package_name(str) – 指定应复制元数据的包的名称。
  • recursive(bool) – 如果为True,则收集软件包依赖项的元数据。这使得在冷冻的应用程序内部使用pkg_resources.require(‘package’)变得可能。
    Returns 这应该分配给datas。
    Return type list

示例

>>> from PyInstaller.utils.hooks import copy_metadata
>>> copy_metadata('sphinx')
[('c:\python27\lib\site-packages\Sphinx-1.3.2.dist-info',
'Sphinx-1.3.2.dist-info')]

某些软件包依赖于通过pkg_resources模块访问的元数据文件。通常,PyInstaller不包括这些元数据文件。如果一个软件包在没有这些文件的情况下失败,则可以在钩子文件中使用此功能轻松添加它们到冷冻束中。返回列表中的元组有两个字符串。第一个是此系统中文件夹的完整路径名。第二个只是文件夹的名称。当这些元组添加到datas中时,文件夹将绑定在顶层。
从版本4.3.1开始更改:防止将dist-info元数据文件夹重命名为破解egg-info(参见#3033)。
从版本4.4.0开始更改:添加递归选项。

collect_entry_point(_name_)

收集给定入口点的所有出口商的模块和元数据。
参数 name(str) - 入口点的名称。请检查使用入口点的库的文档以找到其名称。
返回值 应分别分配给数据和hiddenimports的(datas,hiddenimports)对。
对于像pytestorkeyring这样依赖于插件来扩展其行为的库。

2.12.了解PyInstaller钩子85

示例

pytest使用名为“pytest11”的入口点来进行扩展。为了收集所有这些扩展,使用:

datas,hiddenimports = collect_entry_point(“pytest11”)

这些值可以在挂钩中使用或添加到.specfile的datas和hiddenimports参数中。参见使用Spec文件。
从版本4.3开始。

get_homebrew_path(_formula='')

返回所请求的配方的homebrew路径,或在没有参数调用时返回全局前缀。
以字符串形式返回路径,如果找不到,则返回None。

include_or_exclude_file(_filename_, _include_list=None_, _exclude_list=None_)

基于文件名和包含和排除模式列表的通用包含/排除决策函数。
参数

  • filename- 用于包含考虑的文件名。
  • include_list- 包含文件模式列表。
  • exclude_list- 排除文件模式列表。
    返回值 指示文件是否应包含的布尔值。
    如果提供了包含列表,则仅当文件名与包含模式之一匹配(如果提供,则不匹配exclude_list中的任何模式)时返回True。如果未提供include_list,则仅当文件名不匹配任何排除列表中的模式时返回True。如果两个列表都没有提供,则对于任何文件名都返回True。
collect_delvewheel_libs_directory(_package_name_, _libdir_name=None_, _datas=None_, _binaries=None_)

从delvewheel启用的python轮的.libs目录中收集数据文件和二进制文件。这些轮在位于软件包目录旁边的.libs目录中运送共享库,因此不在collect_dynamic_libs()实用程序函数的范围内。
参数

  • package_name- 包的名称(例如scipy)。
  • libdir_name- .libs目录的可选名称(例如scipy.libs)。如果未提供,则将“.libs”添加到package_name中。
  • datas- 需要添加收集的数据文件条目的可选数据列表。组合结果作为输出元组的一部分返回。
  • binaries- 需要添加收集的二进制文件条目的可选二进制文件列表。组合结果作为输出元组的一部分返回。
    返回值 应分别分配给datas和binaries的(datas,binaries)对。
    返回值类型元组

示例
收集属于Windowsscipywheel的scipy.libsdelvewheel目录:

datas,binaries = collect_delvewheel_libs_directory(“scipy”)

当应将收集的条目添加到现有的datas和binaries列表中时,可以使用以下形式以避免使用中间临时变量并将其合并到现有的列表中:

datas,binaries = collect_delvewheel_libs_directory(“scipy”,datas = datas,binaries = binaries)

版本5.6中新增。
Conda支持

用于专门处理Anaconda发行版的帮助程序方法位于PyInstaller.utils.hooks.conda_support中,其设计目的是模仿(虽然是松散的)importlib.metadata包。这些函数从conda-meta目录中的json文件中找到并解析分发元数据。

新版本4.2.0。

如果在Conda环境中运行,则仅在条件子句中包装使用此模块:

from PyInstaller.compat importis_pure_conda

if is_pure_conda:
    from PyInstaller.utils.hooks importconda_support

#代码在此。例如

binaries = conda_support.collect_dynamic_libs(“numpy”)
...

所有包都是用于安装它的_distribution name_引用的,而不是您导入它的_package name_。即,使用distribution(“pillow”)而不是distribution(“PIL”)或使用package_distribution(“PIL”)。

distribution(name)
获取给定分布名称(即,您将conda install)的分布信息。
返回类型分配
package_distribution( name )
获取package 的分发信息(即导入的东西)。
返回类型 Distribution
例如,包 pkg_resources 属于分发 setuptools,其中包含三个 packages。

>>> package_distribution("pkg_resources")
Distribution(name="setuptools",
packages=['easy_install', 'pkg_resources', 'setuptools'])

files( name , dependencies=False , excludes=None )
列出属于一个分发的所有文件。
参数

2.12. 了解 PyInstaller Hooks 87

  • name - 分发的名称。
  • dependencies - 是否递归收集依赖的文件。
  • exclude - 如果 dependencies 为 true,则忽略的分发。
    返回类型 所有属于给定分发的文件名。
    当 dependencies=False 时,这只是一个快捷方式:
conda_support.distribution(name).files

requires( name , strip_versions=False )
列出分发的要求。
参数

  • name(str) - 分发的名称。
  • strip_versions(bool) - 仅列出名称,而不是版本约束。
    返回类型 List[str]
    返回值 一个分发名称列表。

class Distribution( json_path )
Conda 分发的存储桶类表示。
这个类导出以下属性:
变量

  • name - 分发的名称。
  • version - 分发的版本。
  • files - 包含在此分发中的所有文件名为 PackagePath。
  • dependencies - 此分发依赖的其他分发的名称(已删除版本约束)。
  • packages - 包含在此分发中的可导入包的名称。
    此类不打算直接由用户构造。相反,使用 distribution() 或 package_distribution() 为您提供一个。

class PackagePath( *args )
相对于 Conda 根目录(sys.prefix)的文件名。
即使在非 Posix 操作系统上也继承自 pathlib.PurePosixPath。要转换为指向实际文件的 pathlib.Path,请使用 locate() 方法。
locate()
返回此路径对应于指向文件的 path-like 对象。

walk_dependency_tree( initial , excludes=None )
收集分发及其所有直接和间接依赖项。
参数

  • initial - 要收集的分发名称。
  • excludes - 要排除的分发。
    返回值 一个 {name: distribution} 映射,其中分发是 conda_support.distribution(name) 的输出。

第 88 章。目录:

collect_dynamic_libs( name , dest=‘.’ , dependencies=True , excludes=None )
收集分发 name 的 DLL。
参数

  • name - 分发的项目名称。
  • dest - 目标路径,默认为’.'。
  • dependencies - 递归收集依赖的库(建议)。
  • excludes - 要跳过的依赖分发,默认为 None。
    返回值 PyInstaller 的 (source, dest) 格式中的 DLL 列表。
    这仅从 Conda 的 sharedlib(Unix) 或 Library/bin(Windows) 文件夹中收集库。要从分发的安装中收集,请使用常规 PyInstaller.utils.hooks.collect_dynamic_libs()。

2.12.6 使用 PyInstaller.isolated 进行子进程隔离

PyInstaller 钩子通常需要导入它们编写的包,但这样做可能以某种方式操纵 globals,例如 sys.path 或 os.environ,影响构建。例如,在 Windows 上,Qt 的二进制文件被添加到并通过 PATH 加载,以这样的方式,如果您在一个会话中引入多个 Qt 变体,则不能保证每个变体将获得哪个变体的二进制文件!

为了解决这个问题,PyInstaller 在孤立的 Python 子进程中执行任何此类任务,并在钩子中使用PyInstaller.isolated子模块进行操作。

from PyInstaller import isolated

此子模块提供:

  • isolated.call() 调用在孤立的 Python 程序中执行函数。
  • @isolated 装饰器将函数标记为始终在孤立状态下调用。
  • isolated.Python() 以单个 Python 子实例高效调用许多函数。

call( function , *args , **kwargs )
使用单独的子 Python 调用函数并检索其返回值。
参数

  • function - 要发送和调用的函数。
  • *args -
  • **kwargs - 发送到函数的位置和关键字参数。必须是简单的内置类型 - 不是自定义类。
    返回值 函数的返回值。再次说明,这些必须是可以通过marshal序列化的基本类型。
    dumps()。
    抛出 RuntimeError - 在被孤立进程中发生的任何异常都会被捕获并在父进程中重新引发。
    要使用,请定义一个返回您想要查找的信息的函数。它所需的任何导入都必须发生在函数体中。例如,要安全地检查 matplotlib.get_data_path() 的输出,请使用:
# 定义一个在孤立状态下运行的函数。
def get_matplotlib_data_path():
    import matplotlib
# 示例,调用 get_matplotlib_data_path 函数
result = isolated.call(get_matplotlib_data_path)

第 2.12 节。了解 PyInstaller Hooks 89

(接上一页)
返回matplotlib的数据路径
# 使用 isolated.call() 方法调用。
get_matplotlib_data_path = isolated.call(matplotlib_data_path)

对于像上面那样不带参数的单次使用函数,可以稍微滥用修饰器语法来定义并一次性执行函数。

>>> @isolated.call
... def matplotlib_data_dir():
...     import matplotlib
...     return matplotlib.get_data_path()
>>> matplotlib_data_dir
'/home/brenainn/.pyenv/versions/3.9.6/lib/python3.9/site-packages/matplotlib/mpl-data'

函数可以接受位置和关键字参数并返回大多数通用的Python数据类型。

>>> def echo_parameters(*args, **kwargs):
...     return args, kwargs
>>> isolated.call(echo_parameters, 1, 2, 3)
((1, 2, 3), {})
>>> isolated.call(echo_parameters, foo=["bar"])
((), {'foo': ['bar']})
说明
要使一个函数在孤立环境中表现出不同的行为,请检查__isolated__全局变量。
if globals().get("__isolated__", False):
# 我们现在在一个子进程里面。
...
else:
# 这是主进程。
...
decorate(_function_)
装饰一个函数,使其始终在孤立的子进程中调用。

示例
使用方法是编写一个函数,然后在函数前添加@isolated.decorate。

@isolated.decorate
def add_1(x):
    '''Add 1 tox, displaying the current process ID.'''
    import os
    print(f"Process {os.getpid()}: Adding 1 to{x}.")
    return x + 1

结果add_1()函数现在可以像正常函数一样调用,它将自动使用一个子进程。
90 第2章. 目录:

>>> add_1(4)
Process 4920: Adding 1 to 4.
5
>>> add_1(13.2)
Process 4928: Adding 1 to 13.2.14.2

类Python(_strict_mode=None_)
启动并连接到一个单独的Python子进程。
这是本模块提供的最低级公共API。直接使用该类的优点是可以在单个子进程中评估多个函数,使其比多次调用call()快。
strict_mode参数控制在子进程无法关闭时的行为。如果启用了严格模式,则会引发错误,否则只记录警告。如果strict_mode的值为None,则使用PyInstaller.compat.strict_collect_mode的值(这取决于PYINSTALLER_STRICT_COLLECT_MODE环境变量)。

示例
要调用一些预定义函数x=foo(),y=bar("numpy")z=bazz(some_flag=True),所有使用相同的孤立子进程,请使用:

with isolated.Python() as child:
    x=child.call(foo)
    y=child.call(bar,"numpy")
    z=child.call(bazz,some_flag=True)
call( function , *args , **kwargs )
在子 Python 中调用函数。检索其返回值。该方法的用法与 call() 函数完全相同。

2.12.7 the hook(hook_api) Function

除了设置全局值之外,挂钩还可以定义函数 hook(hook_api)。只有在挂钩需要应用复杂逻辑或在源机器上进行复杂搜索时,才需要使用hook()函数。

分析对象调用该函数,并将其传递给hook_api对象,该对象具有以下不可变属性:

name:引起挂钩调用的模块的完全限定名称,例如six.moves.tkinter。

file:模块的绝对路径。如果它是:

  • 标准(而不是命名空间)包,则是该包目录的绝对路径。
  • 命名空间(而不是标准)包,则是抽象占位符-。
  • 非包模块或C扩展,则是相应文件的绝对路径。

path:如果它是包,它是由该模块所有目录的绝对路径组成的列表,否则为 None。通常,列表仅包含包目录的绝对路径。

co:由__file__中的内容编译而成的代码对象(例如,通过内置的compile())。

analysis:加载钩子的Analysis对象。

Thehook_apiobject还提供了以下方法:

2.12 理解PyInstaller Hooks 91

add_imports(* names):Thenames参数可以是单个字符串或字符串列表,用于给出要导入的模块的完全限定名称。这具有与将名称添加到hiddenimports全局变量中相同的效果。

add_datas(tuple_list):Thetuple_list参数具有与datas全局变量使用的格式相同。此调用会将项目添加到该列表中。

add_binaries(tuple_list):Thetuple_list参数具有binaries全局变量使用的格式。此调用会将项目添加到该列表中。

set_module_collection_mode(name,mode):为指定的包/模块名称设置包集合模式。 mode的有效值为:“pyz”,“pyc”,“py”,“pyz + py”,“py + pyz”和None。“None”会在给定包/模块名称的上下文的当前挂钩内清除/重置设置!可以为挂钩的包,其子模块或子包,或其他包设置集合模式。如果name为None,则替换为挂钩包/模块名称。

hook()函数可以使用hook_api的上述方法添加、移除或更改包含的文件。或者,它可以简单地在四个全局变量中设置值,因为这些变量将在hook()返回后进行检查。

钩子可以通过在spec文件中调用get_hook_config()函数访问给定的钩子config参数中给出的用户参数。

get_hook_config(hook_api,module_name,key):获取钩子的用户设置。
参数

  • module_name(str):键设置所属的模块/包名称。
  • key(str):配置的关键字。
    返回值 配置的值。如果未设置,则为None。
    get_hook_config函数将在Analysis.hooksconfigdict中查找设置。 可以以以下形式将钩子设置添加到.spec文件中:
a = Analysis(["my-app.py"]...
hooksconfig = {
"gi": {
"icons": ["Adwaita"],
"themes": ["Adwaita"],
"languages": ["en_GB", "zh_CN"],
},
},
...

2.12.8 pre_find_module_path(pfmp_api)方法

您可以使用特殊函数pre_find_module_path(pfmp_api)编写钩子。当Analysis首次看到已挂钩的模块名称时,将调用此方法,而在此之前尚未定位到该模块或包的路径(因此称为“预查找模块路径”)。

仅当将此类钩子存储在名为pre_find_module_path的子文件夹中时,Hooks才能识别它们,这些子文件夹位于分布式钩子文件夹或additional-hooks-dir文件夹中。对于同一模块,您可以同时拥有常规钩子和此类钩子。例如,PyInstaller包括ahooks/hook-distutils.py以及ahooks/pre_find_module_path/hook-distutils.py。

传递的pfmp_api对象具有以下不可变属性:

第92章 内容:

module_name:字符串,已挂接模块的完全限定名称。

pfmp_api对象具有一个可变属性search_dirs。这是一个字符串列表,用于指定将搜索挂钩模块的绝对路径或路径。列表中的路径将按顺序搜索。pre_find_module_path()函数可以替换或更改pfmp_api.search_dirs的内容。

从pre_find_module_path()返回后,search_dir的内容将用于查找和分析该模块。

有关用法示例,请参见hooks/pre_find_module_path/hook-distutils.py文件。当PyInstaller在虚拟环境中执行时,它使用此方法重定向对distutils的搜索。

2.12.9 pre_safe_import_module(psim_api)方法

您可以使用特殊函数pre_safe_import_module(psim_api)编写钩子。已找到已挂钩的模块,但在将其及其递归导入的所有内容添加到已导入模块的“图形”之前,将调用此方法。仅在以下情况下使用先安全导入钩子:

  • 脚本导入包.dynamic-name
  • 包存在
  • 但是,在编译时没有dynamic-name模块存在(它将在运行时以某种方式定义)

使用此类钩子将动态生成的名称告知PyInstaller。 PyInstaller不会尝试查找动态名称,失败并将它们报告为丢失。但是,如果这些名称有常规挂钩,它们将被调用。

仅当将此类钩子存储在名为pre_safe_import_module的子文件夹中时,Hooks才能识别它们,这些子文件夹位于分布式钩子文件夹或additional-hooks-dir文件夹中(有关示例,请参见分布式hooks/pre_safe_import_module文件夹)。

您可以同时拥有常规钩子和此类钩子,用于同一模块。例如,分布式系统具有ahooks/hook-gi.repository.GLib.py和ahooks/pre_safe_import_module/hook-gi.repository.GLib.py。

传递的psim_api对象提供以下属性,所有属性都是不可变的(尝试更改其中一个会引发异常):

module_basename:字符串,已挂接模块的未定名称,例如text。

module_name:字符串,已挂接模块的完全限定名称,例如email.mime.text。

module_graph:代表到目前为止处理的所有导入的模块图。

parent_package:如果该模块是其包的顶级模块,则为None。否则,表示导入顶级模块的图形节点。

最后两个item,module_graph和parent_package,与module-graph相关,module-graph是PyInstaller用于记录所有导入的内部数据结构。通常,您不需要了解module-graph。

psim_api对象还提供以下方法:

add_runtime_module(fully_qualified_name):使用此方法添加一个函数定义的模块,其名称可能不会出现在源代码中,因为它在运行时动态定义。这对于将模块通知PyInstaller并避免误导性警告很有用。一种典型用法是应用psim_api中的名称:

psim_api.add_runtime_module(psim_api.module_name)

add_alias_module(real_module_name,alias_module_name):real_module_name是现有的模块的完全限定名称,可以按名称导入(如果尚未导入,则将其添加到图形中)。alias_module_name是可能在源文件中引用的名称

2.12. 理解 PyInstaller 的 Hooks 93

但应该被视为真正的模块名称。此方法确保如果 PyInstaller 处理alias_module_name的导入,将使用real_module_name。

append_package_path(directory) 钩子可以使用此方法将要由 PyInstaller 搜索的软件包路径添加到 PyInstaller,通常是导入模块如果模块被正常执行,那么该路径将被动态添加到路径。directory是一个字符串,是要添加到__path__属性的路径名。

2.13 钩子配置选项

从版本4.4开始,PyInstaller 实现了一种机制,用于向钩子传递配置选项。撰写本文时,此功能仅在_.spec文件_中受支持,并没有相应的命令行接口。

钩子配置选项由一个传递给具有hooksconfig参数的 Analysis对象的字典组成。字典的键表示_hook identifiers_,而值是钩子特定键和值的字典,对应于钩子设置:

a = Analysis(
["program.py"],
...,
hooksconfig={
"some_hook_id": {
"foo": ["entry1", "entry2"],
"bar": 42,
"enable_x":True,
},
"another_hook_id": {
"baz": "value",
},
},
...,
)

2.13.1 支持的钩子和选项

本节列出了实现配置选项支持的钩子。对于每个钩子(或钩子组),我们提供_hook identifier_和支持选项列表。

GObject 内省(gi)钩子

在_gi_钩子标识符下传递的选项控制与 GObject 内省(即,hook-gi.*)相关的各种钩子中的 GLib/Gtk 资源(主题、图标、翻译)的收集。

在 Linux 上冻结基于Gtk3的应用程序时,它们特别有用,因为它们允许用户限制从系统 /usr/share 目录收集的主题和图标数量。

钩子标识符: gi

选项

  • languages[字符串列表]: 应收集翻译的语言环境列表(例如,en_US)。默认情况下,gihooks 收集所有可用的翻译。
  • icons[字符串列表]: 应收集的图标主题列表(例如,Adwaita)。默认情况下,gihooks 收集所有可用的图标主题。
  • themes[字符串列表]: 应收集的 Gtk 主题列表(例如,Adwaita)。默认情况下,gihooks 收集所有可用的图标主题。
  • module-versions[ 版本字符串的字典 ]:要使用的 gi 模块的版本。例如,键为’GtkSource’,值为’4’,则将使用 gtksourceview4。

示例

仅收集Adwaita主题和图标,将收集的翻译限制为英式英语和简体中文,并使用Gtk版本3.0和GtkSource版本4:

a = Analysis(
["my-gtk-app.py"],
...,
hooksconfig={
"gi": {
"icons": ["Adwaita"],
"themes": ["Adwaita"],
"languages": ["en_GB", "zh_CN"],
"module-versions": {
"Gtk": "3.0",
"GtkSource": "4",
},
},
},
...,
)

注意: 目前,module-versions 配置仅适用于GtkSource 、Gtk 和 Gdk。

GStreamer (gi.repository.Gst) 钩子

GStreamer 的收集受到通用 gi 钩子配置(例如,由 languages 选项控制的翻译文件的收集)和名为gstreamer^1的特殊钩子配置的控制,该特殊钩子配置控制 GStreamer 插件的收集。

GStreamer 框架具有许多插件,通常作为单独的软件包安装 (gstreamer-plugins-base、gstreamer-plugins-good、gstreamer-plugins-bad 和 gstreamer-plugins-ugly,在打包系统之间的名称可能会有所不同)。默认情况下,PyInstaller 收集 所有 可用插件及其二进制依赖项;因此,在构建环境中安装所有 GStreamer 插件可能会导致收集许多不必要的插件,并由于单个插件和底层共享库的复杂依赖关系而导致冻结的应用程序大小增加。

钩子标识符: gstreamer?

选项

  • include_plugins[ 字符串列表 ]:应包含在冻结应用程序中的插件名称列表。指定 include 列表隐含地排除未出现在列表中的所有插件。
  • exclude_plugins[ 字符串列表 ]:应从冻结应用程序中排除的插件名称列表。如果存在 include 列表,则在 apply include 列表之后 apply exclude 列表;否则,exclude 列表适用于所有可用插件。

(^1) 虽然钩子称为 gi.repository.Gst,但选择与 Gstreamer 相关的选项的标识符选择简单的gstreamer。

2.13. 钩子配置选项 95

包含和排除列表都期望基础插件名称(例如,audioparsers、matroska、x264、flac)。在内部,每个名称都转换为模式(例如, ‘**/flac.’),并使用 fnmatch 根据实际的插件文件名进行匹配。因此,也可以在插件名称中包含通配符(*)。

基本示例:排除不需要的插件

排除 OpenCV GStreamer 插件,防止将 OpenCV 共享库引入冻结的应用程序。

a = Analysis(
["my-gstreamer-app.py"],
...,
hooksconfig={
"gstreamer": {
"exclude_plugins": [
"opencv",
],
},
},
...,
)

高级示例:仅包括特定的插件

当优化冻结的应用程序大小时,显式包含实际上应用程序需要的子集插件通常更有效。

考虑以下简单的播放器应用程序:

# audio_player.py
import sys
import os

import gi
gi.require_version('Gst','1.0')
from gi.repository importGLib, Gst

if len(sys.argv) != 2:
print(f"Usage:{sys.argv[0]} ")
sys.exit(-1)

filename = os.path.abspath(sys.argv[1])
if notos.path.isfile(filename):
print(f"Input file{filename}does not exist!")
sys.exit(-1)

Gst.init(sys.argv)
mainloop = GLib.MainLoop()

playbin = Gst.ElementFactory.make("playbin", "player")
playbin.set_property('uri', Gst.filename_to_uri(filename))
playbin.set_property('volume', 0.2)
playbin.set_state(Gst.State.PLAYING)

mainloop.run()

(^2)还可以避免意外指定插件前缀,该前缀通常为_libgst_,但可能是_gst_,具体取决于用于构建GStreamer的工具链。

第96章 2. 内容:

假设虽然应用程序使用通用的playbinandplayerelements,但我们打算冻结应用程序仅播放音频文件。在这种情况下,我们可以如下限制收集的插件:

# 用于在Linux 和Windows上播放FLAC(和可能一些其它音频文件)的gstreamer插件列表,并未完全优化。
gst_include_plugins = [
# gstreamer
"coreelements",
# gstreamer-plugins-base
"alsa", # Linux audio output
"audioconvert",
"audiomixer",
"audiorate",
"audioresample",
"ogg",
"playback",
"rawparse",
"typefindfunctions",
"volume",
"vorbis",
# gstreamer-plugins-good
"audioparsers",
"auparse",
"autodetect",
"directsound",# Windows audio output
"flac",
"id3demux",
"lame",
"mpg123",
"osxaudio", # macOS audio output
"pulseaudio", # Linux audio output
"replaygain",
"speex",
"taglib",
"twolame",
"wavparse",
# gstreamer-plugins-bad
"wasapi", # Windows audio output
]

a = Analysis(
["audio_player.py"],
...,
hooksconfig={
"gstreamer": {
"include_plugins": gst_include_plugins,
},
},
...,
)

确定需要收集哪些插件可能需要对GStreamer管道及其插件系统有很好的了解,并可能导致进行几次测试迭代,以查看所需的多媒体功能是否按预期工作。不幸的是,当涉及像这样使用插件系统的应用程序时,优化应用程序大小并没有免费的午餐。请记住,除了明显命名的插件(例如与FLAC相关的功能flac),您可能还需要收集至少一些来自gstreamer本身的插件(例如coreelements)以及至少一些来自gstreamer-plugins-base。

Matplotlib钩子

用于matplotlib包的钩子允许用户通过backendsoption在matplotlib标识符下控制后端收集行为,如下所述。

**钩子标识符:**matplotlib

选项

  • backends[字符串_或_字符串列表]:后端选择方法或要收集的后端名称。有效的字符串值:“auto”,“all”或人类可读的后端名称(例如’TkAgg’)。要指定要收集的多个后端,请使用字符串列表(例如[‘TkAgg’, ‘Qt5Agg’])。

后端选择过程

如果backendsoption设置为“auto”(或未指定),则钩子通过扫描代码格式matplotlib.use() 函数调用,收集字面参数,进行所使用后端的自动检测。例如,在代码中使用matplotlib.use(‘TkAgg’)将导致收集TkAgg后端。如果未找到此类调用,则将默认后端确定为第一个可导入的基于GUI 的后端,使用与matplotlib.get_backend() 和matplotlib.pyplot.switch_backend()函数内部使用的相同优先级列表:[‘MacOSX’, ‘Qt5Agg’, ‘Gtk3Agg’, ‘TkAgg’, ‘WxAgg’]。如果没有可导入的GUI后端,则收集无头的’Agg’。

注意: 由于字节码扫描方法的局限性,仅特定形式的matplotlib.use() 调用可以自动检测。必须将后端指定为字符串文字(而不是通过变量传递)。第二个可选参数force也可以被指定,但它也必须是文字,而且不能作为关键字参数指定。

import matplotlib

matplotlib.use('TkAgg') # 被检测到
matplotlib.use('TkAgg', False) # 被检测到

backend ='TkAgg'
matplotlib.use(backend) # 没有被检测到

matplotlib.use('TkAgg', force=False) # 没有被检测到

除了matplotlib模块名称外,其常见别名mpl也可以被识别:

import matplotlib as mpl
mpl.use('TkAgg') # 被检测到

从模块导入函数也应该有效:

from matplotlib import use
use('TkAgg') # 被检测到

如果backendsoption设置为’all’,则选择所有(可导入的)后端,这对应于PyInstaller 4.x和早期版本的行为。可导入后端的列表取决于环境中安装的包;例如,如果安装了PyQt5或PySide2包中的任一包,则Qt5Agg后端将变得可导入。

否则,backendsoption的值将被视为后端名称(如果是字符串)或后端名称列表(如果是列表)。对于用户提供的后端名称,不执行其他验证;无论它们是否可导入,都会收集后端。

示例

a = Analysis(
["my-matplotlib-app.py"],
...,
hooksconfig={
"matplotlib": {
"backends": "auto", # 自动检测;默认行为
# "backends": "all", # 收集所有后端
# "backends": "TkAgg", # 收集特定的后端
# "backends": ["TkAgg", "Qt5Agg"], # 收集多个后端
},
},
...,
)

注意: Qt5Agg后端有条件地导入PyQt5和PySide2包。因此,如果两者都安装在您的环境中,则PyInstaller最终将收集两者。除了增加冻结应用程序的大小外,这还可能导致收集的共享库版本之间发生冲突。为了防止这种情况,请使用–exclude-module选项来排除其中一个包(即–exclude-module PyQt5 或–exclude-module PySide2)。

2.13.2 添加钩子选项

实现对钩子选项的支持需要访问hook_api对象,而该对象仅在hook实现了hook_api函数时可用(如此处所述)。

可以使用get_hook_config()函数获取钩子配置选项的值:

# hook-mypackage.py
from PyInstaller.utils.hooks import get_hook_config

# 与hook选项无关的处理,使用全局hook值
binaries, datas, hiddenimports = ...

# 收集额外数据
def hook(hook_api):
# 布尔选项'collect_extra_data'
if get_hook_config(hook_api,'mypackage', 'collect_extra_data'):
extra_datas = ... # 收集额外数据
hook_api.add_datas(extra_datas)

实现了钩子中的选项处理后,请在“支持的钩子和选项”下添加一个文档部分,以通知用户该选项的可用性及其值的含义。

上述钩子示例允许用户通过在_.spec file_中设置相应选项来切换从mypackage收集的额外数据:

a = Analysis(
["program-using-mypackage.py"],
...,
hooksconfig={
"mypackage": {
"collect_extra_data":True,
},
},
...,
)

2.14 构建引导程序

PyInstaller在发布文件夹的bootloader文件夹中为某些平台提供预编译的bootloader。如果当前平台(操作系统和字长)没有预编译的bootloader,pip设置将尝试构建一个。

如果您的平台没有预编译的bootloader,或者您想修改bootloader源代码,则需要构建bootloader。为此,请执行以下操作:

  • 下载并安装Python,这是运行waf所必需的。
  • 从我们的GitHub存储库克隆或下载源代码。
  • 将目录更改为您克隆或解压缩源代码的文件夹。
  • 进入 bootloader并用以下方式制作bootloader:python ./waf all。
  • 通过运行(部分)测试套件 ref:_running-the-test-suite_来测试构建。

这将为您当前的平台生成引导加载程序可执行文件(当然,对于Windows,这些文件将具有.exe扩展名):

  • …/PyInstaller/bootloader/OS_ARCH/run,
  • …/PyInstaller/bootloader/OS_ARCH/run_d,
  • …/PyInstaller/bootloader/OS_ARCH/runw(仅适用于macOS和Windows),以及
  • …/PyInstaller/bootloader/OS_ARCH/runw_d(仅适用于macOS和Windows)。

引导加载程序架构默认为机器架构,但可以使用–target-arch选项更改,前提是安装了适当的编译器和开发文件。例如,在64位机器上构建32位引导加载程序:

python ./waf all --target-arch=32bit

如果出现错误,请阅读接下来的详细说明,然后寻求技术帮助。

通过设置环境变量PYINSTALLER_COMPILE_BOOTLOADER,pip设置将尝试为您的平台构建引导加载程序,即使已经存在。

支持的平台有:

  • GNU/Linux(使用gcc)
  • Windows(使用Visual C++(VS2015或更高版本)或MinGW的gcc)。
  • macOS(使用clang)

贡献平台有:

  • AIX(使用gcc或xlc)
  • HP-UX(使用gcc或xlc)
  • Solaris

有关交叉构建的更多信息,请阅读以下内容并注意Vagrantfile中提供的虚拟机部分。

2.14.1针对GNU/Linux的构建

开发工具

为了构建引导加载程序,您需要一个开发环境。您可以运行以下命令安装所需的所有内容:

  • 在Debian或类似的Ubuntu系统上:
sudo apt-get install build-essential zlib1g-dev
  • 在Fedora、RedHat和派生系统上:
sudo yum groupinstall "Development Tools"
sudo yum install zlib-devel

请参阅发行版的文档以获取其他发行版的信息。

现在,您可以按照上面的方法构建引导加载程序。

或者,您可能想使用Vagrantfile提供的_linux64_ build-guest(请参见下文)。

构建符合Linux标准基准(LSB)的二进制文件(可选)

默认情况下,GNU/Linux上的引导加载程序是”普通“的非LSB二进制文件,对于所有GNU/Linux发行版都应该可以正常工作。

如果出于某种原因您想构建符合Linux标准基准(LSB)的二进制文件,则可以通过在waf命令行中指定–lsb来执行此操作,如下所示:

python ./waf distclean all --lsb

成功构建引导程序需要LSB版本4.0。有关与LSB构建相关的其他选项,请参阅python ./waf --help。

(^1)Linux标准基准(LSB)是一组开放标准,应在GNU/Linux发行版之间增加兼容性。不幸的是,它没有被广泛采用,并且Debian和Ubuntu在2015年秋季放弃了对LSB的支持。因此,PyInstaller引导加载程序不再作为LSB二进制文件提供。

2.14. 构建引导加载程序101

2.14.2构建macOS

在macOS上,请安装Xcode,Apple的用于开发macOS软件的工具套件。您可以安装并使用Xcode的命令行工具,而不必安装完整的_Xcode__包。安装任一项都将提供_clang__编译器。

如果工具链支持universal2二进制文件,则64位引导加载程序默认情况下将构建为支持x86_64和arm64架构的universal2 fat二进制文件。这需要较新的_Xcode__(12.2或更高版本)。在缺乏对universal2二进制文件支持的旧工具链上,将构建单一的x86_64 thin引导加载程序。可以通过将__universal2__或__no-universal2__标志传递给waf build命令来控制此行为。如果尝试使用__universal2__标志和不支持universal2二进制文件的工具链,则会导致配置错误。

no-universal2__标志将目标架构未指定,使结果可执行文件的架构为C编译器的默认值(几乎肯定是构建机器的架构)。如果要构建任一架构的thin可执行文件,请使用__no-universal2__标志,然后可选择通过CC环境变量覆盖编译器并添加-arch__标志。

构建一个thin本机可执行文件:

python waf --no-universal2 all

构建一个thin,x86_64可执行文件(无论构建机器的架构如何):

CC=‘clang -arch=x86_64’ python waf --no-universal2 all

构建一个thin,arm64可执行文件(无论构建机器的架构如何):

CC='clang -arch=arm64’python waf --no-universal2 all

默认情况下,构建脚本针对macOS 10.13,可以通过导出MACOSX_DEPLOYMENT_TARGET环境变量来覆盖。

针对macOS的交叉构建

对于macOS的交叉编译,您需要Clang/LLVM编译器、cctools (ld、lipo 等) 和OSX SDK。
Clang/LLVM 默认是一个交叉编译器,并且几乎可在每个GNU/Linux发行版上使用,因此您只需要一个正确版本的cctools和macOS SDK 即可。

获取它们很容易,只需做一次,然后将结果传输到构建系统中。然后,构建系统可以是正常的(比较新的)GNU/Linux系统^2

(^2) 请注意,为了避免问题,您用于准备步骤的系统应具有与构建系统相同的架构(并且可能还有相同的GNU/Linux发行版版本)。
102 第二章. 内容:

准备工作:获取SDK和构建工具

为了准备SDK和构建cctools,我们使用了OS X Cross工具链中非常有用的脚本。如果您对详情感兴趣以及OS X Cross提供的其他功能,请参阅其主页。

为了避免您阅读OSXCross的文档,我们准备了一份虚拟机定义,可以执行所有所需步骤。如果您感兴趣获得精确的命令,请参考Vagrantfile中的packages_osxcross_debianoid,prepare_osxcross_debianiod和build_osxcross。

请按照以下步骤操作:

1.下载Xcode 12.2或更高版本的命令行工具。您需要一个_Apple ID_来搜索和下载文件;如果您还没有,则可以免费注册。
请确保您遵守相应软件包的许可证。
2.将已下载的_.dmg_文件保存到bootloader/_sdks/osx/Xcode_tools.dmg。
3.使用Vagrantfile自动构建SDK和工具:

vagrant up build-osxcross && vagrant halt build-osxcross
这将创建bootloader/_sdks/osx/osxcross.tar.xz文件,然后安装到构建系统中。
如果由于某种原因失败,请尝试运行vagrant provision build-osxcross。

4.此虚拟机不再使用,您现在可以使用vagrant destroy build-osxcross进行丢弃。

构建引导程序

同样地,使用Vagrantfile自动构建macOS引导程序:

export TARGET=OSX #让Vagrantfile生成macOS平台的引导程序
vagrant up linux64 && vagrant halt linux

这将在*…/PyInstaller/bootloader/Darwin-*/中创建引导程序。

如果由于某种原因失败,请尝试运行vagrant provision linux64。

3.此虚拟机不再使用,您现在可以使用:

vagrant destroy build-osxcross

4.如果您已经完成了macOS引导程序的生成,则再次取消设定_TARGET_:

unset TARGET

如果您不想使用Vagrant文件提供的构建客户机,请执行以下步骤(请参见Vagrantfile中的build_bootloader_target_osx):

mkdir -p ~/osxcross
tar -C ~/osxcross --xz -xf /vagrant/sdks/osx/osxcross.tar.xz
PATH=~/osxcross/bin/:$PATH
python ./waf all CC=x86_64-apple-darwin15-clang
python ./waf all CC=i386-apple-darwin15-clang

2.14. 构建引导程序103

2.14.3 构建Windows引导程序

PyInstaller提供的预编译引导程序是自包含静态可执行文件,对使用的Python版本没有限制。

当您自己构建引导程序时,必须在以下三个选项之间仔细选择:

1.使用Visual Studio C++编译器。
这允许创建自包含静态可执行文件,可用于所有Python版本。这就是为什么随PyInstaller提供的引导程序是使用Visual Studio C++编译器构建的原因。
需要Visual Studio 2015或更高版本。
2.使用MinGW-w64套件。
这允许创建更小的,动态链接的可执行文件,但需要使用与编译Python所使用的同一级别的Visual Studio^3。因此,此引导程序将绑定到特定版本的Python。
原因是,与Unix样系统不同,Windows不提供系统标准C库,而是将其留给编译器。但Mingw-w64没有标准C库。它链接到msvcrt.dll,这在许多Windows安装中存在-但不保证存在。
3.使用cygwin和MinGW。
这将为cygwin创建可执行文件,而不是用于’普通’Windows。

在所有情况下,您可能希望

-设置路径以包含Python,例如设置PATH=%PATH%;C:\python35,
-窥探Vagrantfile或…/appveyor.yml以了解我们如何构建。

您还可以为cygwin构建引导程序。

使用Visual Studio C++构建

-使用我们的_wscript_文件时,您无需运行vcvarsall.bat以在VC++安装和目标架构之间’切换’环境。实际的C++版本无关紧要,使用–target-arch=选项选择目标架构即可。
-如果您没有为其他工作使用Visual Studio,那么仅安装独立的C++构建工具可能是最佳选择,因为它避免了将您不需要的东西充斥在系统中(并节省了非常多的安装时间)。

提示:我们建议使用chocolatey软件包管理器安装build-tools软件。初看起来像过载,但这是安装
C++构建工具的最简单方法。这涉及在管理模式下的两行代码:
...如chocolatey首页上所述的一键安装
choco install -y python3 visualstudio2019-workload-vctools
  • 有用的链接:
    - 微软 Visual C++ Build-Tools 2015
    - 微软用于 Visual Studio 2017 的 Build-Tools。

安装C++构建工具后,您可以按照上述方法构建引导程序。

(^3) 这个描述似乎不准确。我应该依赖于C++运行时库。如果你了解细节,请提交一个问题。
第104章 第2节 内容:

使用MinGW-w64构建

请注意上面提到的限制。

如果Visual Studio不方便,您可以从以下位置之一下载并安装MinGW发行版:

  • MinGW-w64需要使用gcc 4.4及以上版本。
  • TDM-GCC- MinGW(未使用)和MinGW-w64安装程序

注意:在Windows上,使用MinGW-w64时,请将PATH_TO_MINGW_BIN添加到系统PATH。变量。在构建引导程序之前运行:

set PATH = C:\ MinGW \ bin;%PATH%

现在,您可以按照上面示例的方式构建引导程序。如果您已经安装了Visual C ++和MinGW,则可能需要添加runpython ./waf --gcc all。

使用cygwin和MinGW构建

请注意,这将创建适用于cygwin的可执行文件,而不是适用于“普通”Windows的可执行文件。

使用cygwin的setup.exe安装_python_和_mingw__。

现在,您可以按照上面示例的方式构建引导程序。

2.14.4构建AIX

-默认情况下,AIX构建32位可执行文件。
-对于64位可执行文件,请设置环境变量OBJECT_MODE。

如果Python被构建为64位可执行文件,则处理二进制文件(例如.o和.a)的AIX实用程序可能需要标志-X64。而不是为每个命令提供此标志,提供此设置的首选方式是使用环境变量OBJECT_MODE。根据Python是32位还是64位可执行文件构建,您可能需要设置或取消设置环境变量OBJECT_MODE。

可以使用以下命令确定大小:

$ python -c“import sys; print(sys.maxsize <= 2**32)”

当答案为True(如上所述)时,Python构建为32位可执行文件。

使用32位Python可执行文件时,请按以下方式进行操作:

撤消OBJECT_MODE
./waf configure all

使用64位Python可执行文件时,请按以下方式进行操作:

export OBJECT_MODE = 64
./waf configure all

** 2.14.构建引导程序105 **

**注意:**在使用PyInstaller打包应用程序时,还需要正确设置OBJECT_MODE。

要构建引导程序,您需要与用于构建python的编译器兼容(相同)的编译器。

**注意:**使用不同版本的gcc编译的Python与您使用的可能不兼容。 GNU工具并不总是二进制兼容。

如果您不知道使用的编译器是哪一个,此命令可以帮助您确定编译器是否为gcc或IBM编译器:

python -c“import sysconfig; print(sysconfig.get_config_var(‘CC’))”

如果编译器是gcc,则您可能需要安装其他RPM以支持GNU运行时依赖项。

当使用IBM编译器时,不需要其他先决条件。 IBM编译器的建议值为_:command:xlc_r_。

2.14.5构建自由BSD

FreeBSD引导加载程序可以使用FreeBSD机器上的_通常的步骤_使用clang构建。但是要注意,在FreeBSD上本地编译的任何可执行文件都只能在相等或更新的版本的FreeBSD上运行。为了支持较旧版本的FreeBSD,必须编译出所需支持的最旧OS版本。

或者,可以使用Docker和FreeBSD交叉编译器映像从Linux交叉编译FreeBSD引导加载程序。该映像与最旧的非生命周期结束的FreeBSD发布保持同步,因此在其上编译的任何东西都将在所有活动的FreeBSD版本上运行。

在随机目录中:

-启动docker守护程序(通常是systemctl start docker-可能需要sudo如果您没有设置无根docker)。
-从此处下载最新的交叉编译器.tar.xz映像。
-导入图像:docker image load -i freebsd-cross-build.tar.xz。跨编译器映像现在以名称freebsd-cross-build保存。如果愿意,可以丢弃.tar.xz文件。

然后从此存储库的根目录开始:

-运行:

docker run -v $ (pwd):/io -it freebsd-cross-build bash -c“cd / io / bootloader; ./waf all”

2.14.6 Vagrantfile虚拟机

PyInstaller维护一组虚拟机描述,用于测试和(交叉)构建。为了管理这些框,我们使用vagrant。

所有guests^4在运行vagrant up GUEST或vagrant provision GUEST时将自动构建引导程序。它们将构建32位和64位引导程序。

(^)(4)除了guest osxcross,它将按照Cross-Building for macOS部分中描述的方式构建OS X SDK和cctools。
第106章 第2节 内容:

在构建引导程序时,客人们共享PyInstaller分发文件夹,并将构建的可执行文件放置在构建主机上(进入…/PyInstaller/bootloader/)。

大多数盒子需要安装两个_Vagrant_插件:

vagrant plugin install vagrant-reload vagrant-scp

示例用法:

vagrant up linux64 # 还将构建引导加载程序
vagrant halt linux64 # 或者 'destroy'

# 验证引导加载程序已经重建
git status ../PyInstaller/bootloader/

您可以通过设置环境变量来传递一些参数以配置Vagrantfile,如下:

GUI=1 TARGET=OSX vagrant up linux64

或者像这样:

export TARGET=OSX
vagrant provision linux64

我们当前提供这些客户端:

linux64 GNU/Linux(某些最新版本),用于构建GNU/Linux引导加载程序。
  • 如果设置了TARGET=OSX,则跨构建macOS的引导加载程序(请参见“为macOS跨构建”)。
  • 如果设置了TARGET=WINDOWS,则使用mingw跨汇编构建Windows引导加载程序。请注意,
    这会施加上述限制。
  • 否则(默认情况下)生成GNU/Linux引导加载程序。
    windows10 Windows 10,用于使用Visual C++构建Windows引导加载程序。
  • 如果设置了MINGW=1,则将使用MinGW构建引导加载程序。请注意上述限制。
注:Windows box使用密码验证,因此在某些情况下必须输入密码(密码为Passw0rd!)。
build-osxcross GNU/Linux guest用于构建如“为macOS跨构建”部分中所述的OS X SDK和cctools。

PyInstaller的2.15变更日志

2.15.1下一个版本(2023-05-22)

特征

  • 尝试保留来自win32和pythonwin目录的pywin32扩展的父目录布局,而不是将这些扩展收集到顶级应用程序目录中。 (#7627)

2.15.PyInstaller的107个变更日志

错误修复

-(Linux/macOS)修复了PySide2和PySide6运行时挂钩中的Qt目录路径覆盖。通过QT_PLUGIN_PATH和QML2_IMPORT_PATH环境变量设置的这些路径与PySide2和PySide6一起使用,这些构建使用系统范围的Qt安装,而默认情况下不可移植(例如,Homebrew)。(#7649)
-(Windows)修复VSVersionInfo的字符串序列化,以便考虑StringStruct值可能包含引号字符的可能性。(#7630)

  • 尝试减轻Anacondapywin32包的问题,因为该包在不同位置安装了三个副本pywintypes3X.dll和pythoncom3X.dll。(#7627)
  • 对传递给Analysis构造函数的datas和binaries列表进行的更改现在将使cachedAnalysis失效并触发重新构建。这适用于手动编辑.spec文件所做的更改以及由于添加或删除相应的命令行选项(–add-data,–add-binaries,–collect-data,–collect-binaries,–copy-metadata)而导致的自动更改。以前,更改可能没有生效,因为如果可用,则返回了旧的缓存构建,并且除非用户明确请求使用–clean命令行选项进行清洁构建,否则旧的缓存构建仍会返回。(#7653)

2.15.2 5.11.0(2023-05-13)

特征

  • 为没有使用PEP 263编码头指定编码但包含本地(非UTF8)编码中的非ASCII字符的纯Python模块添加了一个解决方法。当这些字符仅在代码注释中存在时,python仍会加载和运行模块,但是仅尝试通过加载程序的get_source()方法检索其源代码会导致UnicodeDecodeError,这会中断分析过程。错误现已被捕获,并且回退代码路径尝试检索源代码作为原始数据,以避免编码问题。(#7622)

错误修复

-(Windows)除非启用了二进制拆分或upx处理,否则不会将收集的二进制文件写入二进制缓存中。(#7595)

  • 修复了在遇到重复条目时,在PKG/CArchive和PYINSTALLER_STRICT_UNPACK_MODE环境变量未设置时,在onefile可执行文件中导致崩溃的启动程序中的回归。(#7613)

过时

  • TOC类现已过时。改用具有相同三元组的纯列表。 PyInstaller现在在其实例化期间对构建目标(例如,PYZ,EXE,COLLECT)传递的TOC列表执行显式规范化(即条目去重)。 (#7615)

第108章2.2.1。目录:引导加载程序

  • 修复引导加载程序使用不支持-Wno-error = unused-but-set-variable编译器标志的旧版本gcc(例如gccv4.4.3)的构建问题。 (#7592)

文档

  • 更新TOC列表和Tree类的文档,以反映TOC类的过时。(#7615)

PyInstaller核心

  • 在分析/构建过程中删除对TOC类的使用,改为使用纯列表实例。TOC类执行的TOC条目的隐式规范化(去重)已被替换为显式规范化。生成的TOC列表Analysis在Analysis实例化结束时显式规范化,然后存储在Analysis属性中(例如,Analysis.pure,Analysis.binaries,Analysis.datas)。类似地,传递给构建目标(例如,PYZ,EXE,COLLECT)的TOC列表在其实例化过程中显式规范化。 (#7615)

2.15.3 5.10.1(2023-04-14)

错误修复

  • 修复由于在存档编写器代码清理期间引入的PKG / CArchive生成中的错误,导致具有严格数据对齐要求(例如armhf / armv7上的linux)的平台上的回归,例如32位Debian Buster在Raspberry上的4。(#7566)

2.15.4 5.10.0 (2023-04-11)

缺陷修复

  • (Linux)当通过ld.so动态加载器可执行文件启动PyInstaller冻结的可执行文件时,忽略基于/proc/self/exe的可执行文件名称解析。在这种情况下,解析的名称指向ld.so可执行文件,导致PyInstaller冻结的可执行文件出现“从可执行文件无法打开PyInstaller存档”的错误。(#7551)
  • 确保在.spec文件中手动指定的二进制文件(或通过相应的–add-binary或–collect-binaries命令行开关指定)经过了二进制依赖项分析,以便自动收集其依赖项。(#7522)
  • 扩展#7066中关于排除导入机制的重构,以正确处理包内的相对导入。例如,在包’a’的钩子内,确保excludedimports = [‘a.b’]在来自import b中发挥作用时,即在from a导入b的情况下。(除了from a import b之外)。(#7495)
  • 扩展#7066中关于排除导入机制的重构,以正确处理单个from … import …语句中导入多个子模块的情况(使用绝对或相对导入)。例如,当packagec从d导入e、f时,我们需要考虑potentialexcludedimportsrules匹配的packaged,如果它本身没有被排除,则可能规则独立匹配d.e和d.f。(#7495)
  • 修复二进制依赖项搜索阶段中的编组错误,这是由于收集的软件包列表包含modulegraph.Alias 实例,而非仅仅是plain str实例。(#7515)

2.15. PyInstaller 109更新日志

  • 重新组织multiprocessing运行时钩子,仅对spawn和forkserver启动方法覆盖Popen实现,而不是fork启动方法。这避免了使用fork启动方法进行嵌套多处理时发生死锁的情况,这是由于复制了覆盖提供的锁(在#7411中引入)在其锁定状态下传递到分叉的子进程中所造成的。(#7494)

不兼容性更改

  • 重写了archive_viewer实用程序,修改了命令行接口(重命名为–list),并更改了输出格式。(#7518)

钩子

  • (Windows)通过从matplotlib.libs目录收集所有delve wheel生成的文件来改进支持格式为matplotlib >= 3.7.0。这在将PyPI matplotlib wheels与Anaconda python 3.8和3.9结合使用时是必需的。(#7503)
  • 添加PyQt6.QtSpatialAudio模块的钩子,该模块在PyQt6 6.5.0中添加。(#7549)
  • 添加PyQt6.QtTextToSpeech模块的钩子,该模块在PyQt6 6.4系列中添加。(#7549)
  • 扩展PySide6钩子以实现PySide6.5.0兼容性:添加用于PySide6.5.0中引入的QtLocation、QtTextToSpeech和QtSerialBus 部件的钩子。(#7549)

文档

  • 澄清支持的颜色规范格式,并在启动画面文档中应用一致的默认参数值格式。(#7529)

2.15.5 5.9.0 (2023-03-13)

功能

  • 选择“由软件包提供的挂钩”而不是“pyinstaller-hooks-contrib”中的挂钩,如果两者都提供相同的挂钩。(#7456)

缺陷修复

  • 修复在规范文件中更改sys.path被挂钩实用程序函数(例如collect_submodules())忽略的问题。(#7456)

2.15.6 5.8.0 (2023-02-11)

功能

  • 使用glib-schema-compiler编译收集的GLib模式文件,而不是收集预编译的gschemas.compiled文件,以便正确支持从多个位置收集模式文件。不再收集源模式文件,因为运行时应该只需要gschemas.compiled文件。(#7394)

缺陷修复

  • (Cygwin)避免使用需要在Cygwin环境中不可用的pywin32-ctypes功能的Windows特定代码路径。(#7382)
  • (非Windows)修复了当多个线程同时使用spawn方法并发地生成进程时,通过multiprocessingruntime hook修改环境变量的竞争条件。(#7410)
  • (Windows)版本信息文件中的更改现在会触发可执行文件的重新构建。(#7338)
  • 禁止在从钩子返回并在PyInstaller.building.utils.format_binaries_and_datas中进行清理的binariesanddatas元组中使用空源路径。空的源路径通常是钩子路径检索代码中的错误,会导致整个当前工作目录的隐式收集。这绝不是预期的行为,所以抛出SystemExit。(#7384)
  • 修复使用–log-level = DEPRECATION引发的“未知日志级别”错误。(#7413)

不兼容性更改

  • 已从PyInstaller的FrozenImporter中删除了已弃用的PEP-302 find_module()和load_module()方法。从python 3.4和PEP-451开始,这些方法已经不再被python的导入机制使用,因此一直处于未测试和未维护状态。删除影响仍然依赖于PEP-302查找器/加载器方法而不是PEP-451的第三方代码。(#7344)

钩子

  • 收集从Qt6 v6.4.0开始需要QtMultimedia模块的多媒体插件。(#7352)
  • 不要将designerplugins作为QtUiTools模块的一部分收集PySide2和PySide6绑定。相反,只将插件的收集绑定到QtDesigner模块。(#7322)

模块加载器

  • 从FrozenImporter中删除了已经废弃的PEP-302功能。自python 3.4起,find_module()和load_module()方法已经被PEP-451 loader取代了。(#7344)

2.15.7 5.7.0 (2022-12-04)

功能

  • 将包的位置和确切的解释器路径添加到检查标准库后移植和不兼容PyInstaller标准库后移植(enum34和typing)的错误消息中。(#7221)
  • 通过PYI_LOG_LEVEL环境变量控制构建日志级别(–log-level)。(#7235)
  • 支持为Windows构建本机ARM应用程序。如果在具有ARM Python构建的ARM机器上运行PyInstaller,则将生成ARM应用程序。(#7257)

2.15. PyInstaller 111更新日志

缺陷修复

  • (Anaconda)修复PyInstaller.utils.hooks.conda.collect_dynamic_libs钩子函数,通过引入一个额外的类型检查(排除目录和指向目录的符号链接),以及额外的后缀检查(只包括文件名与以下模式匹配的文件:.dll,.dylib,。so和.so.*)。 (#7248)
  • (Anaconda)修复在linux和macOS上使用Anaconda python 3.10时的问题,由于从python3.1到python3.10的附加符号链接,环境lib目录的所有内容最终都会被视为数据。 (#7248)
  • (GNU/Linux)修复gi共享库未被打包的问题,如果它们没有版本后缀并且位于由LD_LIBRARY_PATH设置的特殊位置而不是典型的库路径,则存在该问题。 (#7278)
  • (Windows)修复windowed冻结应用程序无法通过subprocess模块生成交互式命令提示符控制台的问题,这是由于subprocess运行时挂钩与流句柄的干扰。 (#7118)
  • (Windows)在windowed或noconsole模式下,停止将sys.stdout和sys.stderr设置为custom NullWriter对象,而是将它们保留为None。这与windowed python解释器(pythonw.exe)的行为相匹配,并防止与代码进行互操作时出现问题,它(正确地)期望流要么为None,要么是完全兼容io.IOBase的对象。 (#3503)
  • 确保在PySide6.support.deprecated模块中收集PySide6 6.4.0及更高版本,以便启用Qt键和键修饰符枚举值之间的|和&运算符的持续支持(例如QtCore.Qt.Key_D和QtCore.Qt.AltModifier)。 (#7249)
  • 修复在onefile构建中可能出现的python扩展模块重复的问题,当一个扩展既作为EXTENSION又作为DATA(或BINARY)TOC类型进行收集时,会出现这种情况。这导致运行时警告关于文件已经存在;最臭名昭着的例子是WARNING: file already exists but should not: C:\Users\user\AppData\Local\Temp\MEI1234567\torch_C.cp39-win_amd64.pyd,在构建使用torch的onefile应用程序时。 (#7273)
  • 修复在以egg形式安装的包中尝试读取top_level.txt元数据的虚假尝试。 (#7086)
  • 修复一些构建步骤忽略日志级别(通过–log-level提供)的问题。 (#7235)
  • 修复MERGE无法正确清理已传递的Analysis.binaries和Analysis.datas TOCs的问题,这是由于在PyInstaller 5.0中对TOC类所做的更改导致的。这有效地破坏了MERGE和多包捆绑包的假定去重功能,现在应该得到恢复。 (#7273)
  • 当使用pyinstaller your-code.py而不使用python -m PyInstaller your-code.py调用PyInstaller时,防止将$pythonprefix/bin添加到sys.path中。 当库名称与控制台脚本相同时,可以防止集合不匹配。 (#7120)
  • 防止孤立子进程在清理代码路径时无限期阻塞,当子进程无法退出时。在等待5秒的宽限期后,我们现在尝试终止这样的子进程,以防止构建过程挂起。 (#7290)

第112章 第2节 内容:

不兼容的更改

  • (Windows)在windowed/noconsole模式下,PyInstaller不再将sys.stdout和sys.stderr设置为custom NullWriter对象,而是将它们保留为None。新行为与windowed python解释器(pythonw.exe)的行为相匹配,但可能会破坏在未先检查sys.stdout或sys.stderr是否可用的情况下使用它们的代码。因此,旨在在windowed/noconsole模式下运行的代码应该使用windowed python解释器进行验证,以捕获与控制台不可用相关的错误。 (#7216)

弃用

  • 弃用字节码加密(–key选项),在PyInstaller v6.0中将其删除。 (#6999)

钩子

  • (Windows)删除subprocess运行时挂钩。问题已在引导加载程序中得到解决,即当标准流不可用(例如在windowed/no-console应用程序中)时,该问题会导致subprocess模块在尝试生成未重定向所有标准流的子进程时引发OSError:[WinError 6] The handle is invalid异常。 (#7182)
  • 确保PySide2、PyQt5、PySide6和PyQt6绑定的每个Qt*子模块都有对应的钩子,并因此可以在冻结的应用程序中单独导入。适用于编写本文时的最新版本的软件包:PySide2 == 5.15.2.1,PyQt5 == 5.15.7,PySide6 == 6.4.0和PyQt6 == 6.4.0。 (#7284)
  • 通过删除Django运行时钩子中的django.core.management.get_commands的覆盖,提高与当代Django4.x版本的兼容性。由于当代版本的PyInstaller和Django都正确填充了动态命令列表,因此静态命令列表覆盖已过时(基于Django1.8)和不必要。 (#7259)
  • 引入额外的日志消息到matplotlib.backend钩子,以提供更好的洞察力,了解何时生效时,以检测到matplotlib.usecalls的后端选择和原因。 (#7300)

引导程序

  • (Windows)在一个文件应用程序中,如果标准流不可用(例如在窗口化/无控制台应用程序中),则避免传递无效的流处理程序(值为-1的INVALID_HANDLE_VALUE常量)到启动的应用程序子进程。 (#7182)

引导程序构建

  • 支持使用MSVC构建ARM本机二进制文件,使用命令python waf --target-arch=64bit-arm all。如果在ARM机器上构建,则–target-arch=64bit-arm为默认值。 (#7257)
  • 可以使用ARM版的clang使用python waf --target-arch=64bit-arm --clang all构建Windows ARM64引导程序。 (#7257)

2.15. PyInstaller 113的变更日志

2.15.8 5.6.2 (2022-10-31)

缺陷修复

  • (Linux、macOS)修复共享库集合中的回归,其中共享库将最终以其完全版本的.so名称(例如,libsomething.so.1.2.3)而不是以其最初引用的名称(例如,libsomething.so.1)进行收集,原因是偶发的符号链接解析。 (#7189)

2.15.9 5.6.1 (2022-10-25)

错误修复

  • (macOS)修复由#7180中的一个错字导致的macOS应用包签名回归问题。 (#7184)

2.15.10 5.6(2022-10-23)

功能

  • 官方支持Python 3.11。 (请注意,PyInstaller v5.5也预计可以正常工作,但仅已通过Python 3.11的预发布版本进行测试。)(#6783)
  • 实现一种新的hook实用程序函数collect_delvewheel_libs_directory(),旨在处理外部共享库中的delvewheel启用的PyPI wheels,以供Windows使用。 (#7170)

错误修复

  • (macOS)修复在生成的macOS .app bundles中由于软件包的源.py文件的重定位而导致的OpenCV(cv2)加载器错误。 (#7180)
  • (Windows)提高与scipy1.9.2的兼容性,其Windows wheels已切换到delvewheel,并因此将共享库放置在外部.libs目录中。 (#7168)
  • (Windows)将#7028中的DLL父路径保留行为限制为从site-packages目录(由site.getsitepackages()和site.getusersitepackages()返回)收集的文件,而不是所有路径sys.path 中的所有路径,以避免在特定情况下发生意外行为,例如sys.path包含驱动器根目录或用户的主目录时。 (#7155)
  • 修复与PySide66.4.0的兼容性问题,其中不再使用已弃用的Qml2ImportsPathlocation键;在可用时使用新的QmlImportsPath键。 (#7164)
  • 防止PyInstaller运行时钩子setuptools尝试在收集setuptools时覆盖distutils提供的版本,而setuptools的版本低于60.0时会出现错误。这既模仿了未冻结的行为,也防止了版本在50.0和60.0之间的错误,我们不会明确地收集setuptools。_distutils。 (#7172)

114第二章。目录:

不兼容的更改

  • (macOS)在生成的macOS .app bundles中,不再将收集的源.py文件从Contents / MacOS重新定位为Contents / Resources,以避免当.py文件的路径应解析为与相邻的二进制扩展名相同时出现问题时。另一方面,此更改可能会导致在捆绑签名和/或未尝试时出现回归。 (#7180)

引导程序

  • (Windows)更新捆绑的zlib源代码为v1.2.13。 (#7166)

2.15.11 5.5(2022-10-08)

功能

  • (Windows)支持在可执行文件中嵌入多个图标。 (#7103)

错误修复

  • (Windows)修复PyInstaller 5.4中引入的回归(#6925),在存在其他python安装程序的情况下收集python3.dll的不正确副本(因此还有来自相同目录的另一个不正确的python3X.dll副本)。 (#7102)
  • (Windows)为ctypes.util.find_library提供运行时覆盖,该覆盖在扫描二进制依赖项的独立子过程中为sys._MEIPASS添加了_PATH_环境变量中指定的目录。 (#7097)
  • 修复在导入pywin32顶层扩展模块时找不到pywin32DLL的问题,导致在#7028中引入的DLL目录结构保留行为。引入一个新的引导/加载器模块,如果可用,则将pywin32_system32目录添加到sys.path和DLL搜索路径中,而不是必须为来自pywin32的每个单独的顶层扩展模块提供运行时钩子脚本。 (#7110)

钩子

  • 修复了matplotlib.backends钩子在尝试通过钩子配置指定要收集的后端列表时引发的错误。 (#7091)

2.15.12 5.4.1(2022-09-11)

错误修复

  • (Windows)修复pyi_rth_win32comgenpy(win32com的运行时钩子)引发的运行时错误。 (#7079)

2.15。PyInstaller 113的更改日志:

2.15.13 5.4(2022-09-10)

功能

  • (Windows)在收集通过链接时依赖分析所发现的DLL时,尝试保留其父目录结构,而不是将其收集到应用程序的顶层目录。这旨在保留与PyPI wheel中打包的python软件包捆绑的DLL的父目录结构,而从系统目录(以及Anaconda环境的Library \ bin目录)收集的DLL仍收集到顶级应用程序目录。 (#7028)
  • 支持由setuptools提供的distutils,自setuptools> = 60.0以来可用。 (#7075)
  • 实现用于在hook中使用的通用文件过滤决策函数,基于源文件名和可选的包含和排除模式列表(PyInstaller.utils.hooks.include_or_exclude_file())。 (#7040)
  • 重构模块排除机制。通过钩子中的excludedimports列表指定的排除模块条目现在用于在模块上_import_期间抑制模块导入from corresponding nodes_during modulegraph construction_,而不是将节点从图形中删除作为后处理步骤。这应该使模块排除更加健壮,但主要好处是我们避免运行(可能很多且可能很昂贵)挂钩,这些挂钩将最终被排除在外模块。 (#7066)

错误修复

  • (Windows)尝试在孤立子进程中导入软件包过程期间使用_PATH_环境变量中找到的目录以及跟踪对os.add_dll_directory函数的调用来扩展DLL搜索路径。 (#6924)
  • (Windows)确保在使用Anaconda安装的PyQt5和Qt5时收集ANGLE DLLS(libEGL.dll和libGLESv2.dll)。 (#7029)
  • 修复在分析.pyc文件时出现的AssertionError,其中包含超过255个变量名称的import语句都在同一命名空间中。 (#7055)

不兼容的更改

  • (Windows)PyInstaller现在尝试保留从python软件包(例如,在PyPI wheel中捆绑)收集的DLL的父目录结构,而不是将其收集到顶级应用程序目录中。此行为可能与假定旧行为的第三方钩子不兼容,并可能导致重复DLL文件或缺少挂钩提供的运行时搜索路径中的DLL文件。 (#7028)

钩子

  • 实现了newgstreamerhook配置组,包括include_plugins和exclude_plugins选项,可控制为gi.repository.Gsthook收集的GStreamer插件。(#7040)
  • 通过GObject反射(gi)绑定提供附加的gstreamer模块的钩子:gi.repository.GstAllocators、gi.repository.GstApp、gi.repository.GstBadAudio、gi.repository.GstCheck、gi.repository.GstCodecs、gi.repository.GstController、gi. repository.GstGL、gi.repository.GstGLEGL、gi.repository.GstGLWayland、gi.repository。GstGLX11、gi.repository.GstInsertBin、gi.repository.GstMpegts、gi.repository.GstNet、gi.repository.GstPlay、gi.repository.GstPlayer、gi.repository.GstRtp、gi.repository.GstRtsp、gi.repository。GstRtspServer、gi.repository.GstSdp、gi.repository.GstTranscoder、gi.repository.GstVulkan、gi.repository.GstVulkanWayland、gi.repository.GstVulkanXCB和gi.repository.GstWebRTC。(#7074)

第2章第15.14节5.3(2022-07-30)

特性

  • (Windows)在onefilebootloader父进程中实现控制台控制信号的处理。实现处理器抑制CTRL_C_EVENT和CTRL_BREAK_EVENT,让子进程按照它们自己的方式处理它们。在CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT或CTRL_SHUTDOWN_EVENT的情况下,处理器尝试延迟父进程的终止,以便子进程有时间退出并让父进程的主线程在退出之前清理临时目录。这可以防止onefilefrozen应用程序在用户关闭控制台窗口时留下其临时目录。(#6591)
  • 实现一种机制,用于控制模块和包的收集模式,从顶级包到单个子模块的细粒度。因此,钩子现在可以指定挂钩的包是否应作为字节编译的.pyc模块收集到嵌入式PYZ存档中(默认行为)还是作为源.py文件收集到外部数据文件中(PYZ存档中没有相应的模块)。 (#6945)

缺陷修复

  • (非Windows)避免在POSIX信号处理程序中生成调试消息,因为涉及的函数通常不是信号安全的。在Linux上关闭冻结应用程序时,在某些情况下可避免SIGPIPE的无限垃圾邮件。(#5270)
  • (非Windows)如果onefilefrozen应用程序的子进程由信号终止,请延迟父进程重新引发信号,直到完成清理为止。这样可以防止onefilefrozen应用程序在父进程或子进程收到SIGTERM信号时留下其解压缩的临时目录。(#2379)
  • 当使用noarchive=True(例如,–debug noarchive或–debug all)进行构建时,PyInstaller不再使用.pyc或.py的文件污染用户可写源位置。写在相应源文件旁边的文件。(#6591)
  • 当使用noarchive=True(例如,–debug noarchive或–debug all)进行构建时,在收集的.pyc模块中现在剥离源路径,与使用PYZ archive相同。(#6591)

钩子

  • 为gi.repository.freetype2添加PyGObject钩子。使用PyGObject 3.25.1+删除未找到的隐藏导入警告。 (#6951)
  • 删除不可用的pkg_resources隐藏导入,包括py2_warn、markers和_vendor.pyparsing.diagram。(#6952)

文档

  • 记录Windows的信号处理行为以及与通过任务管理器关闭冻结的应用程序相关的各种怪癖。(#6935)

第2章第15.15节5.2(2022年7月8日)

特性

  • 检测图标文件(.ico或.icns)是否是另一种图像类型,但已被错误地标记为本地图标类型。如果安装了pillow,则规范化为实际的本地图像类型,否则提出错误。(#6870)
  • 如果用户在应用程序仍在运行时移动或删除应用程序,则通过解释性SystemExit进行优雅退出。请注意,仅在尝试加载尚未加载的模块时检测到此项。(#6856)
  • 实现一个名为warn_on_missing_hiddenimports的新标准挂钩变量。此可选布尔标志允许挂钩选择退出由该挂钩起源的丢失的隐藏导入所生成的警告。(#6914)

缺陷修复

  • (Linux)修复使用Anaconda环境时收集的Python共享库名称与引导加载程序期望的名称之间可能不匹配的问题。当尝试冻结也链接到Python共享库的扩展程序时,会出现不匹配。(#6831)
  • (Linux)在使用发行版的RPM软件包安装的GObject反射时,在RHEL/Fedora Linux上冻结的应用程序中修复了缺少的gi.repository错误。(#6780)
  • (macOS)QtWebEnginehook现在使QtOpenGL和QtDBus对具有Qt 6的框架安装的呈现器进程可用。(#6892)
  • (Windows)为了尝试减少一体式构建的处理时间和内存占用,优化了EXE PE标头修复过程。(#6874)
  • 在ctypes.util.find_library()周围添加try/except保护,以防止发生Cython错误#93094,导致FileNotFoundError。(#6864)
  • 修复了PyInstaller v5中的回归错误,其中程序中不存在的GObject反射(gi)模块(例如,可选依赖项)的导入会导致构建时错误并中止构建过程。(#6897)
  • 如果传递的是可导入模块的名称而不是包,则PyInstaller.utils.hooks.collect_submodules()函数现在返回包含模块名称的列表,与对于没有子模块的包相同。(#6850)
  • 防止PyInstaller.utils.hooks.collect_submodules()递归到通过过滤器参数传递的子包中。(#6846)
  • PyInstaller.utils.hooks.collect_submodules()函数现在从返回的模块列表中排除无法导入的子包。(#6850)

钩子

  • (macOS)在相应的PySide6和PyQt6运行时钩子中禁用Qt6的DisableQtWebEnginesandboxing作为对QtWebEngineProcess帮助程序进程崩溃的解决方法。由于PyInstaller收集Qt库的方式,这在Qt 6.3.1版本之后是必需的,但无论使用的Qt6版本如何都会应用。如果您使用较旧版本的Qt6并希望保持沙盒,请在导入Qt包之前在程序启动时重设QTWEBENGINE_DISABLE_SANDBOX环境变量。(#6903)
  • 通过在hooks配置中添加依赖项并更新gi.repository.Gtk和gi.repository.Gdk以使用module-version与gi.repository.Gtk和gi.repository.Gdk一起使用,添加对GTK4的支持。 (#6834)
  • 重构GObject introspection(gi)钩子,以便处理仅在挂钩加载阶段或hook()函数中进行,而不是两者混合进行。 (#6901)

118第2章 内容:

  • 更新GObject introspection(gi)钩子,使用新引入的GiModuleInfo对象进行以下操作:
    - 检查模块可用性。
    - 执行类型库数据收集;等同于旧的get_gi_typelibs函数调用。
    - 获取相关联的共享库路径,等同于旧的get_gi_libdir函数调用。
    get_gi_typelibs和get_gi_libdir函数现在内部使用GiModuleInfo来为外部用户提供向后兼容性。 (#6901)

2.15.16 5.1(2022-05-17)

Bugfix

  • (Windows)修复导致(相对)规范路径两次出现在相对图标路径中,导致找不到图标的回退问题。 (#6788)
  • 防止在使用collect_data_files()或collect_dynamic_libs()收集单个文件模块时收集整个Python站点。(#6789)
  • 防止挂钩实用程序函数(例如collect_submodules(),collect_data_files()和collect_dynamic_libs())无法识别包时,其PEP 451兼容的加载器未实现可选的is_package方法。(#6790)
  • get_package_paths()函数现在支持PEP420命名空间包–尽管由于向后兼容的原因,当存在多个路径时,它只返回第一个路径。(#6790)
  • hook实用程序函数collect_submodules(),collect_data_files()和collect_dynamic_libs()现在支持从PEP420命名空间包中进行收集。 (#6790)
  • 用户提供的规范文件路径以及通过–workpath和–distpath提供的路径现在在传递给PyInstaller的内部之前被解析为绝对完整路径。 (#6788)

挂钩

  • 在picklehook中排除octest。更新PySide2,PySide6,PyQt5和PyQt6钩子,其中包含以前由doctest引入的隐藏导入项。 (#6797)

引导程序

  • (Windows)将捆绑的zlibsources更新为v1.2.12。 (#6804)

引导程序构建

  • 如果PyInstaller存储在具有长路径的目录中,则在Windows上使用MSVC进行构建不会崩溃。(#6806)

2.15.PyInstaller 119的Changelog

2.15.17 5.0.1(2022-04-25)

Bugfix

  • (Linux)使glibruntime hook将冻结应用程序的数据目录前置到XDG_DATA_DIRS环境变量中,而不是完全覆盖它。这应该修复使用xdg-open启动系统安装的应用程序的情况(例如,通过webbrowser模块在Web浏览器中打开URL),并且找不到已注册的应用程序。 (#3668)
  • 防止来自UPX的无法执行的错误终止构建。 (#6757)
  • 恢复PyInstaller 5.0之前的解析相对路径为规范文件相对于当前工作目录而不是规范文件的先前行为。 (#6759)
  • (Windows)更新系统DLL包含列表,以允许从Visual Studio 2012(VC11)运行时和Visual Studio 2013(VC12)运行时以及最新版本的Visual Studio 2015/2017/2019/2022 (VC14)运行时(14.3)收集DLL,。(#6778)

钩子

  • 重构QtWebEngine钩子以支持纯Widget-based和纯QML / Quick-based应用程序。 (#6753)
  • 为了与Windows和Linux上的Qt 6.3兼容,更新PySide6和PyQt6钩子。QtWebEngine不再为助手可执行文件提供qt.conf文件,因此我们会为基于QtWebengine的冻结应用程序生成自己的文件。 (#6769)

2.15.18 5.0(2022-04-15)

特征

  • (macOS)在onedirmode中构建的App bundles现在可以选择加入_argv emulation_,以便将从UI(Open with…)传递的文件路径反映在sys.argv中。 (#5908)
  • (macOS)在onedirmode中构建的App bundles现在可以选择加入_argv emulation_,以便将在初始拖放事件中接收的文件路径反映在sys.argv中。 (#5436)
  • (macOS)_argv emulation_功能现在作为任一onefile或onedirmode中构建的应用程序包的可选功能可用。 (#6089)
  • (Windows)默认情况下将清单嵌入生成的onedirexecutables中,以避免用户重命名可执行文件时可能出现的问题(例如,由于激活上下文缓存而找不到清单文件,当用户重命名可执行文件并尝试在重命名清单文件之前运行它时)。 在onedirmode中生成外部清单文件的旧行为可以使用–no-embed-manifest命令行开关或通过.spec文件中EXE()的embed_manifest=False参数重新启用。 (#6223)
  • (Wine)在Wine下构建Windows冻结应用程序时,防止收集Wine内置的DLL(以PE-converted或fake/placeholder形式)。 对于每个排除的Wine内置DLL,显示一个警告。(#6149)
  • 添加PyInstaller.isolated子模块作为PyInstaller.utils.hooks的安全替代品。 exec_statement()。 (#6052)
  • 改进与UPX排除模式的匹配,包括OS默认大小写敏感性,通配符运算符(*)和模式中父目录的支持。 启用像“Qt *.dll”和“PySide2 * .pyd”之类的模式。 (#6161)
  • 使collect_submodules()的错误处理可配置。 (#6052)

Bugfix

  • 在onefileapp Bundle启动时,修复了可能存在的Apple事件丢失问题,当子进程尚未准备好接收父进程转发的事件时。(#6089)
  • (Windows)删除了通过激活上下文加载onefilefrozen可执行文件清单的尝试,这会在调试版本中观察到 尝试设置进程默认激活上下文失败,因为进程默认激活上下文已经设置 的消息。自从#3746实现了直接清单嵌入到onefile可执行文件中,这种方法就已经无效了。(#6203)
  • 当使用子模块或子包名称调用PyInstaller.utils.hooks.get_module_file_attribute()时修复了导入泄露问题。(#6169)
  • 当使用子模块或子包名称调用PyInstaller.utils.hooks.is_package()时修复了导入泄露问题。(#6169)
  • 在打包GTK应用程序时调用get_gi_libdir()时防止导入错误。通过为Ubuntu构建添加PyGObject依赖项来启用GTK的CI测试。(#6300)
  • 如果不会生成.spec文件,但同时给出了特定于该功能的命令行选项,则发出错误报告。(#6660)
  • 防止onefilecleanup递归到链接目录中并仅删除链接即可。(#6074)

不兼容的更改

  • (macOS)以onefile模式构建的应用程序Bundle不再默认执行_argv模拟。现在必须通过在.spec文件中使用argv_emulation=True参数或通过–argv-emulation命令行标志明确选择将初始打开文档/URL事件转换为sys.argv条目的功能。(#6089)
  • (Windows)默认情况下,manifest现在嵌入到onefile模式的可执行文件中。可以使用–no-embed-manifest命令行开关或在.spec文件中使用embed_manifest=False参数来重新启用生成外部清单文件的旧行为。(#6223)
  • 如果不会生成.spec文件,但同时给出了特定于该功能的命令行选项,则发出错误报告。(#6660)
  • PyInstaller.utils.hooks.get_module_attribute()函数现在返回实际属性值而不是它的字符串表示。该函数的外部用户(例如第三方挂钩)必须相应地调整其返回值的处理。(#6169)
  • matplotlib.backends挂钩不再收集所有可用的matplotlib后端,而是尝试默认自动检测所使用的后端。可以通过钩子配置选项重新启用旧行为。(#6024)

挂钩

  • 重新设计matplotlib.backends hook,尝试执行所使用的后端的自动检测,而不是收集所有可用的后端。实现钩子配置选项,允许用户在这种新行为和收集所有后端的旧行为之间切换,或手动指定要收集的后端。(#6024)

PyInstaller 121的更改日志

启动器

  • 更改–no-universal2标志的行为,以便现在它假定编译器的目标架构(可以通过CC环境变量进行覆盖以促进交叉编译)。 (#6096)
  • 重构Apple事件处理代码并将其移动到单独的源文件中。(#6089)

文档

  • 添加新部分,描述macOS上的Apple事件转发行为以及应用于macOS应用程序包的可选_argv模拟以及其警告。 (#6089)
  • 更新有关使用UPX的文档。(#6161)

PyInstaller核心

  • 不支持Python 3.6。(#6475)

启动器构建

  • (Windows)为Windows启动程序启用控制流保护。(#6136)

2.15.19 4.10(2022年3月5日)

功能

  • (Wine)在Wine下构建Windows冻结应用程序时,防止收集Wine内置的DLL(无论是在PE转换还是伪造/占位符形式中)。对于每个被排除的内置Wine DLL,显示警告。(#6622)

缺陷修复

  • (Linux)解除对objcopy操作的超时,以防止在处理大型可执行文件时对慢速磁盘进行误判。(#6647)
  • (macOS)将严格的体系结构验证限制为仅针对扩展模块的收集二进制文件。修复了当universal2包的多架构扩展模块的架构片段链接到不同的单架构薄共享库时出现的架构验证错误,正如在scipy 1.8.0 macOS universal2 wheel中所示。 (#6587)
  • (macOS)移除每个codesign和lipo操作的60秒超时,这会导致处理巨大二进制文件时构建中止问题。(#6644)
  • (Windows)在构建过程中使用一个虚构的(不是.exe)后缀名来命名中间可执行文件,以防止杀软在PyInstaller仍在处理文件时尝试扫描文件,从而导致构建时PermissionError。(#6467)
  • 修复了在相应的源.py文件的st_mtime设置为零时尝试收集不存在的.pyc文件的问题。(#6625)

122第2章。 内容:

挂钩

  • 在PIL hook中将IPython添加到排除包列表中,以防止在没有任何其他导入时自动收集IPython。这反过来防止使用PIL.Image时,自动拉取整个matplotlib。(#6605)

启动器

  • 修复了在启用编译器中启用Thumb指令集时检测32位arm平台的问题。在这种情况下,waf构建脚本中的ctx.env.DEST_CPU设置为thumb而不是arm。(#6532)

2.15.20 4.9(2022年2月3日)

缺陷修复

  • 在运行pkgutil.iter_modules时添加了对外部路径的支持。添加了对多个搜索路径到pkgutil.iter_modules的支持。正确处理空列表时的pkgutil.iter_modules。(#6529)
  • 修复了在使用pyenv安装Python且python可执行文件未链接到libpython3x.so时查找libpython3x.so的问题。(#6542)
  • 修复了在PyInstaller的pkgutil.iter_module替换/覆盖的路径匹配部分中处理符号链接的问题。(#6537)
  • 为PySide6.QtMultimedia和PyQt6.QtMultimedia添加钩子。 (#6489)
  • 为所有四个支持的Qt绑定(PySide2、PySide6、PyQt5和PySide6)的QtMultimediaWidgets添加钩子。 (#6489)
  • 添加对setuptools 60.7.1及其在pkg_resources中vendoring of jaraco.text的支持。如果遇到setuptools 60.7.0,会因与PyInstaller的加载程序逻辑不兼容而退出并显示错误消息。 (#6564)
  • 收集QtWaylandClient相关的插件,以便在使用任何四个支持的Qt绑定(PySide2、PyQt5、PySide6和PyQt6)的冻结应用程序中启用Wayland支持。 (#6483)
  • 当使用PySide2.QtMultimedia或PySide6.QtMultimedia与PySide的true_property特性相结合时,修复缺少QtMultimediaWidgets模块的问题。 (#6489)

2.15.21 4.8 (2022-01-06)

特性

  • (Windows)将可执行文件的构建时间设置为当前时间的PE头文件。可以通过SOURCE_DATE_EPOCH环境变量指定自定义时间戳,以允许可重复构建。 (#6469)
  • 为Termux平台提供非官方支持。 (#6484)
  • 将Linux和其他类Unix操作系统上的双进程onedirmode替换为单进程实现。这使得这些操作系统上的onedir mode与Windows和macOS相当,因为单进程onedir mode已经使用了一段时间。 (#6407)

2.15.关于PyInstaller 123的更改日志

错误修正

  • (macOS)修正生成通用二进制文件(universal2)可执行文件的回归,该回归导致生成的可执行文件无法通过codesignstrict验证。 (#6381)
  • (Windows)修正onefile提取行为,当运行时临时目录设置为驱动器号时。现在,应用程序的临时目录直接在指定的驱动器上创建,而不是在当前驱动器上创建。 (#6051)
  • (Windows)解决了来自python.org的python 3.9.8的兼容性问题,由于python.exe中缺少内嵌的manifest而引起。 (#6367)
  • (Windows)解决由于可执行文件的堆栈较小而导致_pyarmor_ -protected冻结应用程序堆栈溢出的问题,该堆栈小于python解释器的堆栈。 (#6459)
  • (Windows)修正当使用来自MS应用商店的Python时找不到python3.dll共享库的问题。 (#6390)
  • 修复了一个错误,该错误阻止未捕获异常的traceback被检索和显示在窗口化引导加载器的错误报告设施中(Windows上未捕获异常对话框,macOS上的syslog)。 (#6426)
  • 当onefile构建试图覆盖现有的onedir build时,修复在macOS或Linux上崩溃的问题(#6418)
  • 修正将Linux共享库(.so)文件作为二进制文件在macOS上收集时的构建错误。 (#6327)
  • 在通过FrozenImporter.get_source()读取收集的.py源文件时,修复编码处理的错误处理。 (#6143)
  • 修复当路径含有空格时,钩子加载器函数无法找到钩子的错误。 (在代码库重新格式化期间不小心撤销了修复。) (#6080)
  • Windows:当编译在–windowed模式中的应用程序使用subprocess但未显式将stdin,stdout和stderr设置为PIP或DEVNULL时,防止无效句柄错误。 (#6364)

钩子

  • (macOS)添加对Anaconda安装的PyQtWebEngine的支持。 (#6373)
  • 添加钩子以支持PySide6.QtWebEngineWidgets和PyQt6.QtWebEngineWidgets。 PyInstaller中的QtWebEngine支持需要Qt6v6.2.2或更高版本,因此如果遇到早期版本,我们会退出并产生错误,而不是生成失效的构建。 (#6387)
  • 避免在不必要的情况下(即应用程序不使用QtQml或QtQuick模块)收集整个QtQml模块及其依赖项。由于扩展模块与libQt5Qml或libQt6Qml共享库链接,因此会触发不必要的收集,影响纯基于widget的应用程序(Linux上的PySide2和PySide6)以及使用QtWebEngineWidgets的基于widget的应用程序(所有OS上的PySide2、PySide6、PyQt5和PyQt6)。 (#6447)
  • 更新numpyhook以与版本1.22兼容;钩子不再能够排除distutils和numpy.distutils,因为它们是由一些外部软件包使用的numpy.testing所需的,如scipy。 (#6474)

第124章。目录:

启动加载器

  • (Windows)将引导加载器可执行文件的堆栈大小设置为2 MB,以匹配python解释器可执行文件的堆栈大小。 (#6459)
  • 将Linux和类Unix操作系统上的双进程onedir模式替换为单进程实现。新模式使用exec()而不使用fork()在同一进程中重启引导加载器可执行镜像,在设置环境变量(即LD_LIBRARY_PATH和其他环境变量)之后。 (#6407)
  • 锁定引导加载器中的PKG侧载模式,除非可执行文件嵌入了特殊签名。 (#6470)
  • 当用户脚本以未捕获异常终止时,通过PyErr_Fetch获取的异常数据始终与调用PyErr_NormalizeException。否则,在某些情况下,试图通过traceback.format_exception格式化traceback会失败,并且无法在窗口化启动加载器的错误报告中显示traceback。 (#6426)

引导加载器构建

  • 可以通过设置环境变量PYINSTALLER_COMPILE_BOOTLOADER在pip install期间强制编译引导加载器。 (#6384)

2.15.22 4.7 (2021-11-10)

错误修正

  • 自v4.6以来存在一个错误,会错误地假定某些Unix系统目录存在,并导致FileNotFoundError。 (#6331)

钩子

  • 更新sphinxhook以与最新版本(4.2.0)兼容。 (#6330)

启动加载器

  • (Windows)在编译Windows引导程序时,显式设置NTDDI_VERSION = 0x06010000和_WIN32_WINNT = 0x0601,以请求Windows 7特征级别的Windows头文件。窗口化引导程序需要至少Windows Vista特征级别,并且一些工具链(例如,在Linux上的mingw交叉编译器)默认设置级别过低。(#6338)
  • (Windows)使用MinGW工具链编译时,移除对未使用的windres实用程序的检查。(#6339)
  • 将使用PyRun_SimpleString替换为PyRun_SimpleStringFlags。(#6332)

2.15. PyInstaller 125版本更新内容

2.15.23 4.6(2021-10-29)

新增功能

  • 添加对Python 3.10的支持。(#5693)
  • (Windows)默认在生成的onedir可执行文件中嵌入清单,以避免用户重命名可执行文件时潜在问题(例如,由于激活上下文缓存,在用户重命名可执行文件并尝试运行之前找不到清单文件)。旧的行为可以通过使用–no-embed-manifest命令行开关或在.spec文件中对EXE()的embed_manifest=False参数重新启用。(#6248)
  • (Windows)在Windows的VSVersionInfo文件中遵守PEP 239编码规范器。(#6259)
  • 实现用于通过importlib.resources(python >= 3.9)或importlib_resources(python <= 3.8)访问文件系统上的资源(数据文件)的基本资源读取器。(#5616)
  • 在x86_64和aarch64上为基于musl的Linux发行版(例如Alpine或OpenWRT)提供预编译的轮子。(#6245)

错误修正

  • (macOS)确保将可执行文件的预处理和后处理步骤(目标架构选择,SDK版本调整,(重新)签名)应用于独立PKG模式。(#6251)
  • (macOS)增强macOS汇编管道以解决在macOS 10.13 High Sierra上使用codesign实用程序的问题。(#6167)
  • (Windows)当使用MSYS2/MINGW python时,修复sysconfig平台特定数据模块的收集。(#6118)
  • (Windows)修复MinGW-w64工具链编译引导程序时未处理窗口化的冻结应用程序中的问题。当工具链强制嵌入默认清单(例如来自msys2的MinGW-w64工具链)时,问题的范围从与清单相关的选项(例如uac-admin)不起作用到窗口化的冻结应用程序根本不启动(出现LoadIconMetric过程入口点无法找到的错误消息)。 (#6196)
  • (Windows)修复了可选嵌入式产品版本信息资源结构中字符串的声明长度。声明长度为两倍太长,并在使用_ctypes_和winver API读取版本信息时导致尾随的垃圾字符。 (#6219)
  • (Windows)删除了通过激活上下文加载onefile冻结可执行文件的尝试,该方法在onefile可执行文件中直接嵌入清单后,从#3746开始就无效了。即使在调试版本中也会出现“尝试设置进程默认激活上下文失败,因为已经设置进程默认激活上下文”消息的错误。(#6248)
  • (Windows)抑制有关api-ms-win-core-*DLL的缺失库警告。(#6201)
  • (Windows)容忍使用unicode字节顺序标记读取Windows VSVersionInfo文件。(#6259)
  • 修复在程序包侧加载模式(pkg_append=False)中sys.executable指向外部包文件而不是可执行文件的错误。(#6202)
  • 修复了可能导致ctypes.util.find_library(“libfoo”)非确定性地选择任何与libfoo *相匹配的库来绑定的runaway glob问题,而不是libfoo.so。(#6245)
  • 修复了与MIPS和loongarch64体系结构的兼容性问题。(#6306)

126章2. 内容:

  • 修复了FrozenImporter.get_source(),以正确处理包的__init__.py源文件。这反过来解决了当收集和可用源.py文件时缺少源文件错误的问题,例如使用pytorch JIT的包(例如kornia)。 (#6237)
  • 修复了使用side-load模式(pkg_append=False)和onefile模式的组合时,生成的独立包文件的位置。现在,将包文件放置在可执行文件旁边,而不是.spec文件旁边。(#6202)
  • 在生成spec文件时,避免将spec文件的位置硬编码为Analysis的pathex参数。(#6254)

不兼容的更改

  • (Windows)默认情况下,在onedir模式中现在将清单嵌入到可执行文件中。旧的行为可以通过使用–no-embed-manifest命令行开关或在.spec文件中对EXE()的embed_manifest=False参数重新启用。(#6248)

挂钩

  • (macOS)修复了与AnacondaPyQt5软件包的兼容性。(#6181)
  • 添加一个用于pandas.plotting的钩子,以恢复与pandas1.3.0及更高版本的兼容性。(#5994)
  • 为PyQt6和PySide6添加了一个名为QtOpenGLWidgets的钩子,以收集Qt6中引入的新QtOpenGLWidgets模块。(#6310)
  • 添加了Qt5-based软件包(PySide2和PyQt5)的Hooks for QtPositioning和QtLocation模块,以确保收集相应的插件。(#6250)
  • 修复了与conda的主要渠道中PyQt5 5.9.2的兼容性。(#6114)
  • 避免Qt-based软件包的挂钩中可能触发的与部分PyQt6安装相关的潜在错误。(#6141)
  • 为PyQt6和PySide6更新了QtNetworkhook,以收集在Qt 6.2中引入的新tls插件。(#6276)
  • 更新gi.repository.GtkSourcehook,以接受具有模块版本钩子配置字典的功能,以允许使用大于3.0的GtkSource版本。(#6267)

引导程序

  • (Windows)抑制了两个snprintf截断警告,这阻止了引导程序使用winlibs MinGW-w64工具链构建。(#6196)
  • 更新Linux引导程序交叉编译器Dockerfile,以允许使用PyPA官方基本映像替换dockcross映像。(#6245)

2.15. PyInstaller 127 变更日志

2.15.24 4.5.1 (2021-08-06)

** Bugfix**

  • 修复钩子加载函数无法找到钩子的问题,如果路径中有空格的话。(#6080)

2.15.25 4.5.0 (2021-08-01)

功能

  • (POSIX)新增exclude_system_librariesfunction选项,以便在.spec文件的Analysis类中排除大多数或全部
    非Python系统库从捆绑包中。在新的_POSIX特定选项_章节中记录。 (#6022)

Bugfix

  • (Cygwin)添加 Add_MEIPASS 到 DLL 搜索路径中,以修复在 cygwin 环境下制作的 onefile 构建中加载 Python 共享库的问题,并在其外部运行。 (#6000)
  • (Linux)在 ldd 输出中针对“未找到”行(即 libsomething.so=>not found)显示缺失库警告,而不是悄悄地忽略它们。 (#6015)
  • (Linux)修复当 libc.so 是引用时误报缺失库的问题。 (#6015)
  • (macOS)修复非框架 Python 构建时无法从 python 可执行文件的导入推断库路径的问题,以便检测 Python 共享库。 (#6021)
  • (macOS)修复使用 Homebrew python 3.9 和 Tcl/Tk 8.6.11 创建的基于 tkinter 的 onedir 应用程序的崩溃问题。 (#6043)
  • (macOS)在修复可执行文件以进行代码签名时,更新 __LINKEDIT 段中的 vmsize 字段的值。 (#6039)
  • 将有关缺失动态链接库的消息从 ERROR 降级到 WARNING。 (#6015)
  • 修复一个字节码解析错误,导致处理使用 ctypes 的模块时出现元组索引错误。 (#6007)
  • 修复 rhtools 的 pkgutil 和 pkg_resources 共同使用时出现的错误。 (#6018)
  • 修复在 Apple M1 上的体系结构检测问题。 (#6029)
  • 修复窗口化 bootloader 中当无法检索未处理异常的回溯时崩溃的问题。 (#6070)
  • 改进加载钩子入口点时的错误处理。 (#6028)
  • 抑制缺失库警告,以适用于 shiboken2(PySide2)和 shiboken6(PySide6)共享库。 (#6015)

不兼容更改

  • (macOS)禁用处理Apple事件以用于 argv 仿真的功能,并转而使用onedir 应用程序捆绑时的仿真。 这一功能在 PyInstaller 4.4 中通过(#5920)响应功能请求(#5436)和(#5908)引入,但是在 Homebrew python 3.9 和 Tcl/Tk 8.6.11 下基于 tkinter 的 onedir 捆绑包中故障。 因此,在调查原因并解决问题之前,此功能被回退/禁用。 (#6048)

第 128 章内容:

钩子

  • 添加针对 pandas.io.formats.style 的钩子,以处理间接导入 jinja2 和缺少的模板文件。 (#6010)
  • 通过将大部分代码合并到公共帮助器函数中来简化 PySide2.QWebEngineWidgetsPyQt5.QWebEngineWidgets。 (#6020)

文档

  • 添加描述钩子配置机制和当前实现选项的页面。 (#6025)

PyInstaller 核心

  • 隔离对第三方钩子目录的发现到单独的子进程中,以避免在主进程中导入软件包。 (#6032)

引导程序构建

  • 允许在非 Windows 指定时使用 --static-zlib 标志或 PYI_STATIC_ZLIB=1 环境变量进行 zlib 的静态链接。 (#6010)

2.15.26 4.4.0 (2021-07-13)

功能

  • (macOS)实现签署 .app 捆绑包(使用实际签名标识或自定义签名标识)。 (#5581)
  • (macOS)实现对 Apple Silicon M1(arm64)平台的支持,并为冻结了的应用程序(thin-binaryx86_64、thin-binaryarm64 和 fat-binaryuniversal2)提供不同的目标支持,并在所有收集的二进制文件中进行构建时体系结构验证和自定义签名。 (#5581)
  • (macOS)在onedir windowed (.app 捆绑包) 模式下,执行 Apple 事件处理以将 odoc 和 GURL 事件转换为在进入冻结的 Python 脚本之前的 sys.argv。 (#5920)
  • (macOS)在窗口化 (.app 捆绑包) 模式下,始终将未处理的异常信息记录到 syslog 中,无论是否处于调试模式。 (#5890)
  • (Windows)添加对 Microsoft 应用商店中 Python 的支持。 (#5816)
  • (Windows)实现用于在窗口化 / 无控制台模式下显示有关未处理异常及其回溯的信息的自定义对话框。 (#5890)
  • 在 PyInstaller.utils.hooks.copy_metadata() 中添加 recursive 选项。 (#5830)
  • 添加–codesign-identity 命令行开关,以使用实际签名标识进行代码签名而不是自定义签名 (仅适用于 macOS)。 (#5581)
  • 添加–osx-entitlements-file 命令行开关,该开关指定在收集的二进制文件的代码签名期间要使用的可选授权文件 (仅适用于 macOS)。 (#5581)
  • 添加–target-arch 命令行开关,以选择冻结应用程序的目标架构 (仅适用于 macOS)。 (#5581)

2.15. PyInstaller 129 变更日志

  • 添加啫喱画面以显示背景图像和文本:可以使用 pyi_splash 模块从 Python 中控制闪屏。 可以使用–splash IMAGE_FILE 选项添加闪屏。 如果启用了可选文本,则闪屏将在 onefile 模式下显示解包进度。 此功能仅受 Windows 和 Linux 支持。 感谢 @Chrisg2000 编写此功能。(#4354、#4887)
  • 添加钩子以支持PyQt6。(#5865)
  • 添加钩子以支持PySide6。(#5865)
  • 通过将关键字参数 hooksconfig 传递给 Analysis,允许指定与 Gtk 应用程序一起打包的图标集、主题和语言环境。
a = Analysis(["my-gtk-app.py"],
...,
hooksconfig={
"gi": {
"icons": ["Adwaita"],
"themes": ["Adwaita"],
"languages": ["en_GB", "zh_CN"]
}
},
...)

(#5853)

  • 自动从UPX处理中排除Qt插件。(#4178)
  • 自动收集分发数据。这通过扫描收集的Python文件来实现,以查找以下用法:
    - pkg_resources.get_distribution()
    - pkg_resources.require()
    - importlib.metadata.distribution()
    - importlib.metadata.metadata()
    - importlib.metadata.files()
    - importlib.metadata.version()
    在所有情况下,仅在以纯字符串文字形式给出分发名称时才会收集元数据。任何更加复杂的都需要一个包含PyInstaller.utils.hooks.copy_metadata()的钩子。 (#5830)
  • 实现对pkgutil.iter_modules()的支持。 (#1905)
  • Windows:如果提供了不受支持的图像格式的图标,则提供有意义的错误消息。(#5755)

第130章 内容:

错误修复

  • (macOS)在onedirmode中构建的App捆绑包现在会从sys.argv中过滤掉-psnxxx命令行参数,以保持与在onefilemode中构建的捆绑包的行为一致。(#5920)
  • (macOS)确保冻结的应用程序报告的macOS SDK版本对应于用于构建引导加载程序和用于构建Python库的SDK版本的最小值。使应用程序报告比Python库和其他打包的库更高版本可能导致macOS尝试启用Python库中不可用的其他功能,这可能导致不一致的行为和与tkinter相关的UI问题。(#5839)
  • (macOS)在构建应用程序包时,在生成的Info.plist中从CFBundleExecutable属性中删除spuriousMacOS/prefix。 (#4413,#5442)
  • (macOS)现在在onedirmode中构建的app捆绑包中反映了拖放文件路径sys.argv。 (#5436)
  • (macOS)现在反映从UI(Open with …)传递给onedirmode中构建的App捆绑的文件路径sys.argv。(#5908)
  • (macOS)解决由于与暗色模式激活相关的问题而导致的tkinter UI问题:在python.org的macOS Intel安装程序中使用黑色Tk窗口,或在Anaconda python中使用白色文本和亮色背景。(#5827)
  • (Windows)启用收集附加VC运行时DLL(msvcp140.dll,msvcp140_1.dll,msvcp140_2.dll和vcruntime140_1.dll),以允许冻结的应用程序在未安装_Visual Studio 2015/2017/2019 Redistributable的Windows系统上运行。(#5770)
  • 通过其关联的加载程序(即FrozenImporter),启用检索__main__module的代码对象。 (#5897)
  • 修复inspect.getmodule()未能通过inspect.stack()获得的堆栈帧解析模块的错误。 (#5963)
  • 修复__main__module被识别为内置而不是模块的错误。 (#5897)
  • 修复_ctypes依赖项扫描中的错误,如果前面的代码包含超过256个名称或256个文字,将导致引用丢失。 (#5830)
  • 修复已损坏的文件名重复_struct和zlib扩展模块的收集。 (#5851)
  • 在使用RH SCL python 3.8或更高版本构建时修复Python库查找。 (#5749)
  • 防止PyInstaller.utils.hooks.copy_metadata()将[…] .dist-info元数据文件夹重命名为[…] .egg-info,这会破坏带有_extra_的pkg_resources.requires()的使用。 (#5774)
  • 防止一个没有嵌入CArchive的引导加载器可被错误地识别为具有CArchive,这会导致带有侧载的CArchive包的冻结应用程序出现未定义的行为。 (#5762)
  • 防止在冻结的脚本中使用sys或os作为全局名称空间中的变量影响在引导期间安装的ctypes挂钩。 (#5797)
  • 修复在没有更改的情况下重新构建EXE。 (#5921)

2.15. PyInstaller 131更改日志

挂钩

    • 添加PostGraphAPI.analysisattribute。挂钩可以通过hook()函数访问Analysis对象。
    • 挂钩可以访问通过Analysis构建分配的Analysis.hooksconfig属性
      Utils.hooks具有get_hook_config()的辅助函数来获取配置文件。(#5853)
  • 添加对PyQt55.15.4的支持。 (#5631)
  • 不要将setuptools.py27compat和setuptools.py33compat排除在外,因为其他setuptools模块需要它们。 (#5979)
  • 在ctypes钩子中切换库搜索顺序:在尝试在sys._MEIPASS中搜索其basename之前,先检查给定名称是否存在(而不是相反)。 (#5907)

引导程序

  • (macOS)默认情况下将引导程序构建为universal2binary(可以通过传递–no-universal2to waf来禁用)。 (#5581)
  • 添加基于Tcl / Tk的启动屏幕,可以从Python中进行控制。在PyInstaller中创建Splash屏幕所需的必要模块位于Splash下。非常感谢@ Chrisg2000编写此功能。 (#4887)
  • 提供一个Dockerfile,用于构建不同架构的Linux引导加载程序。 (#5995)

文献资料

  • 在相关子章节中记录新的macOS多架构支持和代码签名行为。 (#5581)

引导程序构建

  • 从apt.llvm.org中的clang-11更新linux64 Vagrant VM中的clang,以便可以构建universal2macOS引导程序。 (#5581)
  • 将crossosx Vagrant VM更新为从Xcode的Command Line Tools构建工具链,而不是全Xcode软件包。 (#5581)

2.15.27 4.3(2021-04-16)

特征

  • 提供基本的FrozenImporter.get_source()实现,允许从由钩子收集为数据文件的.py文件中读取源代码。 (#5697)
  • 将CArchive(因此onefile执行文件)允许的最大允许大小从2 GiB提高到4 GiB。 (#3939)
  • _unbuffered stdio_模式(u选项)现在设置Py_UnbufferedStdioFlag标志以在Python库中启用无缓冲stdio模式。 (#1441)
  • Windows:设置EXE校验和。减少来自防病毒软件的误报。 (#5579)
  • 添加新的命令行选项,将其映射到hookutils的集合功能:–collect-submodules,–collect-data,–collect-binaries,–collect-all和–copy-metadata。 (#5391)
  • 为从setuptools入口点定义插件收集的新钩子实用程序collect_entry_point(). (#5734)

错误修复

  • (macOS) 在 Apple M1 上只使用 ARM64 版本的 Python 运行时出现 FixBad CPU type in executable 错误时,解决了 helper-spawned python processes 运行错误的问题。 (#5640)
  • (OSX) 修复了对于系统库的缺失 library error 信息,因为PyInstaller从不收集它们,且从 Big Sur 开始,它们会被系统隐藏。 (#5107)
  • (Windows) 将默认缓存目录更改为 LOCALAPPDATA (原为 APPDATA)。这是为了确保缓存数据不会与漫游配置文件同步。对于这个版本和未来版本,AppData\Roaming\pyinstaller 可以安全删除。 (#5537)
  • (Windows) 修复了当通过–icon NONE禁用图标时,onefile 构建无法嵌入清单的问题。 (#5625)
  • (Windows) 修复了通过–debug imports 或 --debug all 命令行开关以及启用日志记录(通过 import logging 启用)构建的 frozen 程序,在 innoconsole 模式下立即崩溃并显示 Failed to execute script pyiboot01_bootstrap message 的问题。 (#4213)
  • CArchiveReader 现在对MAGIC执行完整的后向文件搜索,允许pyi-archive_viewer打开附加的数据(例如数字签名)嵌入式包后的二进制文件。 (#2372)
  • 修复了MERGE(),以便以它们的完整共享包相对路径而不是仅限于基本名称来正确设置对嵌套资源的引用。 (#5606)
  • 修复了在onefile 构建中,如目标完整路径超过260个字符,则无法提取文件的问题。 (#5617)
  • 修复了在退出应用程序或返回上级时,pyi-archive_viewer 崩溃的问题。 (#5554)
  • 修复了在 MSYS 环境中创建的 onefile 构建中提取嵌套文件的问题。 (#5569)
  • 修复了由于文件路径中的 Unicode 字符导致的安装问题。 (#5678)
  • 修复了在手动添加到 hiddenimports 时 python 3.7 及更早版本中由 ctypes 引起的构建时错误。 (#3825)
  • 在冻结脚本由于未处理的异常而失败时,现在使用返回代码1而不是-1,以使行为与 Python 解释器一致。 (#5480)
  • Linux:修复二进制依赖项扫描器以支持 glibc2.33 引入的 ldconfig 更改。 (#5540)
  • 防止MERGE(multipackage)为重复的 TOC 条目创建自引用。 (#5652)
  • 现在,PyInstaller-frozen 的onefile 程序即使引导程序作为位置独立可执行文件 (PIE) 构建也与 staticx 兼容。 (#5330)
  • 移除对 matplotlib3.4.0rc1 中删除的一个私有函数的依赖。 (#5568)
  • 从 base_library.zip 中剥离.pyc 模块的绝对路径,以启用重复生成的构建,忽略 Python 安装位置差异。 (#5563)
  • (OSX) 修复了在 macOS 上的pycryptodomex问题。 (#5583)
  • 允许编译的模块被收集到 base_library.zip 中。 (#5730)
  • 修复了在某些 Linux C 编译器组合上扫描 ctypes.CDLL(‘libc.so’) 时触发的构建错误。 (#5734)
  • 改进了模块扫描的性能并减少了堆栈使用。 (#5698)

2.15 版更改日志 PyInstaller 133

钩子

  • 添加对 Conda Forge 的NumPy 发行版的支持。 (#5168)
  • 通过pkg_resources添加支持包含内容的包。该实现通过 pkg_resources.resource_exists()、resource_isdir() 和 resource_listdir() 对一个冻结的包(PYZ 嵌入式和在文件系统上的,以此类推)进行查询/列表资源。 (#5284)
  • 钩子:为GtkosxApplication导入正确的 typelib。 (#5475)
  • 防止 matplotlib 钩子在无法确定 matplotlib 数据目录路径时收集当前工作目录。 (#5629)
  • 更新 pandashook,以兼容版本 1.2.0 及以上。 (#5630)
  • 更新distutils.sysconfig的钩子,以使其与 pyenv-virtualenv 兼容。 (#5218)
  • 更新sqlalchemy钩子,以支持版本 1.4.0 及以上。 (#5679)
  • 更新sysconfig的钩子,以使其与 pyenv-virtualenv 兼容。 (#5018)

引导

  • 实现了对嵌入式档案的完整后向文件搜索。 (#5511)
  • 当存档大文件时,从嵌入式档案中执行文件提取时,以流式存储的方式进行,以限制内存占用。 (#5551)
  • 将__file__属性设置为__main__模块(入口点脚本)中的绝对文件名称,即在_MEIPASS内的脚本文件名称。 (#5649)
  • 从 Linux 启用 FreeBSD 的交叉编译。 (#5733)

文档

  • Doc:为 macOS Bundle 添加版本规范文件选项。 (#5476)
  • 更新“运行时信息”部分,以反映__file__在__main__模块内的行为变化。 (#5649)

PyInstaller 核心

  • 放弃对 python 3.5 的支持;于2020年9月已结束生命周期。 (#5439)
  • 将与内置对应的 Python 扩展模块收集到 lib-dynload 子目录中,而不是直接收集到 bundle 的根目录中。这可以防止它们遮盖位于一个包中并通过 ctypes 或 cffi 加载的具有相同基本名称的共享库,并且减少了捆绑包的根目录混乱。 (#5604)

134 第2章 内容:

重大变化

  • 不再收集pyconfig.h和sysconfig的makefile。你应该使用get_config_vars(),它不再依赖于这些文件,而不是get_config_h_filename()和get_makefile_filename()。 (#5218)
  • 现在将__file__属性设置为在_MEIPASS内部的绝对文件名称,而不仅仅是脚本文件名称,对于__main__模块(入口点脚本)。这更符合 unfrozen 脚本中__file__的行为,但可能会破坏明确依赖于旧的冻结行为的现有代码。 (#5649)

2.15.28 4.2 (2021-01-13)

功能

  • 添加挂钩实用程序以查找Anaconda发行版的二进制依赖项。 (#5213)
  • (OSX)使用codesign --remove-signature自动从Python共享库的收集副本中删除签名。这适用于使用最近的Python版本为macOS进行onedir和onefile构建的情况,其中在PyInstaller收集的Python库的已作废签名会防止后者被加载。 (#5451)
  • (Windows)PyInstaller的控制台或窗口图标现在是在冷冻时添加的,不再内置于引导加载程序中。此外,使用–icon = NONE允许不应用任何图标,从而使操作系统显示一些默认图标。 (#4700)
  • (Windows)在构建应用程序的清单中启用longPathAware选项,以支持Windows 10 v.1607及更高版本上的长文件路径。 (#5424)

故障修复

  • 修复加速应用程序运行时加载插件类型模块的问题:如果插件路径比sys._MEIPATH长1个字符(例如“$ PWD / p / plugin_1”和“$ PWD / dist / main”),那么插件相对导入插件的子模块和冻结的应用程序包含同名模块时,将导入冻结的应用程序模块。 (#4141,#4299)
  • 确保冻结包的规范具有set_submodule_search_locations,以修复与importlib_resources 3.2.0及更高版本的兼容性。 (#5396)
  • 修复:如果“noarchive”build选项更改,则不进行重建。 (#5404)
  • (OSX)修复由于最近的Python版本收集的Python共享库的签名无效而无法加载的问题。 (#5062,#5272,#5434)
  • (Windows)PyInstaller的默认图标不再内置于引导加载程序中,而是在冷冻时添加。因此,在指定图标时,只包含该图标的可执行文件并在快捷方式上显示。 (#870,#2995)
  • (Windows)修复在a.spec文件中将VSVersionInfo作为version参数传递给EXE()时出现“toc is bad”的错误消息。 (#5445)
  • (Windows)修复从exe或dll读取清单时出现异常的问题。 (#5403)
  • (Windows)通过创建不存在的路径并扩展环境变量(例如%LOCALAPPDATA%)解决–runtime-tmpdir选项的问题。 (#3301,#4579,#4720)

** 2.15 PyInstaller 135的更改日志**

挂钩

  • (GNU / Linux)将xcbglintegrations和egldeviceintegrations插件作为Qt5Gui的一部分收集。 (#5349)
  • (macOS)修复:无法对使用GTK构建的应用程序进行代码签名(#5435)
  • (Windows)添加win32ctypes.core的挂钩。 (#5250)
  • 添加scipy.spatial.transform.rotation的挂钩以修复与SciPy 1.6.0的兼容性。 (#5456)
  • 添加hook-gi.repository.GtkosxApplication以修复在Gtk macOS应用程序中出现TypeError的问题。 (#5385)
  • 添加挂钩实用程序以查找Anaconda发行版的二进制依赖项。 (#5213)
  • 修复在PyQt5和PySide2挂钩中Qt5library可用性检查,以重新启用早于5.8的Qt5的支持。 (#5425)
  • 实现exec_statement_rc()和exec_script_rc()作为exec_statement()和exec_script()的退出代码返回副本。实现can_import_module()助手,以帮助需要查询模块可用性的挂钩。 (#5301)
  • 限制无法导入子包对collect_submodules()结果的影响,以确保从所有其他子包中收集模块。 (#5426)
  • 删除过时的pygame挂钩。 (#5362)
  • 将keyringhook更新为收集元数据,这是后端发现所需的。 (#5245)

引导加载程序

  • (GNU / Linux)通过/ proc / self / exe上的readlink()重新引入可执行文件解析,并使用prctl()和PR_GET_NAME和PR_SET_NAME保留进程名称。 (#5232)
  • (Windows)使用用户的SID而不是S-1-3-4创建临时目录,以解决wine中对后者支持不足的问题。这使onefilebuilds可以再次在wine下运行。 (#5216)
  • (Windows)使用_snprintf而不是snprintf来构建MSC时与PATH_MAX超过的路径导致的路径处理代码中的错误。需要Visual Studio 2015或更高版本。清理MSC代码路径以处理其他编译器警告。 (#5320)
  • (Windows)修复了使用Visual Studio在Windows下构建引导加载程序测试套件时遇到的问题。这解决了当cmocka存在于构建环境中时的构建错误。 (#5318)
  • (Windows)修复了MinGW 10.2产生的编译器警告,以允许构建bootloader而无需抑制警告。 (#5322)
  • (Windows)修复了在由于未捕获异常而冻结的脚本终止时,窗口化+调试bootloader变体未正确显示异常消息和traceback信息的bug。 (#5446)

PyInstaller Core

  • (Windows)避免使用启用控制流程保护(CFG)的DLL的UPX。 (#5382)
  • 在noarchive模式中不使用.pyomodule文件后缀(自PEP-488以来已删除)。 (#5383)
  • 改进对PEP-420命名空间包的支持。 (#5354)
  • 从CArchive(PKG)中剥离.pyc模块中的绝对路径。这使得构建的可重复性无需匹配构建环境的位置。 (#5380)

136章2.内容摘录:

2.15.29 4.1(2020-11-18)

功能

  • 添加对Python 3.9的支持。 (#5289)
  • 添加对Python 3.8的支持。 (#4311)

故障修复

  • 如果包的__init__模块是扩展模块,则修复无限递归的问题。 (#5157)
  • 删除重复的日志记录消息(#5277)
  • 修复sw_64体系结构支持(#5296)
  • (AIX)在搜索libpython时包括标记为python-malloc的库。 (#4210)

挂钩

  • 添加addexclude_datasinclude_datasfilter_submodules参数到collect_all()函数中,这些参数与collect_data_files函数的excludesincludes参数以及collect_submodules函数的_filter_参数相对应。(#5113)
  • 添加difflib钩子以避免拉取doctests,这仅在作为主程序运行时才需要。
  • 添加distutils.util钩子以避免拉取lib2to3的unittests,这在冻结软件包中很少使用。
  • 添加heapq钩子以避免拉取doctests,这仅在作为主程序运行时才需要。
  • 添加multiprocessing.util钩子以避免拉取python测试套件,因此例如tkinter也不会被拉取。
  • 添加numpy._pytesttester钩子以避免拉取pytest。
  • 添加pickle钩子以避免拉取doctests和argpargs,这仅在作为主程序运行时才需要。
  • 添加PIL.ImageFilter钩子以避免拉取numpy,这是一个可选组件。
  • 添加setuptools钩子以避免拉取numpy,仅在已安装时导入,不用作依赖。
  • 添加zope.interface钩子以避免拉取pytest的unittests,这将在冻结软件包中很少使用。
  • 添加hook-gi.repository.HarfBuzz以修复Gtk应用程序的Typelib错误。(#5133)
  • 通过_DJANGO_SETTINGS_MODULE_环境变量启用覆盖Django设置路径。(#5267)
  • 修复_collect_system_data_files_以扫描给定的输入路径而不是其父路径。_collect_all_system_data_返回的文件路径现在相对于输入路径。(#5110)
  • 修复exec_script()eval_script()中的参数顺序。(#5300)
  • gevent钩子不必要地捆绑HTML文档、__pycache__文件夹、测试和生成的.c和.h文件。(#4857)
  • gevent:不拉取测试套件(仍需完善)
  • 修改gevent钩子,以排除测试子模块。(#5201)
  • 当include_py_files为False时,防止collect_data_files收集.pyo文件。(#5141)
  • 防止从模块导入期间输出到stdout的内容进入由collect_submodules收集的模块列表。(#5244)

2.15.PyInstaller 137更新日志

  • 删除运行时钩子并修复matplotlib数据的常规钩子,以支持matplotlib>=3.3.0,在版本3.1<= &❤️.3上修复弃用警告,并对<3.1版本进行正常处理。(#5006)
  • 删除已弃用的PyQt4和PySide支持。(#5118,#5126)
  • 排除过时的compat模块。
  • 更新sqlalchemy钩子以支持v1.3.19及更高版本,通过添加sqlalchemy.ext.baked作为隐藏导入项。(#5128)
  • 更新tkinter钩子,以收集Tcl模块目录(tcl8)以及Tcl/Tk数据目录。(#5175)
  • (GNU/Linux) {PyQt5,PySide2} .QtWebEngineWidgets:修复搜索额外NSS库以防止/system/ nss / *。那里是空的。
  • (OSX)在tkinterhook中避免从系统Tcl/Tk框架中收集数据,因为我们也没有收集它们的共享库。仅影响仍使用系统Tcl/Tk 8.5的python版本。(#5217)
  • (OSX)从v.3.6.5开始,正确定位官方python.org python构建中捆绑的tcl/tk框架。(#5013)
  • (OSX)修复在PyQt5.QtWebEngineWidgets rthook中设置QTWEBENGINEPROCESS_PATH。(#5183)
  • (OSX)PySide2.QtWebEngineWidgets:将QtQmlModels添加到包含的库中。(#5150)
  • (Windows)从tkinterhook中删除过时的python2.4-era_handle_broken_tcl_tkwork-around,适用于旧的虚拟环境。(#5222)

引导程序

  • 修复使用free()而不是PyMem_RawFree()释放Python分配的内存导致的问题。(#4441)
  • (GNU/Linux)避免temp路径丢失时的segfault。(#5255)
  • (GNU/Linux)在pyi_path_dirname()中用snprintf()替换astrcpy()来确保结果字符串始终以空字符结尾。(#5212)
  • (OSX)添加已运行的应用程序通过Apple事件转发接受URL和拖放事件的功能。(#5276)
  • (OSX)将MACOSX_DEPLOYMENT_TARGET从10.7提升至10.13。(#4627,#4886)
  • (OSX)修复“重新打开”时重新激活运行的应用程序的问题。(#5295)
  • (Windows)在pyi_path_fullpath中使用_wfullpath()而不是_fullpath(),以允许路径中有非ASCII字符。(#5189)

文档

  • 在文档的“构建引导程序”部分中添加zlib构建要求。(#5130)

2.15章PyInstaller核心:

  • 如果发生RecursionError,则添加信息性消息。 (#4406,#5156)
  • 防止具有冲突名称的本地目录遮盖系统库。(#5182)
  • 使用模块加载器获取模块内容,而不是从早期Python 2.x时期开始的古怪方式。(#5157)
  • (OSX)在系统框架中免除Tcl/Tk动态库的相对路径覆盖。修复在仍使用系统框架的旧python.org构建中缺少Tcl/Tk动态库。 (#5172)

测试套件和持续集成

  • 用标记替换特定于平台的测试的skipif_xxx。(#1427)
  • 测试/CI:测试故障将自动重试一次。(#5214)

引导程序构建

  • 修复自PyInstaller 3.6以来破坏的AppImage版本。(#4693)
  • 更新构建系统以使用Python 3。
  • 修复“–distpath”参数对“BUNDLE”步骤的无效性。(#4892)
  • 提高代码签名和验证机制的健壮性。(#3550,#5112)
  • 对GUI应用程序默认使用高分辨率模式。 (#4337)

2.15.30更新日志4.0(2020-08-08)

特点

  • 提供 setuptools 的 entrypoints,以使其他软件包能够提供针对特定包的 PyInstaller 钩子,并为这些钩子提供测试。需要钩子的 Python 包的维护者被邀请使用这个新特性,为他们的包提供最新的 PyInstaller 支持。这很容易实现,详见我们的示例项目 (#4232、#4301、#4582)。非常感谢 Bryan A. Jones 实现了重要的部分。
  • 新的 pyinstaller-hooks-contrib 包现已提供每月更新的钩子。安装 PyInstaller 时会自动安装该软件包,但也可以独立更新。非常感谢 Legorooj 设置了新包并将钩子移动到那里。
  • collect_data_files 的钩子实用程序函数添加 excludesincludes 参数。
  • 更改钩子集合顺序,以使钩子优先顺序为命令行,然后是 entry-point,最后是 PyInstaller 内置功能 (#4876)。

2.15. PyInstaller 139 更改记录

Bug 修复

  • (AIX) 在搜索 libpython 时,包括 python-malloc 标记的库。(#4738)
  • (Win32) 修复因 posix 和 windows inos 实现差异导致的安全警报。 path.dirname()。(#4707)
  • (Win32) 修复 versioninfo 的结构格式字符串。(#4861)
  • (Windows) cv2:如果可用,包含 opencv_videoio_ffmpeg*.dll。(#4999)
  • (Windows) GLib:为 g_spawn* API 的生成助手可执行文件打包。(#5000)
  • (Windows) PySide2.QtNetwork:在 BinariesPath 之外,也在 PrefixPath 中搜索 SSL DLL。(#4998)
  • (Windows) 在 onefile 模式下以 32 位 python 构建时,每次都设置 requestedExecutionLevelmanifest 键,并嵌入清单。(#4992)
  • - (AIX) 修复未初始化变量。(#4728、#4734)
  • 允许在不同驱动器上构建源代码。(#4820)
  • 将 Python 视为可能的库二进制路径。解决了如果在 OSX 上通过 brew 安装 Python3,则找不到 python 的问题(#4895)
  • 确保 onefile 包中的共享依赖项可以在引导加载程序中打开。
  • 确保 base_library.zip 的重复性构建。(#4654)
  • 修复 utils/misc.py 中出现的 FileNotFoundError,该错误发生在将命名空间处理为文件名时。(#4034)
  • 修复多包装问题。_MERGE_ 类现在将具有正确的共享依赖项之间的相对路径,可以被引导程序正确地打开。(#1527、#4303)
  • 修复了试图避免在 .spec 文件中使用硬编码路径时的回归问题。
  • 从根本上解决了加密 Python 字节码 (–key option) 的基本库问题。非常感谢 Matteo Bertini 最终解决了这一问题。(#2365、#3093、#3133、#3160、#3198、#3316、#3619、#4241、#4652)
  • 当剥离编译代码对象中路径的前导部分时,现在将剥离最长可能的导入路径。(#4922)

不兼容的更改

  • 不再支持 Python 2.7。现在,最低要求的版本是 Python 3.5。最后一个支持 Python 2.7 的版本是 PyInstaller 3.6。(#4623)
  • 许多钩子现在是新的 pyinstaller-hooks-contrib 存储库的一部分。有关详细列表,请参见下文。

2.15. PyInstaller 139 内容:

钩子

  • 为scipy.stats._stats添加钩子(自scipy 1.5.0起需要)。(#4981)
  • 防止hook-nltk添加不存在的目录。(#3900)
  • 修复importlib_resources钩子现代版本(1.1.0之后)。(#4889)
  • 修复包含的pkg_resources和packaging中的隐藏导入。 (#5044)
    - 为pkg_resources hook添加更多的隐藏导入。
    - 对可能是pkg_resources重复的packaging进行pkg_resources hook镜像。
    _vendor.packaging.
  • 更新setuptools v45.0.0的pkg_resources hook。
  • 将QtQmlModels添加到OS X上的QtWebEngine。(#4631)
  • 修复从conda-forge构建中检测Qt5库和依赖项的问题。(#4636)
  • 添加断言消息,以便由于Hook冲突而产生错误的用户可以解决它(#4626)。
  • 这些钩子已移至新的pyinstaller-hooks-contrib存储库:BTrees、Crypto、Cryptodome、
    IPython、OpenGL、OpenGL_accelerate、Xlib、accessible_output2、adios、aliyunsdkcore、amazonproduct、apdirs、appy、astor、astroid、astropy、avro、bacon、boto、boto3、botocore、certifi、clr、countrycode、cryptography、cv2、cx_Oracle、cytoolz、dateparser、dclab、distorm3、dns、docutils、docx、dynaconf、enchant、enzyme、eth_abi、eth_account、eth_hash、eth_keyfile、eth_utils、faker、flex、fmpy、gadfly、gooey、google等。*、gst、gtk、h5py、httplib、httplib2、imageio、imageio_ffmpeg、jedi、jinja2、jira、jsonpath_rw_ext、jsonschema、jupyterlab、kinterbasdb、lang-
    codes、lensfunpy、libaudioverse、llvmlite、logilab、lxml、lz4、magic、mako、markdown、migrate、mpl_toolkits、
    mssql、mysql、nacl、names、nanite、nbconvert、nbdime、nbformat、ncclient、netCDF4、nltk、nnpy、notebook、
    numba、openpyxl、osgeo、passlib、paste、patsy、pendulum、phonenumbers、pint、pinyin、psychopy、psycopg2、pub-
    sub、pyarrow、pycountry、pycparser、pyexcel、pyexcelerate、pylint、pymssql、pyodbc、pyopencl、pyproj、pysnmp、
    pytest、pythoncom、pyttsx、pywintypes、pywt、radicale、raven、rawpy、rdflib、redmine、regex、reportlab、reportlab、
    resampy、selenium、shapely、skimage、sklearn、sound_lib、sounddevice、soundfile、speech_recognition、storm、
    tables、tcod、tensorflow、tensorflow_corethon、text_unidecode、textdistance、torch、ttkthemes、ttkwidgets、u1db、
    umap、unidecode、uniseg、usb、uvloop、vtkpython、wavefile、weasyprint、web3、webrtcvad、webview、win32com、
    wx、xml.dom、xml.sax、xsge_gui、zeep、zmq。
  • 这些钩子已加入,同时已移到新的_pyinstaller-hooks-contrib_存储库中:astor(#4400、#4704)、argon2(#4625)、bcrypt(#4735)、(Python的低功耗蓝牙客户端)(#4649)jaraco.text(#4576、#4632)、LightGBM。(#4634)、xmldiff(#4680)、puremagic(基于魔术数字识别文件)(#4709) webassets(#4760),tensorflow_core(支持tensorflow模块转发逻辑)(#4400、#4704)
  • 这些更改已应用于现已移至新的_pyinstaller-hooks-contrib_存储库的钩子
    - 为v2.0.0的Bokeh hook更新(#4742、#4746)
    - 在Windows上为未安装conda的shapely修复shapely hook。(#2834,#4749)

2.15. PyInstaller 141更改日志

Bootloader

  • 重构引导程序,从使用带“该字符串是否终止”检查的strcpy/strncpy到使用snprintf();在更多的地方进行检查。
    (这始于修复关于strncpy和strncat的GCC警告。)
  • 修复:在复制文件时,大多数情况下都复制了过多的数据。这会破坏文件并阻止使用共享依赖项。(#4303)
  • 在调试和窗口模式中,显示回溯以帮助调试pyiboot01_bootstrap错误。(#4213,#4592)
  • 开始引导程序基本功能的小型测试套件。(#4585)

文档

  • 添加针对AIX的平台特定用法说明和引导程序构建说明。(#4731)

PyInstaller核心

  • 提供setuptools entrypoints,以使其他软件包能够提供钩子,这些钩子针对该软件包特定,以及这些钩子的测试。有关更多信息,请参见https://github.com/pyinstaller/hooksample。(#4232,#4582)

引导程序构建

  • (AIX) AIX加载程序不识别-X32或-X64参数,因此需要删除此代码。(#4730,#4731)
  • (OSX)允许最终用户通过环境变量覆盖MACOSX_DEPLOYMENT_TARGET和mmacosx-version-min,并将10.7设置为两者的回退值。(#4677)
  • 当已经使用–noconfirmwhen选项时,请勿打印关于该选项的信息。(#4727)
  • 将wafto版本更新到2.0.20(#4839)

2.15.31旧版本

PyInstaller 3.0 – 3.6更改日志

3.6 (2020-01-09)

**重要提示:**这是支持Python 2.7的PyInstaller的最后一个版本。Python 2已经结束生命周期,许多软件包即将放弃对Python 2.7的支持-或已经做到了。

安全

  • [安全] (Win32) 修复CVE-2019-16784:由于sys._MEIPATH的不安全目录权限而导致的本地特权升级。这个安全修复影响了由PyInstaller在“一个文件”模式下冻结的所有Windows软件。虽然PyInstaller本身没有受到漏洞的影响,但是PyInstaller在“一个文件”模式下冻结的所有Windows软件都是有漏洞的。
    如果您正在使用PyInstaller以“一个文件”模式冻结Windows软件,则应升级PyInstaller并重新构建软件。

特性

  • (Windows):以窗口模式构建的应用程序将其调试消息发送到任何连接的调试器或DebugView而不是消息框中。(#4288)
  • 当路径已经存在一个文件时,提供更好的错误消息以指明期望为目录。(#4591)

漏洞修复

  • (Windows):_VSVersionInfo_再次允许用作可执行文件的版本参数。(#4381,#4539)
  • (Windows):修复modulegraph找不到MSYS2 dll的问题。(#4125,#4417)
  • (Windows):添加资源、图标等时使用的引导程序的临时副本不再创建在%TEMP%中,而是在—workpath中创建,从而解决在某些系统上反病毒软件会立即清理%TEMP%的问题。(#3869)
  • ldconfig缺失或无法使用时不再使构建失败。(#4261)
  • 修复了IPython扩展的加载。(#4271)
  • 修复_distutils_的pre-find-module-path钩子以兼容_virtualenv>=16.3_。 (#4064,#4372)
  • 当无法找到Python库时,提高错误报告的信息显示。(#4162)

钩子

  • 添加hook用于_avro_(序列化和RPC框架)(#4388),django-babel(#4516),enzyme(#4338),
    _google.api(resp.google.api.core)(#3251),_google.cloud.bigquery(#4083,#4084),google.cloud.pubsub
    (#4446),google.cloud.speech(#3888),nnpy(#4483),passlib(#4520),pyarrow(#3720,#4517),
    pyexcel_及其插件io,ods,ods3,odsr,xls,xlsx,xlsxw(#4305),pysnmp(#4287),scrapy(#4514),
    skimage.io(#3934),sklearn.mixture(#4612),macOS_和_Windows_上的_sounddevice(#4498),text-unidecode(#4327,#4530),
    google-cloud-kms客户端库(#4408),ttkwidgets(#4484)和_webrtcvad
    (#4490)。
  • 修正Qt翻译文件的位置。(#4429)
  • 排除导入_pkg_resources_以修复捆绑问题。(#4263,#4360)
  • 修复了用于pywebview的hook以收集所有所需的库和数据文件的问题。(#4312)
  • 修复numpy和scipy的hook以考虑Windows上额外dll的位置差异。(#4593)
  • 修复pysoundfile的hook以在_OSX_和_Windows_上正确地捆绑文件。(#4325)
  • 修复钩子以将_ pint_的元数据也复制为必需以在运行时检索版本。(#4280)
  • 通过模仿PyQt5方法,修复了_PySide2.QtNetwork_的钩子。(#4467,#4468)
  • pywebview的hook现在仅收集正确操作系统(Windows)的数据文件和动态库。pywebview的hook仅捆绑所需的“lib”子目录。(#4375)

2.15. PyInstaller 143的变更日志

  • 更新与PySide2.QtWebEngineWidgets相关的钩子,确保复制到分发所需的支持视图文件。(#4377)
  • 更新PyQt5加载程序,以支持PyQt> = 5.12.3。(#4293,#4332)
  • 更新PyQt5以打包64位SSL支持DLL。(#4321)
  • 更新PyQt5,以正确放置OpenGL DLL以支持PyQt> = 5.12.3。(#4322)
  • (GNU/Linux)使用的_GdkPixbuf_钩子与Ubuntu和Debian兼容。(#4486)。

引导程序

  • (OSX):在应用程序从自定义协议处理程序启动时添加支持向程序参数追加URL。(#4397,#4399)
  • (POSIX)对于单文件二进制文件,如果通过符号链接启动程序,则第二个进程现在保留符号链接的基本名称。(#3823,#3829)
  • (Windows):如果与应用程序捆绑,对python35.dll(或更高版本)在未安装Universal CRT更新的旧版Windows(7、8、8.1)系统上加载之前进行了proactivley加载ucrtbase.dll进行解决未解决的符号错误的问题。(#1566,#2170,#4230)
  • 添加自己的实现来使用_ strndup_ 和 strnlen 在其中一个平台上缺少时使用。

PyInstaller核心

  • 在使用Python 3.7时,现在在_base_library.zip_中使用基于哈希的_.pyc_文件,如** PEP 552**所指定。(#4096)

引导程序构建

  • (MinGW-w64)修复:.rc.o文件未找到的错误。(#4501,#4586)
  • 添加检查是否可用_ strndup_ 和 strnlen
  • 添加OpenBSD支持。(#4545)
  • 修复在Solaris 10上的构建问题。
  • 修复在_configure_阶段检查编译器标志。实际上,检查编译器标志的检查从未起作用。(#4278)
  • 在update-waf脚本中更新公钥的URL。(#4584)
  • 将waf升级到版本2.0.19。

3.5(2019-07-09)

特性

  • (Windows):如果第一个脚本是_a.pywf文件,则强制使用_–windowed_选项。这仍可能被规范文件覆盖。(#4001)
  • 支持图标文件、资源文件和版本资源文件的相对路径。(#3333,#3444)
  • 添加对RedHat软件集合(SCL)Python 3.x的支持。(#3536,#3881)
  • 仅在该平台上安装特定于平台的依赖项。(#4166,#4173)

144第2章. 内容:

  • 新的命令行选项:–upx-exclude,允许用户防止使用UPX压缩二进制文件。(#3821)

漏洞修复

-(conda)修复conda/anaconda平台的检测。
-(GNU/Linux)修复Anaconda Python库的搜索。(#3885,#4015)
-(Windows)通过嵌入清单修复单文件模式下的UAC。 (#1729,#3746)
-(Windows\Py3.7)现在可以在python.exe PE Header中列出VERSION.dll而不是pythonXY.dll时定位pylib(#3942,#3956)

  • 如果模块图引用PyQt5或PySide2但无法导入,则避免出现错误。 (#3997)
  • 正确解析–debug=import,–debug=bootloader和–debug=noarchive命令行选项。(#3808)
  • 不要将PyQt5和PySide2文件视为OS X窗口构建中的资源。 这样做会导致在Qt 5.12下生成的冻结应用程序失败。(#4237)
  • 打开_all_文本文件时明确指定UTF-8的编码方式。(#3605)
  • 修复将spec文件中的datas内容追加到binaries而不是内部datas的崩溃。(#2326,#3694)
  • 在连续运行中从–onefile更改为–onedir时修复崩溃。(#3662)
  • 修复在Anaconda上发现Qt路径。(#3740)
  • 修复读取包括非ASCII字符的XML清单文件时引发的编码错误。 这个错误禁止构建具有非ASCII字符的文件名的可执行文件。(#3478)
  • 修复了Qt5LibraryInfo中对QCoreApplication构造函数的输入。 现在,核心应用程序的初始化和完成以及系统范围和应用程序范围的设置更加安全。(#4121)
  • 修复使用pip 19.0进行安装。(#4003)
  • 修复版本更新期间的PE文件损坏。(#3142,#3572)
  • 在虚假的‘site`模块中将_USER_BASE_设置为空字符串,而不是None,因为Jupyter Notebook要求它为‘str’。(#3945)
  • 查询PyQt5以确定是否支持SSL,仅在支持SSL时添加SSL DLL。 此外,搜索路径以查找SSL DLL,而不是在Qt的BinariesPath中查找。(#4048)
  • 要求pywin32-ctypes版本0.2.0,最低支持Python 3.7。(#3763)
  • 使用pkgutil而不是文件系统操作与模块交互。(#4181)

不兼容的更改

  • PyInstaller不再针对即将到期的Python 3.4进行测试。
  • 函数compat.architecture(),compat.system()和compat.machine()已经被同名变量替换。 这避免了多次评估的保存。
  • 需要–debug参数的选项,而不是假定默认值为all。(#3737)

PyInstaller 145的更改日志

钩子

  • 添加了用于aliyunsdkcore(#4228),astropy(#4274),BTrees(#4239),dateparser.utils.strptime(#3790),faker(#3989,#4133),gooey(#3773),GtkSourceView(#3893),imageio_ffmpeg(#4051),importlib_metadata和importlib_resources(#4095),jsonpath_rw_ext(#3841),jupyterlab(#3951),lz4(#3710),magic(#4267),nanite(#3860),nbconvert(#3947),nbdime(#3949),nbformat(#3946),notebook(#3950),pendulum(#3906),pysoundfile(#3844),python-docx(#2574,#3848),python-wavefile(#3785),pytzdata(#3906),PyWavelets pywt(#4120),pywebview(#3771),radicale(#4109),rdflib(#3708),resampy(#3702),sqlalchemy-migrate(#4250),textdistance(#4239),tcod(#3622),ttkthemes(#4105)和umap-learn(#4165)的挂钩。
  • 添加用于certifi的运行时钩子。(#3952)
  • 更新‘notebook’钩子以查找jupyter_core报告的所有Jupyter路径。(#4270)
  • 修复‘notebook’钩子,仅包括实际存在的目录。(#4270)
  • 修复_setuptools.extern.six_的pre-safe-import-module钩子。(#3806)
  • 修复OS X上的QtWebEngine挂钩。(#3661)
  • 修复在没有NSS子目录(例如Archlinux)的发行版上QtWebEngine挂钩。(#3758)
  • 在eth_hash包中包含动态导入的后端。(#3681)
  • 只在该平台上安装特定于平台的依赖项。(#4168)
  • 如果QML目录不存在,请跳过打包PyQt5 QML文件。(#3864)
  • 在PyCryptodome中支持ECC。(#4212,#4229)
  • 更新PySide2挂钩以遵循PyQt5方法。(#3655,#3689,#3724,#4040,#4103,#4136,#4175,#4177,#4198,#4206)
  • 为v3.0+更新jsonschema钩子。(#4100)
  • 为正确打包Sphinx 1.8更新Sphinx钩子。

引导器

  • 将捆绑的zlib库更新为1.2.11,解决漏洞。(#3742)

文档

  • 更新–help所产生的文本,以说明–debug参数需要一个选项。 在Sphinx构建流程中正确格式化此参数。(#3737)

项目和进程

  • 从pyproject.toml的PEP-518“build-system”表中删除,以修复使用pip 19.0进行安装。

PyInstaller核心

  • 支持_COLLECT_和_BUNDLE_中的文件夹。(#3653)
  • 完全删除_pywin32_依赖项,其发布不稳定,pypi上的版本可能不再有未来发布。 要求_pywin32-ctypes_,后者是纯Python。(#3728,#3729)
  • modulegraph:与上游版本0.17对齐。
  • 现在打印更具描述性的错误,而不是转储跟踪。 (#3772)
  • 抑制有关在Win 10上缺少UCRT依赖项的警告。(#1566,#3736)

测试套件和持续集成

  • 修复在 Windows Python 3.7 x64 上的test_stderr_encoding()和test_stdout_encoding()失败问题 (#4144)
  • 更新测试时所使用的软件包,防止 pyup修改test/requirements-tools.txt (#3845)
  • 重写代码以避免RemovedInPytest4Warning:不再支持直接应用标记到参数,建议使用pytest.param(…, marks=…) (#4140)
  • 在Xenial下运行Travis测试;删除已弃用的sudo: false标签 (#4140)
  • 通过使用正确的扩展语法,更新Markdown测试以符合Markdown 3.0的更改。

3.4 (2018-09-09)

功能特性

  • 添加对Python 3.7的支持(#2760, #3007, #3076, #3399, #3656),由Hartmut Goebel实现。
  • 改善对基于Qt5的应用程序的支持(#3439)。通过模拟大部分Qt部署工具的行为,支持了大部分PyQt5变量。但是,不支持Anaconda的PyQt5软件包,因为其QlibraryInf实现报告错误的值。CI测试目前在PyQt5 5.11.2上运行。非常感谢Bryan A. Jones的帮助。
  • –debugnow允许更轻松地激活更多的调试。这包括引导加载程序消息、Python的“冗长导入”以及将收集的Python文件存储在输出目录中而不是冻结。请参阅seepyinstaller–help获取详情。(#3546, #3585, #3587)
  • 提示用户安装用于缺失_pyconfig.h_的开发包。(#3348)
  • 在setup.py中指定此发行版兼容的Python版本。
  • 使base_library.zip可再现:设置文件的时间戳。(#2952, #2990)
  • 新的命令行选项–bootloader-ignore-signals使启动加载程序将所有信号转发到捆绑的应用程序。 (#208, #3515)
  • (OS X)Python标准库模块plistlib现在用于生成Info.plist文件。这使得可以在info_plist中传递复杂和嵌套的数据。(#3532,#3541)

2.15. PyInstaller 147的更改日志

Bug修复

  • 将missingwarnings模块添加到base_library.zip中。(#3397, #3400)
  • 修正并简化在Windows、msys2、cygwin上搜索libpython的过程。 (#3167, #3168)
  • 修正使用加密的PYZ档案时与_pycryptodome_(_pycrypto_库的替代品)不兼容的问题。 (#3537)
  • 修正引导程序父进程在子进程完成之前终止导致的竞争条件。例如,当子进程本身与switch_root玩耍时,这可能发生。 (#2966)
  • 修正文件名包含…时的错误安全警报。 (#2641, #3491)
  • 仅在必要时更新缓存文件的资源,以保持签名有效。 (#2526)
  • (OS X)修复:即使LSUIElement=True,应用程序图标也会出现在Dock中。(#1917, #2075, #3566)
  • (Windows)修复尝试使用–resource选项将资源添加到Windows可执行文件时崩溃的问题。 (#2675, #3423)
  • (Windows)仅在必要时更新资源以保持签名有效 (#3323)
  • (Windows)在读取XML清单文件时使用UTF-8。(#3476)
  • (Windows)utils/win32:捕获无效的–icon参数并终止并显示消息。(#3126)

不兼容的更改

  • 不再支持Python 3.3 (#3288),感谢Hugo和xoviat。
  • –debugnow希望有一个(可选的)参数。因此,使用…–debug script.py将会破坏。使用…script.py --debug或…–debug=all script.py代替。并且–debug=all(如果未给出参数,则为默认值)包括noarchive,它将所有收集的Python文件存储在输出目录中而不是冻结它们。使用–debug=bootloader以获得前面的行为。(#3546, #3585, #3587)
  • (较小)更改中间构建文件和_warn_文件的命名。这仅影响依赖于这些文件名称的第三方工具(如果存在)。
  • (副标题)–add-data和–add-binary的目标路径不再为空,使用代替。 (#3066)
  • (较小)使用C扩展的标准路径,而不是点路径(仅限Python 3)。

钩子

  • 转换为钩子的可视化库:bokeh(#3607)、Champlain、Clutter(#3443)、dynaconf(#3641)、flex(#3401)、FMPy(#3589)、gi.repository.xlib(#2634, #3396)、google-cloud-translate、google-api-core(#3658)、jedi(#3535, #3612)、nltk(#3705)、pandas(#2978, #2998, #2999, #3015, #3063, #3079)、phonenumbers(#3381, #3558)、pinyin(#2822)、PySide.phonon、PySide.QtSql(#2859)、pytorch(#3657)、scipy(#2987, #3048)、uvloop(#2898)、web3、eth_account、eth_keyfile(#3365, #3373)。
  • Cryptodome 3.4.8、Django 2.1、gevent 1.3等更新的钩子。Crypto(PyCryptodome)(#3424)、Gst和GdkPixbuf(在msys2上运行,#3257, #3387)、sphinx 1.7.1、setuptools39.0等更新的钩子。
  • 用于PyQt5的更新的挂钩(#1930, #1988, #2141, #2156, #2220, #2518, #2566, #2573, #2577, #2857, #2924, #2976, #3175, #3211, #3233, #3308, #3338, #3417, #3439, #3458, #3505)等等:
    - 由QtQml.QQmlEngine加载所有QML。
    - 在确定PyQt5库位置时,改进错误报告。

第148章2的内容:

- 改进了查找qt.conf的方法。
- 包括PyQt5的OpenGL回退DLL。 (#3568)。
- 将PyQt5 DLL放在正确的位置。 (#3583)

  • 修复cryptodome (#3405)、PySide2 (样式不匹配) (#3374、#3578)的钩子。
  • 修复在PyQt5.QtNetwork中缺少SSL库的Windows问题。 (#3511,#3520)
  • 修复Windows Python 2.7中的zmq。 (#2147)
  • (GNU/Linux) 修复USB挂钩逻辑:通过usb.backend报告的库名称解析。 (#2633, #2831, #3269)
  • 清理USB挂钩逻辑。

引导加载程序

  • 如果在归档中设置了选项pyi-bootloader-ignore-signals,则将所有信号转发到子过程。(#208,#3515)
  • 使用waitpid而不是wait避免引导加载器父进程被信号。 (#2966)
  • (OS X)默认情况下不要使应用程序成为GUI应用程序即使在–windowed模式下也是如此。不在引导加载程序中强制执行此功能允许使用Info.plist选项控制行为 - 可以在PyInstaller中设置或在_.spec_文件中设置。(#1917,#2075,#3566)
  • (Windows) 显示或打印utf-8调试消息不乱码。 (#3477)
  • 当HAVE_UNSETENV未定义时修复setenv()调用。 (#3722,#3723)

模块加载程序

  • 在导入扩展模块失败的情况下改进错误消息。 (#3017)

文档

  • 修复文档中的拼写错误、小错误和格式错误。 (#3442,#3521,#3561,#3638)
  • 明确指出—windowed独立于—onedir。 (#3383)
  • 提到使用importsimp.find_module()导入的程序包不会被检测到。
  • 反映有关LD_LIBRARY_PATH的实际行为。(#3236)
  • (OS X)修改关于plistlib功能的info_plist部分并使用与实时世界使用更加对齐的示例。(#3532,#3540,#3541)
  • (开发人员)彻底改写提交和提交消息的指南。 (#3466)
  • (开发人员)重新制作开发者的快速入门指南。

2.15. PyInstaller 149的更改日志

项目和进程

  • 添加piprequirements.txt文件。
  • 让_pyup_每月更新“Test - Libraries”软件包要求。
  • 使用towncrier管理更改日志条目。 (#2756,#2837,#3698)

PyInstaller核心

  • 为挂钩添加requirements_for_package()和collect_all()帮助函数。
  • 将解释性头文件添加到warn文件中,希望减少将文件发布到问题跟踪器的人数。
  • 将模块位置添加到base_library.zip,该位置是Python 3.6中的模块强制执行所需的(而且是warnings required)。
  • 始终写入warn文件。
  • 将应用程序程序接口中添加的二进制数据应用于format_binaries_and_datas()(它将挂钩样式元组转换为TOC样式元组)。
  • 避免在get_module_file_attribute()帮助函数中打印无用的异常。
  • 不收集Python扩展名的collect_dynamic_libc()。
  • 修复多个ResourceWarnings和DeprecationWarnings (#3677)
  • 如果在format_binaries_and_datas()中未找到文件,则提示用户安装必要的开发包,例如pyconfig.h。(#1539,#3348)
  • 钩子帮助函数is_module_satisfies()返回未找到软件包的False。(#3428,#3481)
  • 按块读取缓存摘要数据。(#3281)
  • 为以libzmq.cp36-win_amd64.pyd命名的C扩展文件选择正确的文件扩展名。
  • 再次在_warn_文件中说明导入类型(条件、延迟等)。
  • (modulegraph)拆下_altgraph_库,从上游使用。(#3058)
  • (OS X)在–console模式下,在Info.plist中设置LSBackgroundOnly=True,以隐藏dock中的应用程序图标。这仍然可能被_.spec_文件中的info_plist覆盖。(#1917,#3566)
  • (OS X)使用python标准libraryplistlib生成Info.plist文件。(#3532,#3541)
  • (Windows)完全删除_pywin32_依赖项,其版本不稳定并且在pypi上的版本可能不再有未来版本。相反,需要纯Python_pywin32-ctypes_。(#3141)
  • (Windows)在更新资源之前对清单进行编码。(#3423)
  • (Windows) 使import与使用不兼容的签名进行python.net__import__的程序包兼容。(#3574)

测试套件和持续集成

  • 添加在docker中运行测试的脚本和dockerfile。 (已投稿,不再维护)(#3519)

  • 避免日志消息被写入(和捕获)两次。

  • 修复decoratorskipif_no_compiler。

  • 修复关于“W”运行时Python选项的测试,以验证模块_警告_实际上可以导入。(#3402,#3406)

  • 在不通过pytest捕获输出时修复Unicode错误。

  • 运行pyinstaller -h以验证其是否起作用。

  • test_setuptools_nspkgno longer modifies source files.

  • Appveyor:
    - 添加用于appveyor.yml的Appveyor变量文档。
    - 重大清理appveyor.yml (#3107)
    - 其他测试产生>1小时的运行时间。将每个任务分为两个任务。
    - 在2个内核上运行Appveyor测试;因此,同时运行2个作业。
    - 减少磁盘使用。
    - 将Python 2.7测试分为两个作业,以避免1小时限制。
    - 更新使用Windows Server 2016。(#3563)

  • Travis
    - 使用构建阶段。
    - 清理travis.yml (#3108)
    - 修复(OS X)上的Python安装。(#3361)
    - 仅为“Test - Libraries”阶段启动X11服务器。
    - 使用目标Python解释器编译启动加载程序以检查此Python版本的构建工具是否可以使用。

引导加载程序构建

  • 打印编译时调用的Python版本。
  • 将_waf_构建工具更新为2.0.9,并为_waf_2.0修复ourwscript。
  • (GNU/Linux)在使用–debug构建时打开FORTIFY_SOURCE,方便调试。

2.15. PyInstaller 151的更改日志

已知问题

  • Anaconda的PyQt5包不受支持,因为其QlibraryInfo实现会报告不正确的值。
  • 打包到软件包中的所有脚本以及所有运行时钩子都共享相同的全局变量。此问题自v3.2以来就存在,但最近才发现,参见#3037。这可能导致从运行时钩子泄漏全局变量到脚本,以及从一个脚本到后续脚本。但在大多数情况下影响都很小。
  • 来自wheels,未解压鸡蛋或未在egg中的数据文件不会自动包含在内。这可以通过使用钩子文件来解决,但在使用–onefile和像_python-daemon_之类的东西时可能不够用。
  • 多包(MERGE)功能(#1527)目前已破坏。
  • (OSX)对于OpenDocument事件(#1309)的支持已遭破坏。
  • (Windows)对于Python 2.7,如果用户名(更具体地说是%TEMPDIR%)包括某些Unicode字符,冻结的应用程序可能无法运行。这并不会发生在所有Unicode字符上,只发生在其中一些字符上,似乎是Windows的一个错误。请升级到Python 3以解决问题(#2754,#2767)。
  • (Windows)对于Python> = 3.5针对Windows <10,开发人员需要特别注意包含Visual C ++运行时.dll。请参阅手册中的“特定于平台的说明”一节(#1566)。

3.3.1(2017-12-13)

钩子

  • 修复hooks accessible_output和sound_lib中的导入问题(#2860)。
  • 修复3.5.4 Conda中sysconfig的ImportError(#3105,#3106)。
  • 为Windows上的conda环境修复shapely钩子(#2838)。
  • 添加unidecode的钩子。

引导程序

  • (Windows)可以再次在Windows XP上使用预构建的bootloader(以及使用MSVC自定义构建的bootloader)。将最低目标操作系统设置为XP(#2974)。

引导程序构建

  • 修复FreeBSD的构建(#2861,#2862)。

PyInstaller Core

  • 使用说明:添加关于在提供spec文件时使用选项的帮助消息(#3039)。
  • 添加打印UnicodeDecodeError中exec_command_all的信息。
  • (win32)在加载图标文件时发生错误时发出错误消息(#2039)。
  • (aarch64)使用64位ARM的正确引导程序(#2873)。
  • (OS X)修复替换运行时搜索路径关键字的问题(@ …)(#3100)。
  • Modulegraph
    • 修复由于重新导入类似SWIG的模块而导致的递归太深错误(#2911,#3040,#3061)。
    • 保留导入的标识符的顺序。

测试套件和持续集成

  • 在持续集成测试中:启用flake8-diff linting。这将拒绝不遵循PEP 8的所有更改行。
  • 在Windows上启用并行测试,
  • 更新要求。
  • 添加更多的modulegraph测试用例。
  • 为模块导入顺序添加测试用例。
  • 添加测试用例以检查脚本不共享相同的全局变量(请参见“已知问题”)。

文档

  • 添加关于在提供spec文件时处理选项的澄清(#3039)。
  • 添加使用Python优化运行PyInstaller的文档(#2905)。
  • 添加关于Cython支持限制的说明。
  • 添加如何处理未检测到的ctypes库的信息。
  • 添加关于SWIG支持的要求和限制的说明。
  • 添加一份开发指南。
  • 扩展“如何贡献”。
  • 添加“运行测试套件”。
  • 从Readme中删除徽章(#2853)。
  • 更新man-pages中过时的部分以及其他man页的增强功能。

2.15. PyInstaller 153的更改日志:

已知问题

  • 打包到软件包中的所有脚本以及所有运行时钩子都共享相同的全局变量。此问题自v3.2以来就存在,但最近才发现,参见#3037。这可能导致从运行时钩子泄漏全局变量到脚本,以及从一个脚本到后续脚本。但在大多数情况下影响都很小。
  • 更多的内容请参见3.3版的已知问题。

3.3(2017-09-21)

  • **添加对Python 3.6的支持!**非常感谢xiovat!(#2331,#2341)
  • 为添加数据文件(–datas,#1990)和二进制文件(–binaries,#703)添加了命令行选项
  • 添加了命令行选项“-运行时-tmpdir”。
  • Windows的引导程序现在使用MSVC构建,并与运行时库(CRT)静态链接。这解决了许多与python.dll所需的.dll不兼容的问题。
  • GNU / Linux的引导程序现在正式不是LSB二进制文件。这已经是自3.1以来的情况,但以另一种方式记录。此外,构建现在默认为非LSB二进制文件(#2369)。
  • 我们改进并稳定了引导程序的构建以及持续集成测试。有关详细信息,请参见下文。非常感谢所有参与此工作的人。
  • 为了简化解决错误添加不正确的包,现在始终生成带有交叉引用的HTML文件。它的视觉外观已经现代化(#2765)。

不兼容的更改

  • 不再优雅地处理已经过时数个版本的命令行选项,而是引发错误(#2413)
  • 安装:PyInstaller删除了一些第三方软件包的内部副本。现在它们从它们在PyPI的官方发布版中获取(#2589)。这导致PyInstaller不再只能从已解压的存档中使用,而是需要像任何Python软件包一样安装。这只会影响少数人,例如开发人员。
  • 遵循PEP 527,我们现在只发布一个源存档,并决定使用_.tar.gz_(#2754)。

钩子

  • 新增和更新的钩子:accessible_output2 (#2266), ADIOS (#2096), CherryPy (#2112), PySide2 (#2471,
    #2744) (#2472), Sphinx (#2612, 2708) (#2708), appdir (#2478), clr (#2048), cryptodome (#2125), cryp-
    tography (#2013), dclab (#2657), django (#2037), django migrations (#1795), django.contrib (#2336),
    google.cloud, google.cloud.storage, gstreamer (#2603), imageio (#2696), langcodes (#2682), libaudioverse
    (#2709), mpl_toolkits (#2400), numba, llvmlite (#2113), openpyxl (#2066), pylint, pymssql, pyopencl, pyproj
    (#2677), pytest (#2119), qtawesome (#2617), redmine, requests (#2334), setuptools, setuptools (#2565), shapely
    (#2569), sound_lib (#2267), sysconfig, uniseg (#2683), urllib3, wx.rc (#2295),
    - numpy: 寻找.dvlib库文件 (#2544), 支持numpy MKL构建 (#1881, #2111)
    - osgeo: 添加conda特定位置来检查辅助数据 (#2401)
    - QT 和相关
    ∗添加 PySide2 钩子。
    ∗通过将文件放置在正确的目录中,消除运行时钩子。

第154章 内容:

∗修复homebrew中查找qmake的路径 (#2354)
∗修复Qt dll位置 (#2403)
∗捆绑 PyQT 5.7 DLLs (#2152)
∗PyQt5: 返回包括子目录的qml插件路径 (#2694)
∗修复PyQt5.QtQuick的钩子 (#2743)
∗PyQt5.QtWebEngineWidgets: 包括QWebEngine所需的文件

- GKT+ 和相关的
∗修复windows上的Gir文件路径。
∗当GI的typelib存在时,修复不必要的文件搜索和生成
∗gi: 更改从虚拟环境运行时的gir搜索路径
∗gi: 在OSX代码签名不可识别的目录中打包gdk-pixbuf
∗gi: 在Linux上运行时重新编写GdkPixbuf加载器缓存
∗gi: 为GdkPixbuf支持onefile模式
∗gi: 在gdk-pixbuf-query-loaders-64存在时支持使用
∗gi:OSX仅需要GIR文件
∗gio: 也复制mime.cache
∗修复windows平台上的PyGObject的钩子 (#2306)

  • 修复钩子: botocore (#2384), clr (#1801), gstreamer (#2417), h5py (#2686), pylint, Tix数据文件 (#1660),
    usb.core (#2088), 非Windows系统上的win32com (#2479)
  • 修复在POSIX操作系统上的多进程生成模式 (#2322, #2505, #2759, #2795)。

引导程序

  • 添加_tempdir_选项以控制引导程序将提取文件的位置 (#2221)
  • (Windows)在发布到PyPI上的版本需要msvcr*.dll (#2343)
  • 修复了不安全的字符串操作,资源和内存泄漏。感谢Vito Kortbeek (#2489, #2502, #2503)
  • 删除了遗留的使用getenv()
  • 在子进程中设置适当的LISTEN_PID(由_systemd_设置) (#2345)
  • 添加PID到引导程序日志消息中 (#2466, #2480)
  • (Windows)使用_wputenv_s()代替SetEnvironmentVariableW()
  • (Windows)增强错误消息(#1431)
  • (Windows)为Python 3问题添加解决方法http://bugs.python.org/issue29778 (#2496, #2844)
  • (OS X):在–onedir模式下使用单个进程 (#2616, #2618)
  • (GNU/Linux)默认使用–no-lsb编译引导程序(#2369)
  • (GNU/Linux)修复:linux64引导程序需要glibc 2.14 (#2160)
  • (GNU/Linux)set_dynamic_library_path 更改中断插件库的使用 (#625)

2.15. PyInstaller 155变更日志

引导程序构建

引导程序的构建得到了很大的改进。在wscript中,构建不再依赖于Python解释器的位大小,而是依赖于编译器。我们拥有一台用于构建Windows引导程序和跨平台构建OS X引导程序的机器。因此,所有维护者现在都能够为所有支持的平台构建引导程序。

  • 添加"官方"的构建脚本。
  • (GNU/Linux)将–no-lsb设为默认值,添加–lsb选项。
  • 大规模修改Vagrantfile:
    - 让OS X box 构建Darwin引导程序(未使用)
    - 让Windows使用MSVC构建引导程序
    - 允许在linux64上指定交叉目标。
    - 启用OS X的交叉构建。
    - 启用Windows的交叉构建(未使用)
    - 添加为osxcross构建box。
  • 大规模修改wscript:
    - 删除选项–target-cpu。
    - 使用编译器的目标架构,而不是Python的。
    - 对脚本进行了重大改造。
    - 如果需要,则构建zlib,而不是"在Windows上"。
    - 删除过时的警告。
    - 更新Solaris,AIX和HPUX支持。
    - 为AIX平台添加 ‘strip’ 工具的标志。
    - 不要设置POSIX/SUS版本定义。
  • (GNU/Linux)对于64位arm/aarch,忽略gcc标志-m64 (#2801)。

模块加载器

  • 实现PEP-451模块规范类型的导入系统 (#2377)
  • 修复:导入时线程不安全?(#2010, #2371)

PyInstaller核心

  • 分析:检查Python版本是否需要重新构建时进行测试。

  • 分析:在模块中存在语法错误时不应终止,只需忽略它们。

  • 没有找到"数据"时提供更好的错误消息。 (#2308)

  • 构建:OSX:创建Info.plist XML时使用unicode文本。

  • 构建:如果"数据"文件名包含glob特殊字符,则不会失败。 (#2314)

  • 构建:从.spec文件中读取运行时tmpdir。

  • 构建:更新注释。

  • 如果bincache损坏,building将提醒用户。 (# 2614)

  • Cli-utils: 删除过时命令行选项的优雅处理。

  • Configure: 当移动旧cache-dir时,要创建新的parent-dir。 (# 2679)

  • Depend: 包括 Windows 上的vcruntime140.dll。 (# 2487)

  • Depend: 如果分析的脚本有语法错误,则打印错误消息。

  • Depend: 在扫描ctypes库时删除非基本名称二进制文件。

  • 增强运行时ctypes导入错误的错误消息。

  • 修复# 2585:py2非Unicode sys.path受到os.path.abspath()引诱。 (# 2585)

  • 如果扩展模块对ctypes有隐藏的导入,则修复崩溃。 (# 2492)

  • 修复过时命令行选项的处理。 (# 2411)

  • 修复Python 3.x上versioninfo.py的破坏性 (# 2623)

  • 修复:“Unicode-objects must be encoded before hashing” (# 2124)

  • 修复:UnicodeDecodeError - collect_data_files未以Unicode格式返回文件名 (# 1604)。

  • 删除过时命令行选项的优雅处理。 (# 2413)

  • 使非Windows的grab版本更有礼貌。 (# 2054)

  • 使utils/win32/versioninfo.py正确处理版本信息。

  • Makespec:修复PyCrypto的版本号处理。 (# 2476)

  • 对modulegraph进行优化和重构,并扫描ctypes依赖项。

  • 当在源代码中遇到编码错误时,pyinstaller不应崩溃。 (# 2212)

  • 拷贝COLLECT和EXE之前删除目标。 (# 2701)

  • 在添加未找到的数据文件时,要删除无信息的回溯。 (# 2346)

  • 处理导入过程中的线程问题。 (# 2010)

  • utils/hooks: 在collect_data_files中添加日志记录。

  • (win32)支持使用pypiwin32或pywin32-ctypes。 (# 2602)

  • (win32) 使用os.path.normpath确保排除系统库。

  • (win32) 在Windows MSYS2中查找libpython%.%.dll。 (# 2571)

  • (win32) 使versioninfo.py正确处理版本信息。 (# 2599)

  • (win32) 在check_requirements被调用之前不导入pywin32。

  • (win32) pyi-grab_version和-version-file不起作用? (# 1347)

  • (win32)关闭PE()对象以避免mmap内存泄漏。 (# 2026)

  • (win32) 修复:在某些情况下,Windows版本信息中的ProductVersion不显示。 (# 846)

  • (win32) 修复python2中多字节路径启动程序导入问题。 (# 2585)

  • (win32)通过_arch_命令转发DYLD_LIBRARY_PATH。 (# 2035)

  • (win32) 为Python 3.5和3.6添加vcruntime140.dll到_win_includes。 (# 2487)

  • (OS X)添加libpython%d.%dm.dylib到Darwin(is_darwin)PYDYLIB_NAMES。 (# 1971)

  • (OS X) macOSbundle Info.plist应为UTF-8。 (# 2615)

2.15 PyInstaller 157的更改日志

  • (OS X) Python 3中的multiprocessing spawn在macOS上无法工作。 (# 2322)
  • (OS X) Pyinstaller无法找到动态库的路径(@ rpath)。 (# 1514)
  • Modulegraph
    • 与上游版本0.13对齐。
    • 添加上游测试套件
    • 如果存在语法错误和Unicode错误,则发出警告。 (# 2430)
    • 实现enumerate_instructions() (# 2720)
    • 将字节码分析切换为使用_Instruction_(如dis3所做的那样)(# 2423)
    • 对于Unicode错误,记录警告,而不仅仅是调试信息。 (# 2418)
    • 使用标准日志记录消息。 (# 2433)
    • 修复了重新导入失败的SWIG C模块(1522,# 2578)。
  • 包含的第三方库
    • 删除了bundledpefileandmacholib,使用PyPI中的版本。 (# 1920,# 2689)
    • altgraph:更新为altgraph 0.13,添加上游测试套件。

实用程序

  • grab_version.py:当实用程序失败时,显示友好的错误消息(# 859,# 2792)。

测试套件和持续集成

  • 重新排列了要求文件。
  • 固定所需版本-现在使用pyup更新(# 2745)
  • 隐藏辅助函数的无用跟踪。
  • 为PyQt5.QtQuick添加一个测试。
  • 为PySide2添加功能测试
  • 为新功能添加–runtime-tmpdir的测试。
  • 修复# 2492的回归测试。
  • 单元格:为PyiModuleGraph添加测试用例。
  • unit/altgraph:向上游altgraph test-suite中添加。
  • unit/modulegraph:向modulegraph test-suite中添加。
  • 持续集成
    • 对CI测试进行了大量增强,使其更加稳定和可靠。
    • 固定所需版本-现在使用pyup更新(# 2745)
    • OS X现在与Travis CI一起测试,同时还有GNU / Linux(# 2508)
    • Travis:使用阶段(# 2753)
    • appveyor:在失败时保存缓存(# 2690)

158第2章。 内容:

- appveyor:验证构建的引导程序具有期望的arch。

文档

  • 添加有关如何捐赠的信息(# 2755,# 2772)。
  • 添加如何使用pip安装开发版本的说明。
  • 修复开发版本的安装说明。 (# 2761)
  • 更好的隐藏import的示例。
  • 阐明并修复“添加数据文件”和“添加二进制文件”。 (# 2482)
  • 记录新的命令行选项’–runtime-tmpdir’。
  • pyinstaller在powerpc linux上工作,大端领域(# 2000)
  • 在wiki页面上大部分重写“构建引导程序”一章。
  • 描述构建符合LSB的引导程序的方法(现在)是特殊情况。
  • help2rst:为选项标题添加交叉引用标签。
  • 启用sphinx.ext.intersphinx和对我们网站的链接。
  • Sphinx不应“调整”命令行文档的显示(#2217)

已知问题

  • 无法自动包含来自Wheels、未解压的eggs或不是egg的数据文件。可以使用hook文件绕过此问题,但在使用–onefile和类似 “python-daemon” 的东西时可能不够用。
  • 目前,多包(MERGE)功能(#1527)已损坏。
  • (OSX)支持OpenDocument事件(#1309)已损坏。
  • (Windows)对于Python 2.7,如果用户名(更具体地说是 %TEMPDIR%)包括一些Unicode字符,则冻结应用程序可能无法运行。这种情况并非发生在所有Unicode字符上,而仅发生在其中一些Unicode字符上,似乎是Windows的错误。作为解决方法,请升级到Python 3(#2754,#2767)。
  • (Windows)对于Python> = 3.5并针对_Windows <10_,开发人员需要特别注意包括Visual C ++运行时.dlls。请参见手册中的“平台特定说明”部分。 (#1566)
  • 对于Python 3.3,导入不是线程安全的(#2371#)。由于Python 3.3于2017-09-29到期,因此我们将不会修复此问题。

3.2.1(2017-01-15)

-新的、更新的和修复的钩子:botocore(#2094)、gi(#2347)、jira(#2222)、PyQt5.QtWebEngineWidgets
(#2269)、skimage(#2195,2225)、sphinx(#2323,)xsge_gui(#2251)。

解决以下问题:

  • 如果工作目录已存在,请勿失败(#1994)
  • 在主脚本中避免编码错误(#1976)
  • 修复哈希程序摘要字节不是str(#2229,#2230)
  • (Windows)修复msvcrt10.dll上的额外依赖项(#1974)

2.15. PyInstaller 159的更改日志

-(Windows)正确解码由pefile生成的字节对象(#1981)
-(Windows)使用pyinstaller打包pefile。这部分撤消了3.2中的某些更改,在这些更改中,打包的pefile被删除以使用pypi版本。在某些应用程序中,pypi版本的性能要慢得多,并且在PY3上仍存在一些小问题。 (#1920)
-(OS X)MacOS上的PyQt5包装问题(#1874)
-(OS X)替换运行时搜索路径关键字(#1965)
-(OS X)(重新)添加OSX的argv仿真,64位(#2219)
-(OS X)在getImports_macholib()中使用decode(“utf-8”)将字节转换为字节(#1973)
-(Bootloader)修复了段错误(#2176)
-(setup.py)仅在GNU / Linux上通过选项-no-lsb(#1975)
-文档、手册等更新和修复。 (#1986、2002、#2153、#2227、#2231)

3.2(2016-05-03)

-现在,即使是“主”脚本,也会进行字节编译(#1847,#1856)
-手册现在在readthedocs.io上(#1578)
-在安装时尝试编译引导加载程序(如果当前平台没有引导加载程序)(#1377)
-(Unix)使用objcopy创建一个有效的ELF文件(#1812,#1831)
-(Linux):用_FORTIFY_SOURCE(#1820)编译
-新的、更新的和固定的钩子:CherryPy(#1860)、Cryptography(#1425,#1861)、杳(1562),
gi.repository.GdkPixbuf(#1843)、gst(#1963)、Lib2to3(#1768)、PyQt4、PyQt5、PySide(#1783、#1897、#1887)、
SciPy(#1908、#1909)、sphinx(#1911、#1912)、SQLAlchemy(#1951)、traitlets wx.lib.pubsub(#1837、#1838),
-针对窗口模式,为我们的虚拟NullWriter添加isatty()(#1883)
-在SystemExit的情况下不要抑制“无法执行脚本”(#1869)
-不要对引导加载程序文件应用Upx压缩器(#1863)
-为由ctypes使用的lib提供绝对路径(#1934)
-(OSX)修复在NFS上的二进制缓存(#1573,#1849)
-(Windows)在grab_version中修复消息(#1923)
-(Windows)修复Windows示例中错误的图标参数(#1764)
-(Windows)修复win32 Unicode处理(#1878)
-(Windows)通过重新构建winmanifest,修复不必要的重新构建(#1933)
-(Cygwin)修复Cygwin 64位找到Python库的问题(#1307,#1810,#1811)
-(OS X)修复编译问题(#1882)
-(Windows)不再打包pefile,而是使用pypi为windows提供的包
-提供更强大的执行Python脚本的方式
-AIX修复。
-将waf更新到1.8.20版(#1868)
-修复了排除的导入,以更可预测的顺序应用钩子#1651

160章。目录:

-内部改进和代码清理(#1754、#1760、#1794、#1858、#1862、#1887、#1907、#1913)
-测试套件的清理修复和改进

已知问题

-Windows 10和Python 3.5构建的应用程序可能无法在早于10的Windows版本上运行(#1566)。
-目前,多包(MERGE)功能(#1527)已损坏。
-(OSX)支持OpenDocument事件(#1309)已损坏。

3.1.1(2016-01-31)

解决以下问题:

-修正setuptools 19.4的问题(#1772、#1773、#1790、#1791)

  • 3.1不收集某些直接导入(#1780)
    -即使在未改变的版本上,Git也报告错误的版本(#1778)
    -不要解析modulegraph.py中的symlinks(#1750、#1755)
  • win32 util未返回ShortFileName(#1799)

3.1(2016-01-09)

  • 支持可重复构建(#490,#1434,#1582,#1590)。
  • 剥离编译代码对象中的前导路径部分(#1059,#1302,#1724)。
  • 在使用–log-level=DEBUG时,在build-directory中发出依赖项图文件。
  • 允许以用户_root_身份运行pyinstaller。根据广泛的要求,例如#1564,#1459,#1081。
  • 新挂钩:botocore,boto3,distorm3,GObject,GI(G Introspection),GStreamer,GEvent,kivy,lxml.isoschematron,pubsub.core,PyQt5.QtMultimedia,scipy.linalg,shelve。
  • 修复或更新的挂钩:astroid,django,jsonschema logilab,PyQt4,PyQt5,skimage,sklearn。
  • 添加选项–hiddenimport作为–hidden-import的别名。
  • (OSX)修复了使用st_flags的问题(#1650)。
  • (OSX)去掉了关于32位兼容性的警告消息(#1586)。
  • (Linux)缓存现在存储在 X D G C A C H E H O M E / p y i n s t a l l e r 中,而不是 XDG_CACHE_HOME/pyinstaller中,而不是 XDGCACHEHOME/pyinstaller中,而不是XDG_DATA_HOME,缓存会自动移动(#1118)。
  • 文档更新,例如关于可重复构建
  • 将GPL许可证的全文放回到COPYING.txt中。
  • 修复在查找ctypes DLL时崩溃的问题(#1608,#1609,#1620)。
  • 修复:如果代码包含函数,则在字节码中的导入未找到(#1581)。
  • 修复了递归到字节代码中以扫描ctypes的问题(#1620)。
  • 修复了PyCrypto模块与crypto功能(-keyoption)一起工作的问题(#1663)。
  • 修复了一些钩子中排除导入的问题,即使在其他地方使用了命名模块,也排除了它们(#1584,#1600)。

2.15. PyInstaller 161的变更日志

  • 修复pip 7.1.2的冻结问题(#1699)。
  • 修复了FreeBSD和Solaris。
  • 首先在$PATH中搜索ldconfig(#1659)
  • 拒绝处理过时的package_xmlplus。
  • 对测试套件,测试基础设施和持续集成进行改进。
  • 对于非发布版本,不使用确切的git修订版。
  • 内部代码重构。
  • 对挂钩API进行了增强和清理-仅适用于挂钩作者。有关详细信息,请参见手册。例如:
    **-**在挂钩中删除了attr-s,因为它们已不再使用。
    **–**更改add / del_import()以接受任意数量的模块名称。
    **-**新的挂钩实用程序函数copy_metadata()。

已知问题

  • 在Windows 10和Python 3.5上构建的应用程序可能无法在早于10的Windows版本上运行(#1566)。
  • 多包(MERGE)功能(#1527)当前无法正常工作。
  • (OSX)对于OpenDocument事件的支持(#1309)已中断。

3.0(2015-10-04)

  • Python 3支持(3.3 / 3.4 / 3.5)。
  • 移除对Python 2.6及以下版本的支持。
  • 引导程序中的完整unicode支持(#824,#1224,#1323,#1340,#1396)
    -(Windows)现在可以从带有非ASCII字符的路径中运行Python 2.7应用程序
    -(Windows)可以运行Python 2.7 onefile应用程序,用于包含非ASCII字符的用户名的用户
    **-**将fix.getfilesystemencoding()修复为返回正确的值(#446,#885)。
  • (OSX)在OS X下构建的可执行文件现在可以数字签名。
  • (OSX)不再分发32位预编译引导程序,只有64位预编译引导程序。
  • (Windows)32位引导程序启用标志LARGEADDRESSAWARE,允许使用4GB的RAM。
  • 新的挂钩:amazon-product-api,appy,certifi,countrycode,cryptography,gi,httplib2,jsonschema,keyring,
    lensfunpy,mpl_toolkits.basemap,ncclient,netCDF4,OpenCV,osgeo,patsy,PsychoPy,pycountry,pycparser,
    PyExcelerate,PyGobject,pymssql,PyNaCl,PySiDe.QtCore,PySide.QtGui,rawpy,请求,scapy,scipy,six,
    SpeechRecognition,u1db,weasyprint,Xlib。
  • 钩子修复:babel,ctypes,django,IPython,pint,PyEnchant,Pygments,PyQt5,PySide,pyusb,sphinx,
    sqlalchemy,tkinter,wxPython。
  • 添加支持自动包含来自egg的数据文件的支持。
  • 添加对目录egg支持的支持。
  • 添加对所有类型的名称空间包的支持,例如zope.interface,PEP302(#502,#615,#665,#1346)。
  • 添加对pkgutil.extend_path()的支持。
  • 新选项–key用于混淆Python字节码。

162第2章的内容:

  • 新选项–exclude-module可忽略特定模块或软件包。
  • (Windows)新选项–uac-admin可在启动应用程序之前请求管理员权限。
  • (Windows)新选项–uac-uiaccess允许提升的应用程序与远程桌面一起使用。
  • (Windows)用于Side-by-side Assembly搜索的新选项:
    - --win-private-assemblies将包含在应用程序中的捆绑的共享程序集更改为专用程序集
    - - 在搜索程序集时,PyInstaller将优先考虑不遵循重定向到更新版本的策略。
  • (OSX)新选项–osx-bundle-identifier设置.app绑定标识符。
  • (Windows)删除旧的COM服务器支持。
  • 允许通过环境变量PYINSTALLER_CONFIG_DIR覆盖PyInstaller默认配置目录。
  • 添加FreeBSD支持。
  • AIX修复。
  • Solaris修复。
  • 使用库模块图形进行模块依赖分析。
  • 引导程序调试消息LOADER:…打印到stderr。
  • PyInstaller不再扩展sys.path,并且打包的第三方库不会干扰其其他版本。
  • Enhancemants toAnalysis():
    **–**新参数excluded-imports来排除导入挂钩中的Python模块。
    **–**新参数binary用于在_.spec_文件和导入挂钩中捆绑动态库。
    **–**新参数数据用于在_.spec_文件和导入挂钩中捆绑附加数据文件。
  • 大量的内部代码重构。
  • 测试套件迁移到pytest框架。
  • 改进的测试基础设施,具有持续集成(Travis - Linux,Appveyor - Windows)
  • wiki和bug跟踪器迁移到github。

已知问题

  • 在Windows 10和Python 3.5上构建的应用程序可能无法在早于10的Windows版本上运行(#1566)。
  • 多包(MERGE)功能(#1527)当前无法正常工作。
  • (OSX)对于OpenDocument事件的支持(#1309)已中断。

2.1(2013-09-27)

  • 重写手册,解释了一些基础知识。
  • 将 PyInstaller 与 setuptools 集成(在 PYPI(https://pypi.python.org/pypi)上可使用 easy_install 或 pip 进行直接安装)。安装后,可使用“pyinstaller”命令来使用 PyInstaller。
  • (Windows)调整 –version-file 资源格式,以支持 Unicode。

2.15 PyInstaller 163 重大更新

  • (Windows)修复了运行包含外语字符路径的冻结应用程序的问题。
  • (Windows)修复了在包含外语字符路径上运行 PyInstaller 的问题。
  • (OSX)为 .app 包实现了 –icon 选项。
  • (OSX)为 OpenDocument AppleEvent 添加 argv 仿真选项(请参阅手册了解详细信息)。
  • 将 –buildpath 重命名为 –workpath。
  • 新创建的应用程序被放置在 –distpath 中。
  • 所有临时工作文件现在都放在 –workpath 中。
  • 添加 –clean 选项,以删除 PyInstaller 缓存和临时文件。
  • 添加了对 Linux arm 的实验性支持。
  • 支持的最低 Python 版本为 2.4。
  • 为 docutils、jinja2、sphinx、pytz、idlelib 和 sqlite3 添加了导入钩子。
  • 为 IPython、scipy、pygst 和 Python for .NET 添加了导入钩子。
  • 为 PyQt5、Bacon 和 raven 添加了导入钩子。
  • 修复了与 Django 1.4 兼容的 django 导入钩子。
  • 为 twisted、pygst 添加了 rthook。
  • 为 pkg_resource 添加了 rthook。它可以修复以下函数(用于冻结应用程序):pkg_resources.resource_stream()、pkg_resources.resource_string()。
  • 在冻结可执行文件中更好地支持 pkg_resources(.egg 操作)。
  • 添加了 –runtime-hook 选项,允许在加载冻结应用程序中的其他 Python 之前运行来自冻结应用程序的自定义代码。这很适用于某些专业的预处理,仅用于冻结可执行文件。例如,此选项可用于为 PyQt4 设置 SIP api v2。
  • 修复运行时选项 –Wignore。
  • 将 utils 重命名为 archieve_viewer.py、bindepend.py、build.py、grab_version.py、make_comserver.py、makespec.py、set_version.py。
  • (OSX)使用 PySide 时,修复了 dist 目录中缺少 qt_menu.nib 的问题。
  • (OSX)修复与 Mac OS X 10.5 的 bootloader 兼容性问题。
  • (OSX)如果找不到 libpython,则在 DYLD_LIBRARY_PATH 中搜索 libpython。
  • (OSX)修复了虚拟环境中 Python 库的搜索问题。
  • 环境变量 PYTHONHOME 现在被取消设置,并且通过函数 Py_SetPythonHome() 在 bootloader 中设置了 Python 主目录的路径。这将覆盖冻结应用程序的 sys.prefix 和 sys.exec_prefix。
  • 将 Python 库文件名(例如 python27.dll、libpython2.7.so.1.0 等)嵌入到创建的 exe 文件中。bootloader 不再尝试使用多个文件名。
  • 冻结可执行文件现在使用 PEP-302 导入钩子来导入冻结的模块和 C 扩展。(sys.meta_path)
  • 删除 iu.py 中旧的导入机制。
  • 在冻结可执行文件中删除了从 zip 存档(.egg 文件)中导入模块的自有代码。原生 Python 实现保持不变。
  • 删除了旧的加密代码。这个功能从来没有完成过。
  • 删除 bootloader 依赖于 Python 标头进行编译的代码。

164 章节 2 内容:

  • (Windows)重新编译启动加载程序,以确保与 win2k 兼容。
  • (Windows)对主目录/临时路径使用 8.3 文件名。
  • 为 bootloader 中的调试文本添加前缀 LOADER。
  • 允许通过程序方式运行 PyInstaller。
  • 移动/重命名一些文件,代码重构。
  • 添加更多测试。
  • 在 PyInstaller 中,tilde 被识别为 $HOME 变量。

2.0(2012-08-08)

  • 支持的最低 Python 版本为 2.3。
  • (OSX)添加了对 Mac OS X 64 位的支持。
  • (OSX)添加了对 Mac OS X 10.7(Lion)和 10.8(Mountain Lion)的支持。
  • (OSX)使用 –windowed 参数时,PyInstaller 会自动创建应用程序包(.app)。
  • 添加了对 AIX 的实验性支持(感谢 Martin Gamwell Dawids)。
  • 添加了对 Solaris 的实验性支持(感谢 Hywel Richards)。
  • 添加了多包函数,以创建一个包集合,以避免库重复。有关详细信息,请参阅文档。
  • 新的简化命令行界面。Configure.py/Makespec.py/Build.py 被 pyinstaller.py 替换。有关更多详细信息,请参阅文档。
  • 删除了从未真正完成的交叉构建/打包功能。
  • 向所有脚本添加了 –log-level 选项,以调整输出级别(感谢 Hartmut Goebel)。
  • 将 rthooks.dat 移动到 support/rthooks.dat
  • 打包的可执行文件现在返回与未打包的脚本相同的返回代码(感谢 Brandyn White)。
  • 为 PyUSB 添加了导入钩子(感谢 Chien-An “Zero” Cho)。
  • 为 wx.lib.pubsub 添加了导入钩子(感谢 Daniel Hyams)。
  • 为 pyttsx 添加了导入钩子。
  • 改进了 Tkinter 的导入钩子。
  • 改进了 PyQt4 的导入钩子。
  • 改进了 win32com 的导入钩子。
  • 改善了在虚拟环境中运行 PyInstaller 的支持。
  • 添加了 cli 选项 –additional-hooks-dir 和 –hidden-import。
  • 删除了 cli 选项 -X、-K、-C、–upx、–tk、–configfile、–skip-configure。
  • 如有 PATH 变量中可用,则默认情况下使用 UPX。
  • 移除了旧平台(dos、os2、MacOS 9)的兼容性代码。

2.15 PyInstaller 165 重大更新

  • 使用 Python 日志系统进行消息输出(感谢 Hartmut Goebel)。
  • 环境变量 MEIPASS2 可以作为 sys._MEIPASS 访问。
  • bootloader 现在覆盖 PYTHONHOME 和 PYTHONPATH。PYTHONHOME 和 PYTHONPATH 被设置为 MEIPASS2 变量的值。
  • bootloader 使用绝对路径。
  • (OSX)在 Mac OS X 上,不再使用 Xcode 的 otool 依赖项。
  • (OSX)使用 PyQt4 时,修复了 dist 目录中缺少 qt_menu.nib 的问题。
  • (OSX)bootloader 在 Mac OS X 上不再使用 DYLD_LIBRARY_PATH。改为使用 @loader_path。
  • (OSX)添加对包含 @executable_path、@loader_path 和 @rpath 的 Mac OS X 中的 .dylib 依赖项的支持。
  • (OSX)改用 macholib 检测对动态库的依赖关系。
  • 改进了测试套件。
  • 改进了源代码结构。
  • 用 suprocess 模块替换了 os.system() 调用。
  • 在冻结的应用程序中捆绑虚假的“site”模块,以防止从主机 OS 中加载任何用户的 Python 模块。
  • 在代码分析中包括运行时钩子(rthooks)。
  • 将源代码托管到 Github 上:https://github.com/pyinstaller/pyinstaller
  • 运行每日测试的托管:https://jenkins.shiningpanda-ci.com/pyinstaller/

1.5.1 (2011-08-01)

  • 增加 Windows 平台生成可执行文件的默认 PyInstaller 图标。
  • 增加支持在 Mac OSX 上使用 –enable-shared 参数编译的 Python。
  • 在文档中添加了 requirements 部分。
  • 文档现在使用 rst2html 和 rst2pdf 生成。
  • 修复 Windows 平台 bootloader-file 错误的路径分隔符。
  • 在某些 Python Windows 安装中,解决 platform.system() 函数返回 “Microsoft” 而非 “Windows” 的问题。
  • 修复了 Mac OSX 上 –windowed 选项的问题,即即使使用这个选项,每次都会创建控制台可执行文件。
  • 在文档中说明了依赖于 otool、ldd 和 objdump。
  • 修复了防止检测由 ctypes 模块加载的 DLL 库的拼写错误。

166 第二章 内容:

1.5 (2011-05-05)

  • 完整支持 Python 2.7。
  • 在 Windows 上完整支持 Python 2.6。无需手动重新分发 DLL、CRT、清单等:PyInstaller 能够捆绑所有所需的依赖项(感谢 Florian Hoech)。
  • 增加了对 Windows 64 位的支持(感谢 Martin Zibricky)。
  • 为 Linux(32 位和 64 位,使用 LSB)和 Darwin(32 位)添加了二进制 bootloader。这意味着在这个平台上的 PyInstaller 用户不再需要自己编译 bootloader(感谢 Martin Zibricky 和 Lorenzo Mancini)。
  • 重写 bootloader 的构建系统,使用 waf(感谢 Martin Zibricky)
  • 正确检测 Mac OSX 下的 Python 统一二进制文件,并在使用不支持的 64 位版本时停止(感谢 Nathan Weston)。
  • 修复 Mac OSX 下的 TkInter 支持(感谢 Lorenzo Mancini)。
  • 改善了包的创建,在 Mac OSX 下支持了单目录构建(感谢 Lorenzo Mancini)。
  • 修复了在使用 dbhash 时出现的假 KeyError。
  • 修复了从 Pyrex 生成的文件中导入嵌套包的问题。
  • PyInstaller 现在可以跟随二进制扩展 (.pyd/.so) 的依赖关系,这些扩展是压缩在 .egg 文件中的。
  • 为 PyTables 添加导入钩子。
  • 为 QtWebKit 添加缺少的导入钩子。
  • 为 pywinauto 添加导入钩子。
  • 为 reportlab 添加导入钩子(感谢 Nevar)。
  • 改善了 matplotlib 导入钩子(适用于 Mac OSX)。
  • 改善了 Django 导入钩子。
  • 通过更加小心地在程序包中包含/排除库来提高在多个 Linux 发行版间的兼容性。
  • 通过支持更老的 Python 版本(Python 2.2+),提高与老版 Python 的兼容性。
  • 在 Mac OSX 上修复了双重弹跳图标 bug。现在窗口应用程序正确地启动,并显示单个弹跳图标。
  • 在 Mac OSX 下修复了奇怪的“丢失符号”的错误(感谢 Isaac Wagner)。

1.4 (2010-03-22)

  • 在 Linux/Mac 上完整支持 Python 2.6 并在 Windows 上完整支持 Python 2.5。
  • 初步支持 Mac OSX:支持一个文件和一个目录;对于非控制台应用程序,可以创建一个 bundle(感谢数月来一起工作的许多人,包括 Daniele Zannotti、Matteo Bertini、Lorenzo Mancini)。
  • 改进了 Linux 支持:生成的可执行文件更加庞大,但现在应该可以在许多不同的 Linux 发行版上运行(感谢 David Mugnai)。
  • 增加了在导入钩子中指定数据文件的支持。PyInstaller 现在可以自动捆绑所有数据文件或插件,以满足某些第三方包的要求。

2.15. PyInstaller 167 的更改日志

  • 智能支持 ctypes:PyInstaller 现在能够跟踪程序源代码中使用 ctypes 的所有地方,并自动捆绑通过 ctypes 访问的动态库(感谢 Lorenzo Mancini 提交)。这在使用支持自定义动态库时非常有用。

  • 在 Windows 下使用PyInstaller 构建的可执行程序现在可以进行数字签名。

  • 在 Python 2.5+ 中增加对绝对导入的支持(感谢 Arve Knudsen)。

  • 在 Python 2.5+ 中增加对相对导入的支持。

  • 增加交叉编译支持:PyInstaller 现在能够在 Linux 下运行时构建 Windows 可执行文件。有关更多详细信息,请参见文档。

  • 增加对 .egg 文件的支持:PyInstaller 现在能够在 .egg 文件中寻找依赖项,打包它们并在运行时提供所有标准功能(入口点等)。

  • 部分支持 .egg 目录:PyInstaller 将其视为普通软件包,因此不会捆绑元数据。

  • 在 Linux/Mac 上,即使系统包没有 .pyc 或 .pyo 文件可用,也可以构建可执行文件,并且系统目录只能由 root 写入。实际上,PyInstaller 将在构建临时目录中动态生成所需的 .pyc/.pyo 文件。

  • 自动为许多第三方包添加导入钩子,包括:
    - PyQt4(感谢 Pascal Veret),支持完整的插件。
    - pyodbc(感谢 Don Dwiggins)
    - cElementTree(本机版本和 Python 2.5 版本)
    - lxml
    - SQLAlchemy(感谢 Greg Copeland)
    - Python 2.5 中的邮件(虽然它不支持 Python 2.4 的旧式语法)
    - gadfly
    - PyQWt5
    - mako
    - 改进的 PyGTK(感谢 Marco Bonifazi 和 foxx)。
    - paste(感谢 Jamie Kirkpatrick)
    - matplotlib

  • 解决了非常讨厌的“未能提取 MSVCRT71”错误,这是由于 DLL 被两次打包造成的(感谢 Idris Aykun)。

  • 从 bootloader 中删除了 C++ 风格的注释,以与 AIX 编译器兼容。

  • 修复了 Linux 下以 DOS 行结尾的 .py 文件的支持(修复了 PyOpenGL)。

  • 在不使用顶层软件包(“import Image”)导入 PIL 时进行修复。

  • 在 NT 下修复了 PyXML 导入钩子(感谢 Lorenzo Mancini)

  • 修复 PyInstaller 拾取错误 optparse 的问题。

  • 提高了 UPX’d/strip’d 文件的二进制缓存的正确性。这解决了在多个相同的第三方库版本之间切换时出现问题(例如,wxPython 允许这样做)。

  • 修复了在 Linux 下导入 optparse 模块的错误(感谢 Louai Al-Khanji)。

  • 在 Python 2.4+ 中,如果在包内导入模块时引发异常,则该模块现在将从父命名空间中移除(以匹配 Python 本身的行为)。

  • 修复了一次性文件包启动时的随机竞争条件,导致生成此异常:“PYZ条目 ‘encodings’(0j)不是有效的代码对象”。

  • 修复了在路径元素中包含unicode字符串时出现的问题。

  • 修复了在非控制台模式下使用“打印”时出现的随机异常(实际上是在 Python 3.0 中修复的pythonw“漏洞”)。

  • 当在 Linux 上运行时,有时临时目录在程序退出时没有被删除。

  • 在64位平台(如x86-64)上启动时修复了随机段错误。

1.3(2006-12-20)

  • 修复了用户提供的图标在使用UPX压缩后从构建的可执行文件中消失的错误。
  • 修复了使用PIL的应用程序打包存在的问题(这是由于Python的导入机制中的一个错误而导致的,出现在最新的Python版本中)。还包括了一个解决方法,即除非导入ImageTk,否则将Tcl/Tk与PIL一起使用。
  • (Windows)在Windows XP下使用时,已打包的程序现在具有正确的外观和感觉,并遵循用户的主题(由于附带了清单文件在生成的可执行文件中)。这对于使用wxPython的应用程序尤其有用。
  • 当从深度目录(路径名中超过70-80个字符)中运行构建的可执行文件时,引导程序现在在缓冲区溢出的情况下进行了修复(这可能会导致崩溃)。
  • 引导程序现在已经压缩到可执行文件中(因此它们在使用十六进制编辑器查看时不会以纯文本形式可见)。
  • 修复了1.1中引入的回归性问题:在Linux下,引导程序不再依赖于libpythonX.X.so。

1.2(2006-06-29)

  • 在使用某些构建调用UPX时修复了崩溃问题。
  • 通过在引导程序可执行文件中添加资源节,修复了对图标的支持。

1.1(2006-02-13)

  • (Windows)让单个文件包不再依赖于MSVCRT71.DLL,即使在Python 2.4下也是如此。即使使用最新的Python版本,您也可以将程序实际上作为单个文件可执行文件进行发布!
  • 修复了有关不正确的python路径检测的问题。现在使用distutils的帮助器。
  • 解决了在较新的Python版本中引入的罕见编码问题:现在自动找到并包含所有编码,因此这个问题应该永远不存在了。
  • 修复了构建COM服务器的问题(在1.0中由于新的构建系统而中断)。
  • 模拟了Python 2.4中断导入的行为:sys.modules在之后进行了清理。这允许在Windows下使用Python 2.4及以上版本打包SQLObject应用程序。
  • 为以下软件包添加了导入钩子:
    • GTK

2.15. PyInstaller 169的更改日志

- PyOpenGL(测试2.0.1.09)
- dsnpython(测试1.3.4)
- KInterasDB(由Eugene Prigorodov提供)

  • 修复了在Python 2.3+下使用“time.strptime”代码的打包问题。
  • (Linux)在计算依赖关系时忽略linux-gate.so(由Vikram Aggarwal提供的修复方法)。
  • (Windows)使用Python 2.4时,设置UPX以便能够压缩使用Visual Studio .NET 2003生成的二进制文件(如大多数扩展)。UPX 1.92+是必需的。

1.0(2005-09-19),有关McMillan Python Installer 5b5的支持

  • 添加了对Python 2.3的支持(修复编解码器打包的问题)。
  • 添加了对Python 2.4的支持(在Windows下,需要使用不同的编译器版本重新编译引导程序)。
  • 修复了对Python 1.5.2的支持,现在应该完全正常了(必须为引导程序重新编写字符串模块的某些部分)。
  • 修复了提取DLL依赖项(PE头解析器中的错误)的罕见错误。
  • 修复了打包PyQt程序的错误(需要隐藏的导入的一个导入钩子)。
  • 修复使用“from init import”语法的模块的导入计算。
  • 修复了在模块通过二进制依赖和直接导入方式都被导入时的打包错误。
  • 重新排版了文档(现在使用docutils和reStructuredText)。
  • 自动编译所有所需版本的引导程序的新Windows构建系统(使用Scons)

2.16 致谢

感谢所有友好的PyInstaller贡献者,他们提供了新代码、错误报告、修复、评论和想法。下面是一个简短的列表,请告诉我们如果您的姓名被意外地省略了:

2.16.1 对PyInstaller 5.11.0的贡献

  • Rok Mandeljc
  • cat(也称为_0xb8_)
  • eduardomotta-emottasistemas

170 第2章 内容:

2.16.2 对PyInstaller 5.10.1贡献

  • Rok Mandeljc
  • Christian Clauss

2.16.3 对PyInstaller 5.10.0的贡献

  • Rok Mandeljc
  • Michael Shigorin
  • V.Armando Solé

2.16.4 对PyInstaller 5.9.0的贡献

  • Brénainn Woodsend
  • Hugo van Kemenade
  • Rok Mandeljc
  • Ievgen Popovych

2.16.5 对PyInstaller 5.8.0的贡献

  • Rok Mandeljc
  • Brénainn Woodsend
  • Arjan Molenaar
  • Breeze
  • Ievgen Popovych
  • João Vitor
  • bersbersbers

2.16.6 对PyInstaller 5.7.0的贡献

  • Rok Mandeljc
  • Brénainn Woodsend
  • Dan Yeaw
  • Rumbelows
  • Shoshana Berleant

2.16. 致谢 171

** 2.16.7 对PyInstaller 5.6.2的贡献**

  • Rok Mandeljc
  • bersbersbers

2.16.8 对PyInstaller 5.6.1的贡献

  • Timmy Welch
  • Rok Mandeljc
  • Brénainn Woodsend

2.16.9 对PyInstaller 5.6的贡献

  • Rok Mandeljc
  • Brénainn Woodsend
  • Padsala Tushal

2.16.10 对PyInstaller 5.5的贡献

  • Rok Mandeljc
  • Jasper Harrison
  • Alex
  • Andreas Schwab
  • jsagarribay

2.16.11 对PyInstaller 5.4.1的贡献

  • Rok Mandeljc - 核心开发人员

  • Brénainn Woodsend - 核心开发人员

  • Jasper Harrison (Legorooj) - 核心开发人员、维护者、发布管理员

  • Hartmut Goebel - 核心开发人员、维护者

  • xoviat

  • Dan Yeaw、Bruno Oliveira、Maxim Kalinchenko、Max Mäusezahl、 Olivier FAURAX、richardsheridan、memo-off

  • Hartmut Goebel - 核心开发人员,维护者和发布经理。

  • Bryan A. Jones - 核心开发人员和 PyQt5 管理员。

  • David Vierra - 核心开发人员和编码专家。

  • xoviat - 勇敢的贡献者

  • Hugo vk - 勇敢的贡献者

  • Mickaël Schoentgen, Charles Nicholson, Jonathan Springer, Benoît Vinot, Brett Higgins, Dustin Spicuzza,
    Marco Nenciarini, Aaron Hampton, Cody Scot, Dave Cortesi, Helder Eijs, Innokenty Lebedev, Joshua Klein,
    Matthew Clapp, Misha Turnbull, ethframe, Amir Ramezani, Arthur Silva, Blue, Craig MacEachern, Cédric RI-
    CARD, Fredrik Ahlberg, Glenn Ramsey, Jack Mordaunt, Johann Bauer, Joseph Heck, Kyle Stewart, Lev Maxi-
    mov, Luo Shawn, Marco Nenciarini, Mario Costa, Matt Reynolds, Matthieu Gautier, Michael Herrmann, Moritz
    Kassner, Natanael Arndt, Nejc Habjan, Paweł Kowalik, Pedro de Medeiros, Peter Conerly, Peter Würtz, Rémy
    Roy, Saurabh Yadav, Siva Prasad, Steve Peak, Steven M. Vascellaro, Steven M. Vascellaro, Suzumizaki-Kimitaka,
    ThomasV, Timothée Lecomte, Torsten Sommer, Weliton Freitas, Zhen Zhang, dimitriepirghie, lneuhaus, s3goat,
    satarsa,

2.16.28 对 PyInstaller 4.1 的贡献

  • Hartmut Goebel - 核心开发人员,维护者和发布经理。
  • Legorooj - 核心开发人员。
  • Bryan A. Jones - 核心开发人员和 PyQt5 管理员。
  • Rok Mandeljc
  • Mickaël Schoentgen
  • Brénainn Woodsend

2.16.29 对 PyInstaller 4.0 的贡献

  • Hartmut Goebel - 核心开发人员,维护者和发布经理。
  • Legorooj - 核心开发人员。
  • Bryan A. Jones - 核心开发人员和 PyQt5 管理员。
  • M Felt aka aixtools, jonnyhsu, Corey Dexter, Rok Mandeljc, Dan Yeaw, Florian Baumann, Ievgen Popovych, Ram
    Rachum, coreydexter, AndCycle, Dan Cutright, David Kiliani, David Maiden Mueller, FeralRobot, Frederico,
    Ilya Orson, ItsCinnabar, Juan Sotomayor, Matt M, Matteo Bertini, Michael Felt, Mohamed Feddad, Nehal J
    Wani, Or Groman, Sebastian Hohmann, Vaclav Dvorak, Ville Ilvonen, bwoodsend, eldadr, jeremyd2019, kraptor,
    seedgou.

2.16.30 对 PyInstaller 3.6 的贡献

  • Hartmut Goebel - 核心开发人员,维护者和发布经理。
  • Bryan A. Jones - 核心开发人员和 PyQt5 管理员。
  • Dan Yeaw, Amir Rossert, Hugo Martins, Felix Schwarz, Giuseppe Corbelli, HoLuLuLu, Jonathan Springer,
    Matt Khan, Min’an, Oracizan, Victor Stinner, Andres, Andrew Chow, Bernát Gábor, Charles Duffy, Chris,
    Chrisg2000, FranzPio, Lee Jeonghun, Lukasz Stolcman, Lyux, László Kiss Kollár, Mathias Lohne, Michael
    Felt, Noodle-Head, Ogi Moore, Patryk, RedFantom, Rémy Roy, Sean McGuire, Thomas Robitaille, Tim, Toby,
    Tuomo, V.Shkaberda, Vojtěch Drábek, Wilmar den Ouden, david, ethframe, lnv42, ripdog, satvidh, thisisivan-
    fong

2.16.31 对 PyInstaller 3.5 的贡献

  • Hartmut Goebel - 核心开发人员,维护者和发布经理。
  • Bryan A. Jones - 核心开发人员和 PyQt5 管理员。
  • Dave Cortesi, Kuisong Tong, melvyn2, Giuseppe Corbelli, Florian Bruhin, Amir Ramezani, Cesar Vandevelde,
    Paul Müller, Thomas Robitaille, zachbateman, Addison Elliott, Amir Rossert, AndCycle, Atomfighter10101,
    Chris Berthiaume, Craig Younkins (bot), Don Krueger, Edward Chen, Exane Server Team, Hannes, Iwan,
    Jakob Schnitzer, Janzert, Jendrik Seipp, Jonathan Springer, Kirill German, Laszlo Kiss-Kollar, Loran425, Lori
    J, MCO, Nikita Melentev, Peter Bittner, RedFantom, Roman, Roman Yurchak, Ruslan Kuprieiev, Spencer
    Brown, Suzumizaki, Tobias Gruetzmacher, Tobias V. Langhoff, TobiasRzepka, Tom Hacohen, Yuval Shkolar,
    cclauss, charlesoblack, djl197, matias morant, satejkhedekar, zhu

2.16.32 对 PyInstaller 3.4 的贡献

  • Hartmut Goebel - 核心开发人员,维护者和发布经理。
  • Bryan A. Jones - 核心开发人员和 PyQt5 管理员。
  • David Vierra - 核心开发人员和编码专家。
  • xoviat - 勇敢的贡献者
  • Hugo vk - 勇敢的贡献者
  • Mickaël Schoentgen, Charles Nicholson, Jonathan Springer, Benoît Vinot, Brett Higgins, Dustin Spicuzza,
    Marco Nenciarini, Aaron Hampton, Cody Scot, Dave Cortesi, Helder Eijs, Innokenty Lebedev, Joshua Klein,
    Matthew Clapp, Misha Turnbull, ethframe, Amir Ramezani, Arthur Silva, Blue, Craig MacEachern, Cédric RI-
    CARD, Fredrik Ahlberg, Glenn Ramsey, Jack Mordaunt, Johann Bauer, Joseph Heck, Kyle Stewart, Lev Maxi-
    mov, Luo Shawn, Marco Nenciarini, Mario Costa, Matt Reynolds, Matthieu Gautier, Michael Herrmann, Moritz
    Kassner, Natanael Arndt, Nejc Habjan, Paweł Kowalik, Pedro de Medeiros, Peter Conerly, Peter Würtz, Rémy
    Roy, Saurabh Yadav, Siva Prasad, Steve Peak, Steven M. Vascellaro, Steven M. Vascellaro, Suzumizaki-Kimitaka,
    ThomasV, Timothée Lecomte, Torsten Sommer, Weliton Freitas, Zhen Zhang, dimitriepirghie, lneuhaus, s3goat,
    satarsa,

2.16.33 对 PyInstaller 3.3.1 的贡献

  • Hartmut Goebel - 核心开发人员和发布负责人。
  • Bryan A. Jones - 核心开发人员。
  • David Vierra - 核心开发人员和编码专家。
  • xoviat - 勇敢贡献者。
  • Dave Cortesi、David Hoese、John Daytona、Nejc Habjan、Addison Elliott、Bharath Upadhya、Bill Dengler、Chris Norman、Miles Erickson、Nick Dimou、Thomas Waldmann、David Weil、Placinta

2.16.34 PyInstaller 3.3的贡献

特别感谢xiovat实现了Python3.6的支持,以及Jonathan Springer和xoviat稳定了持续集成测试。

  • Hartmut Goebel - 核心开发人员和发布负责人。
  • Bryan A. Jones - 核心开发人员。
  • David Vierra - 核心开发人员和编码专家。
  • xoviat - 勇敢的程序员。
  • Jonathan Springer
  • Vito Kortbeek
  • Dustin Spicuzza
  • Ben Hagen
  • Paavo
  • Brian Teague
  • Chris Norman
  • Jonathan Stewmon

第178章2. 内容:

  • Guillaume Thiolliere

  • Justin Harris

  • Kenneth Zhao

  • Paul Müller

  • giumas

  • y2kbugger

  • Adam Clark、AndCycle、Andreas Schiefer、Arthur Silva、Aswa Paul、Bharath Upadhya、Brian Teague、Charles Duffy、Chris Coutinho、Cody Scott、Czarek Tomczak、Dang Mai、Daniel Hyams、David Hoese、Eelco van Vliet、Eric Drechsel、Erik Bjäreholt、Hatem AlSum、Henry Senyondo、Jan Čapek、Jeremy T. Hetzel、Jonathan Dan、Julie Marchant、Luke Lee、Marc Abramowitz、Matt Wilkie、Matthew Einhorn、Michael Herrmann、Niklas Rosenstein、Philippe Ombredanne、Piotr Radkowski、Ronald Oussoren、Ruslan Kuprieiev、Segev Finer、Shengjing Zhu、Steve、Steven Noonan、Tibor Csonka、Till Bey、Tobias Gruetzmacher、(float)

2.16.35 PyInstaller 3.2.1的贡献

特别感谢Thomas Waldmann和David Vierra在新构建系统方面的支持。

  • Hartmut Goebel - 核心开发人员和发布负责人。
  • Martin Zibricky - 核心开发人员。
  • David Cortesi - 核心开发人员和文档管理员。
  • Bryan A. Jones - 核心开发人员。
  • David Vierra - 核心开发人员和编码专家。
  • Cecil Curry - 勇敢的错误修复和代码重构者。
  • Amane Suzuki
  • Andy Cycle
  • Axel Huebl
  • Bruno Oliveira
  • Dan Auerbach
  • Daniel Hyams
  • Denis Akhiyarov
  • Dror Asaf
  • Dustin Spicuzza
  • Emanuele Bertoldi
  • Glenn Ramsey
  • Hugh Dowling
  • Jesse Suen
  • Jonathan Dan
  • Jonathan Springer
  • Jonathan Stewmon

2.16.积分 179

  • Julie Marchant
  • Kenneth Zhao
  • Linus Groh
  • Mansour Moufid
  • Martin Zibricky
  • Matteo Bertini
  • Nicolas Dickreuter
  • Peter Würtz
  • Ronald Oussoren
  • Santiago Reig
  • Sean Fisk
  • Sergei Litvinchuk
  • Stephen Rauch
  • Thomas Waldmann
  • Till Bald
  • xoviat

2.16.36 PyInstaller 3.2的贡献

  • Hartmut Goebel - 核心开发人员和发布负责人。
  • Martin Zibricky - 核心开发人员。
  • David Cortesi - 核心开发人员和文档管理员。
  • Bryan A. Jones - 核心开发人员。
  • David Vierra - 核心开发人员和编码专家。
  • Cecil Curry - 勇敢的错误修复和代码重构者。
  • And Cycle - Unicode修复。
  • Chris Hager - QtQuick hook。
  • David Schoorisse - Windows示例中的错误图标参数。
  • Florian Bruhin - 打字错误狩猎。
  • Garth Bushell - objcopy的支持。
  • Insoleet - lib2to3 hook
  • Jonathan Springer - hook修复,勇敢的PyQt工作。
  • Matteo Bertini - 代码重构。
  • Jonathan Stewmon - botocore、boto、boto3和gevent.monkey的hook。
  • Kenneth Zhao - Solaris修复。
  • Leonid Rozenberg - 打字错误狩猎。
  • Merlijn Wajer - Bug修复。

第180章2. 内容:

  • Nicholas Chammas - 清理工作。
  • nih - hook修复。
  • Olli-Pekka Heinisuo - CherryPy hook。
  • Rui Carmo - cygwin修复。
  • Stephen Rauch - hooks和修复不必要的重建。
  • Tim Stumbaugh - Bug修复。

2.16.37 PyInstaller 3.1.1的贡献

  • Hartmut Goebel - 核心开发人员和发布负责人。
  • David Vierra - 核心开发人员和编码专家。
  • Torsten Landschoff - 修复setuptools的问题
  • Peter Inglesby - 在modulegraph.py中解决符号链接问题
  • syradium - Bug修复
  • dessant - Bug修复
  • Joker Qyou - Bug修复

2.16.38 PyInstaller 3.1的贡献

  • Hartmut Goebel - 核心开发人员和发布负责人。
  • Martin Zibricky - 核心开发人员。
  • David Cortesi - 核心开发人员和文档管理员。
  • Bryan A. Jones - 核心开发人员。
  • David Vierra - 核心开发人员和编码专家。
  • Andrei Kopats - Windows修复。
  • Andrey Malkov - Django运行时hook。
  • Ben Hagen - kivy hook,GStreamer实时hook。
  • Cecil Curry - 模块版本比较和hook重构。
  • Dustin Spicuzza - GLib、GIntrospection、Gstreamer等的hook。
  • giumas - lxml.isoschematron hook。
  • Jonathan Stewmon - botocore、boto、boto3和gevent.monkey的hook。
  • Kenneth Zhao - Solaris修复。
  • Matthew Einhorn - kivy hook。
  • mementum - pubsub.core hook。
  • Nicholas Chammas - 文档更新。
  • Nico Galoppo - skimage和sklearn的hook。
  • Panagiotis H.M. Issaris - weasyprint hook。
  • Penaz - shelve hook。

2.16.积分 181

  • Roman Yurchak - scipy.linalg 链接钩子。
  • Starwarsfan2099 - Distorm3 链接钩子。
  • Thomas Waldmann - 引导程序和FreeBSD修复。
  • Tim Stumbaugh - bug修复。
  • zpin - bug修复。

2.16.39 PyInstaller 3.0 贡献

  • Martin Zibricky - 核心开发者和版本管理人员。
  • Hartmut Goebel - 核心开发者。
  • David Cortesi - Python 3支持的初始工作、Python 3修复、文档更新、各种钩子修复。
  • Cecil Curry - 针对Python 3的’six’钩子、各种 modulegraph 改进、wxPython钩子修复,
  • David Vierra - 引导程序中的 Unicode 支持、Windows SxS组件清单修复以及许多其他 Windows的改进。
  • Michael Mulley - keyring、PyNaCl 导入钩子。
  • Rainer Dreyer - OS X 修复、钩子修复。
  • Bryan A. Jones - 测试套件修复、各种钩子修复。
  • Philippe Pepiot - Linux 修复。
  • Emanuele Bertoldi - pycountry 导入钩子、Django 导入钩子修复。
  • Glenn Ramsey - PyQt5 导入钩子 - 在 OSX 上支持 QtWebEngine、各种钩子修复、Windows 修复。
  • Karol Woźniak - 导入钩子修复。
  • Jonathan Springer - PyGObject 钩子。ctypes、PyEnchant 钩子修复、OS X 修复。
  • Giuseppe Masetti - osgeo、mpl_toolkits.basemap 和 netCDF4 导入钩子。
  • Yuu Yamashita - OS X 修复。
  • Thomas Waldmann - FreeBSD 修复。
  • Boris Savelev - FreeBSD 和 Solaris 修复。
  • Guillermo Gutiérrez - Python 3 修复。
  • Jasper Geurtz - gui 修复、钩子修复。
  • Holger Pandel - Windows 修复。
  • Anthony Zhang - SpeechRecognition 导入钩子。
  • Andrei Fokau - Python 3.5 修复。
  • Kenneth Zhao - AIX 修复。
  • Maik Riechert - lensfunpy、rawpy 导入钩子。
  • Tim Stumbaugh -钩子修复。
  • Andrew Leech - Windows 修复。
  • Patrick Robertson - tkinter 导入钩子修复。
  • Yaron de Leeuw - 导入钩子修复。

182 第二章 内容:

  • Bryan Cort - PsychoPy 导入钩子。
  • Phoebus Veiz - 引导程序修复。
  • Sean Johnston - 版本修复。
  • Kevin Zhang - PyExcelerate 导入钩子。
  • Paulo Matias - Unicode 修复。
  • Lorenzo Villani - 加密功能,各种修复。
  • Janusz Skonieczny - 钩子修复。
  • Martin Gamwell Dawids - Solaris 修复。
  • Volodymyr Vitvitskyi - typo 修复。
  • Thomas Kho - django 导入钩子修复。
  • Konstantinos Koukopoulos - FreeBSD 支持。
  • Jonathan Beezley - PyQt5 导入钩子修复。
  • Andraz Vrhovec - 各种修复。
  • Noah Treuhaft - OpenCV 导入钩子。
  • Michael Hipp - reportlab 导入钩子。
  • Michael Sverdlik - certifi、httplib2、requests、jsonschema 导入钩子。
  • Santiago Reig - 应用导入钩子。

2.16.40 PyInstaller 2.1 和旧版本的贡献

  • Glenn Ramsey - PyQt5 导入钩子。
  • David Cortesi - PyInstaller 手册重写。
  • Vaclav Smilauer - IPython 导入钩子。
  • Shane Hansen - Linux arm 支持。
  • Bryan A. Jones - docutils、jinja2、sphinx、pytz、idlelib 导入钩子。
  • Patrick Stewart - scipy 导入钩子。
  • Georg Schoelly - storm ORM 导入钩子。
  • Vinay Sajip - zmq 导入钩子。
  • Martin Gamwell Dawids - AIX 支持。
  • Hywel Richards - Solaris 支持。
  • Brandyn White - 打包可执行文件返回码修复。
  • Chien-An “Zero” Cho - PyUSB 导入钩子。
  • Daniel Hyams - h2py、wx.lib.pubsub 导入钩子。
  • Hartmut Goebel - Python 日志系统消息输出。选项 –log-level。
  • Florian Hoech - 在 Windows 上完全支持 Python 2.6,包括 DLL、CRT、清单等的自动处理。从/到 Win32 PE 文件读取和写入资源。
  • Martin Zibricky - 使用 waf 重写引导程序构建系统。Linux LSB 兼容的预编译引导程序,Windows 64 位支持。

2.16. Credits 183

  • Peter Burgers - matplotlib 导入钩子。
  • Nathan Weston - 在 OS X 上检测 Python 架构。
  • Isaac Wagner - 各种 OS X 修复。
  • Matteo Bertini - OS X 支持。
  • Daniele Zannotti - OS X 支持。
  • David Mugnai - Linux 支持改进。
  • Arve Knudsen - Python 2.5+ 中的绝对导入
  • Pascal Veret - 带有 Qt4 插件的 PyQt4 导入钩子。
  • Don Dwiggins - pyodbc 导入钩子。
  • Allan Green - 重构和改善过程中的 COM 服务器。
  • Daniele Varrazzo - 各种引导程序和 OS X 修复。
  • Greg Copeland - sqlalchemy 导入钩子。
  • Seth Remington - PyGTK 钩子改进。
  • Marco Bonifazi - PyGTK 钩子改进。PyOpenGL 导入钩子。
  • Jamie Kirkpatrick - paste 导入钩子。
  • Lorenzo Mancini - OS X 下的 PyXML 导入钩子修复。OS X 支持。OS X 上的应用捆绑包创建。OS X 上的 Tkinter。OS X 的预编译引导程序。
  • Lorenzo Berni - django 导入钩子。
  • Louai Al-Khanji - optparse 模块的修复。
  • Thomas Heller - 设置 Windows exe 文件的自定义图标。
  • Eugene Prigorodov - KInterasDB 导入钩子。
  • David C. Morrill - vtkpython 导入钩子。
  • Alan James Salmoni -Tkinter 接口到 PyInstaller。

2.17 手册页面

2.17.1 pyinstaller

概述

pyinstaller<参数> 脚本文件…

pyinstaller<参数> .spec 文件名

描述

PyInstaller 是一个可以把 Python 程序打包成独立的可执行文件的程序,适用于 Windows、GNU/Linux、macOS、FreeBSD、OpenBSD、Solaris 和 AIX。相对于类似工具,它的主要优点是 PyInstaller 能与Python3.7-3.11 一起使用,它通过透明压缩构建更小的可执行文件,它是完全多平台的,并使用操作系统支持来加载动态库,从而确保完全兼容性。

您可以传递一个或多个 Python 脚本文件名或一个单独的 .spec 文件名。在第一种情况下,PyInstaller 会生成一个 .spec 文件(与 pyi-makespec 相同),并立即对其进行处理。

如果您传递了 .spec 文件,它将按照规定进行处理,命令行上给出的大多数选项将不会生效。有关详细信息,请参阅 PyInstaller 手册。

参数

位置参数

脚本名

脚本文件名或者确切的一个.spec文件。如果指定了.spec文件,大部分选项都是不必要的,并且会被忽略。

可选参数

-h,--help  显示帮助信息并退出
-v,--version  显示程序版本信息并退出。
--distpath DIR  希望将打包好程序放到的文件夹路径 (默认值: ./dist)
--workpath WORKPATH  为临时工作文件夹,所有的.log文件,.pyz文件等都应放在其中 (默认值:./build)
-y,--noconfirm  无需确认询问,直接替换输出路径(默认值: SPECPATH/dist/SPECNAME)
--upx-dir UPX_DIR  UPX utility 工具的路径 (默认按执行路径进行搜索)
-a,--ascii  不包括 unicode 编码支持 (默认包括,如果可用)
--clean  在构建之前清除 PyInstaller 缓存和临时文件。
--log-level LEVEL  构建过程中,控制台输出的详细程度,LEVEL 可以是 TRACE、DEBUG、INFO、WARN、DEPRECATION、ERROR、FATAL 中的一个 (默认值: INFO)。
也可以使用 PYI_LOG_LEVEL 环境变量进行设置覆盖。

生成什么

-D,--onedir  创建一个只包含一个可执行文件的文件夹。
-F,--onefile  创建一个只包含一个可执行文件的文件。
--specpath DIR  存放生成的.spec文件夹的路径 (默认值:当前目录)
-n NAME, --name NAME  为生成的打包应用和打包文件指定名称 (默认值:第一个脚本的根名称)

2.17. Man Pages 185

如何打包、搜索

--add-data   添加非二进制文件或文件夹到可执行文件中,路径分隔符因操作系统而异,一般是使用os.pathsep(如 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 名称而非路径名称)。可多次使用该选项。
--splash IMAGE_FILE (实验性质)  添加一个启动画面(splash screen),包含IMAGE_FILE 图像文件。启动画面可在解压包前显示进度更新。

186 Chapter 2. Contents:

如何打包

-d {all,imports,bootloader,noarchive},–debug {all,imports,bootloader,noarchive}

提供一个选项协助调试冻结的应用程序,可以提供多个参数来选择下面的几个选项。 
all:包括下面三个选项。
imports:指定 -v 选项给下层 Python 解释器,使其在初始化每个模块时都打印一条消息,显示加载该模块的位置(文件名或内置模块)。参考 https://docs.python.org/3/using/cmdline.html#id4 了解更多信息。 
bootloader:告诉引导程序在初始化和启动打包好的应用程序时发出进度消息。用于诊断缺失导入问题。
noarchive:使用该选项,不会像存储在结果可执行文件中的归档文件一样存储所有冻结的 Python 源文件,而是将它们作为文件存储在输出目录中。
--python-option PYTHON_OPTION  指定传递给 Python 解释器的命令行选项。目前支持“v”(相当于“--debug imports”)、“u”和“W <警告控制>”。
-s,--strip  对可执行文件和共享库应用符号表削减(不建议在 Windows 上使用)。
--noupx  即使可用,也不使用 UPX(在 Windows 和 *nix 上运行的方式不同)。
--upx-exclude FILE  在使用 upx 时,不要压缩某些二进制文件。这通常是在压缩过程中由 upx 破坏某些二进制文件时使用的。FILE 是没有路径名的文件名。可多次使用该选项。

Windows 和 Mac Os X 特定选项

-c, --console, --nowindowed 打开一个用于标准输入/输出的控制台窗口(默认)。在Windows上,如果第一个脚本是一个“.pyw”文件,则此选项无效。
-w,--windowed,--noconsole Windows和Mac OS X:不提供用于标准输入/输出的控制台窗口。在Mac OS上,这也会触发构建Mac OS.app包。在Windows上,如果第一个脚本是“.pyw”文件,则此选项会自动设置。此选项在*NIX系统上被忽略。
-i,--icon 
FILE.ico:将图标应用于Windows可执行文件。FILE.exe,ID:从exe中提取ID的图标。FILE.icns:将图标应用于Mac OS上的.app包。如果输入的图像文件不是平台格式(Windows上的ico,Mac上的icns),则PyInstaller尝试使用Pillow将图标转换为正确的格式(如果安装了Pillow)。使用“ NONE”来不应用任何图标,从而使操作系统显示一些默认值(默认:应用PyInstaller的图标)。此选项可多次使用。
--disable-windowed-traceback 禁用窗口(无控制台)模式(仅适用于Windows和macOS)下未处理异常的traceback dump,并显示一条消息,表示禁用了此功能。

2.17.手册页187

Windows特定选项

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

Windows并排装配搜索选项(高级)

--win-private-assemblies 将捆绑到应用程序中的任何共享程序集更改为私有程序集。这意味着这些程序集的确切版本将始终被使用,并且在用户机器上的系统级别安装的任何新版本都将被忽略。
--win-no-prefer-redirects 在搜索要捆绑到应用程序中的共享或私有程序集时,PyInstaller将优先考虑不遵循重定向到新版本的策略,并尝试捆绑程序集的确切版本,而不是绑定策略。中的任何程序集的确切版本。

Mac Os特定选项

--argv-emulation 对于macOS应用程序包启用argv仿真。如果启用,启动时初始打开文档/URL事件将由引导加载程序处理,并将传递的文件路径或URL附加到sys.argv中。
--osx-bundle-identifier BUNDLE_IDENTIFIER Mac OS.app包标识符用作代码签名目的的默认唯一程序名称。通常的形式是反向DNS表示法中的分层名称。例如:com.mycompany.department.appname(默认值:第一个脚本的基本名称)
--target-architecture ARCH,--target-arch ARCH 目标架构(仅限macOS;有效值:x86_64,arm64,universal2)。启用在冰冻应用程序的通用2和单一版本之间切换(前提是Python安装支持目标架构)。如果没有指定目标体系结构,则目标当前运行的体系结构。
--codesign-identity IDENTITY 签名代码身份(仅限macOS)。使用提供的身份来签名所收集的二进制文件和生成的可执行文件。如果未提供签名身份,则执行自适应签名。

188章2.内容:

--osx-entitlements-file FILENAME 在代码签名收集二进制文件时使用的权利文件(仅限macOS)。

Rarely Used Special Options

--runtime-tmpdir PATH 在onefile-模式下提取库和支持文件的位置。如果给出此选项,引导程序将忽略由运行时OS定义的任何临时文件夹位置。将在这里创建_MEIxxxxxx文件夹。请仅在确知自己正在做什么的情况下使用此选项。
--bootloader-ignore-signals 告诉引导程序忽略信号,而不是将其转发给子进程。在含有监管进程信号两个引导程序和子进程的情况下非常有用(例如,通过进程组),以避免向子进程发送两次信号。

环境变量

PYINSTALLER_CONFIG_DIR。这将更改PyInstaller缓存某些文件的目录。这个位置的默认位置取决于操作系统,但通常是主目录的子目录。

请参见

pyi-makespec(1),PyInstaller手册https://pyinstaller.readthedocs.io/,项目主页[http://www。](http://www。)
pyinstaller.org

2.17.2 pyi-makespec

概要

pyi-makespec SCRIPT [SCRIPT …]

描述

规范文件是您希望PyInstaller对程序执行的描述。pyi-makespec是一个简单的向导,用于创建涵盖基本用法的规范文件:

pyi-makespec [–onefile] yourprogram.py

默认情况下,pyi-makespec生成一个spec文件,告诉PyInstaller创建一个包含主可执行文件和动态库的发布目录。选项–onefile指定您希望PyInstaller构建一个包含所有内容的单个文件。

在大多数情况下,pyi-makespec生成的规范文件就是您所需的。如果不是,请参阅手册中的“当事情出错时”并确保阅读“规范文件”介绍。

2.17.手册页189

选项

位置参数

脚本名称

可选参数

-h,--help显示此帮助消息并退出
--log-level LEVEL生成时间控制台消息的详细程度。 LEVEL可以是TRACE、DEBUG、INFO、WARN、DEPRECATION、ERROR、FATAL之一(默认值:INFO)。也可以通过并覆盖环境变量PYI_LOG_LEVEL。

产生什么

-D, --onedir 创建一个包含可执行文件的单文件夹文件束(默认)
-F, --onefile 创建一个包含所有文件的单文件可执行文件。
--specpath DIR 存储生成规范文件的文件夹(默认:当前目录)
-n NAME, --name NAME 分配给文件束应用和规范文件的名称(默认:第一个脚本的 base-name)

要打包的内容,要搜索的位置

--add-data  需要添加到可执行文件中的其他非二进制文件或文件夹。路径分隔符是特定于平台的,正被用到os.pathsep(在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 复制指定包的元数据。可以多次使用此选项。

第二章190:内容:

--recursive-copy-metadata PACKAGENAME 复制指定包及其所有依赖项的元数据。可以多次使用此选项。
--additional-hooks-dir HOOKSPATH 额外的路径以查找钩子。可以多次使用此选项。
--runtime-hook RUNTIME_HOOKS 自定义运行时挂钩文件的路径。运行时挂钩是与可执行文件一起捆绑的代码,并在任何其他代码或模块之前执行以设置运行时环境的特殊功能。可以多次使用此选项。
--exclude-module EXCLUDES 可选的模块或包(Python名称,而不是路径名称),将被忽略(就像未找到一样)。可以多次使用此选项。
--splash IMAGE_FILE(实验性的)添加一个闪屏画面,其中包含应用程序的图像 IMAGE_FILE。备用图形可以在解压缩时显示进度更新。

如何生成

-d {all,imports,bootloader,noarchive}, –debug {all,imports,bootloader,noarchive}

R|提供用于调试打包应用程序的帮助。可以提供此参数多次以选择以下选项中的多个选项。 -all:所有以下选项。 -imports:指定-v选项到基础Python解释器,导致其每次初始化模块时打印一条消息,显示加载该模块的位置(文件名或内置模块)。有关详细信息,请参见https://docs.python.org/3/using/cmdline.html#id4。 - bootloader:告诉启动加载器在初始化和启动打包应用程序时发出进度消息。用于诊断缺失导入的问题。 - noarchive:而不是将所有冻结的Python源文件存储为结果可执行文件中的归档文件,将它们作为文件存储在结果输出目录中。
--python-option PYTHON_OPTION 指定要在运行时传递给Python解释器的命令行选项。当前支持“v”(等效于“-debug imports”)、“u”和“W”。
-s, --strip 对可执行文件和共享库应用符号表剥离(不推荐在Windows上使用)
--noupx 即使它可用也不要使用UPX(在Windows和*nix之间工作方式不同)
--upx-exclude FILE 在使用upx进行压缩时,防止对二进制文件进行压缩。如果upx在压缩期间破坏了某些二进制文件,则通常会使用此选项。 文件是不带路径的二进制文件的文件名。可以多次使用此选项。

Windows和Mac OS X特定的选项

-c, --console, --nowindowed 为标准输入/输出打开控制台窗口(默认)。在 Windows 上,如果第一个脚本是“.pyw”文件,则此选项无效。
-w, --windowed, --noconsole Windows和Mac OS X:不为标准i/o提供控制台窗口。在Mac上,这还会触发构建Mac OS .app束。在Windows上,如果第一个脚本是“.pyw”文件,则自动设置此选项。在*nix系统上,此选项被忽略。
-i , --icon 
FILE.ico:应用于Windows可执行文件的图标。 FILE.exe,ID:从.exe中提取带有ID的图标

第二章17.手册:191

--disable-windowed-traceback 禁用窗口(无控制台)模式(仅适用于Windows 和macOS)的未处理异常的跟踪转储,而是显示一条消息,说明已禁用此功能。

Windows特定选项

--version-file FILE 将FILE文件中的版本资源添加到exe文件中。
-m ,--manifest  将manifest文件或XML添加到exe文件中。
--no-embed-manifest 生成一个外部的.exe.manifest文件而不是将manifest嵌入exe文件中。只适用于onedir模式;在onefile模式下,无论是否使用此选项,manifest都将被嵌入执行文件中。
-r RESOURCE,--resource RESOURCE 添加或更新Windows可执行文件中的资源。RESOURCE为1到4个项,FILE[,TYPE[,NAME[,LANGUAGE]]]。FILE可以是数据文件或exe/dll文件。对于数据文件,必须至少指定TYPE和NAME。LANGUAGE默认为0,也可以指定为通配符*以更新给定TYPE和NAME的所有资源。对于exe/dll文件,如果类型、名称和语言被省略或使用通配符*指定,则将添加/更新FILE中的所有资源到最终的可执行文件中。此选项可以多次使用。
--uac-admin 使用此选项会创建一个Manifest,该Manifest会在应用程序启动时请求提升权限。
--uac-uiaccess 使用此选项允许提升权限的应用程序与远程桌面一起使用。

**Windows Side-By-Side Assembly Searching Options(Advanced)**

--win-private-assemblies 对于应用程序捆绑的任何共享程序集将更改为专用程序集。这意味着这些程序集的确切版本将始终被使用,用户机器上系统级别安装的任何更高版本都将被忽略。
--win-no-prefer-redirects 在搜索要捆绑到应用程序中的共享或专用程序集时,PyInstaller将优先不遵循重定向到较新版本的策略,并尝试捆绑程序集的确切版本。

Mac Os Specific Options

--argv-emulation 启用macOS应用程序包的argv仿真。如果启用,引导程序将处理初始打开文档/URL事件,并将传递的文件路径或URL附加到sys.argv。
--osx-bundle-identifier Mac OS .app包标识符用作唯一的程序名称以用于签名。通常的形式是反向DNS符号表示的分层名称。例如:com.mycompany.department.appname(默认值:第一个脚本的basename)
--target-architecture ARCH,--target-arch ARCH 目标体系结构(仅适用于macOS;有效值:x86_64、arm64、universal2)。启用在通用2和单一架构版本的冻结应用程序之间切换(只要Python安装支持目标体系结构)。如果未指定目标体系结构,则目标运行体系结构。
--codesign-identity IDENTITY 代码签名身份(仅适用于macOS)。使用提供的身份来签署收集的二进制文件和生成的可执行文件。如果未提供签名标识,则执行自动签名。
--osx-entitlements-file FILENAME 用于在代码签名所收集的二进制文件上使用的权利文件(仅限于macOS)。

Rarely Used Special Options

--runtime-tmpdir PATH 在onefile模式下,使用此选项将库和支持文件提取到的路径。如果给出此选项,启动程序将忽略运行时操作系统定义的任何临时文件夹位置。_MEIxxxxxx-文件夹将在此处创建。请仅在确信自己知道所做的内容时才使用此选项。
--bootloader-ignore-signals 告诉启动程序忽略信号而不是将信号转发给子进程。在需要监管进程向引导程序和子进程发送信号的情况下非常有用(例如通过进程组)。

环境变量

PYINSTALLER_CONFIG_DIR 这会更改PyInstaller缓存某些文件的目录。这个默认位置取决于操作系统,但通常是home目录的子目录。

参见

pyinstaller(1),The PyInstaller Manual https://pyinstaller.readthedocs.io/,项目主页 http://www.pyinstaller.org

2.17. Man Pages 193

2.18 开发指南

2.18.1 快速入门

  • 我们的Git仓库位于https://github.com/pyinstaller/pyinstaller:
git clone https://github.com/pyinstaller/pyinstaller

  • 开发在_develop_分支上进行。拉请求应该被提交到这个分支。
  • 发布将呆在_master_分支上。
  • 安装所需的测试工具:
pip install -r tests/requirements-tools.txt
  • 可以经常提交,但在请求代码审查之前将提交重新整理为逻辑补丁。git rebase -i是你的朋友。了解更多信息,请阅读“详细提交指南”。通常不接受功能不变的代码重构(有关原理,请参见#2727)。
  • 撰写有意义的提交消息。
    • 第一行应该是一个简短的句子,可以独立地作为更改的简短描述,在现在时态下编写,并以_subsystem-name_为前缀。
    • 提交消息的正文应解释或证明更改。有关详细的提交规则,请阅读“详细提交消息规则”。
  • 提供覆盖更改的测试并首先尝试在本地运行测试。
  • 针对develop分支提交拉请求。别忘了添加_changelog entry_以便我们的用户了解您的更改!
  • 对于新文件,请注意添加版权标头,请参见PyInstaller/init.py(还要注意更新到当前年份)。
  • 响应反馈,将新的“修复”提交与要修复的提交合并为一个带有交互式重写的新提交(git rebase -i)。使用git push --force推送新的重写分支。 (很可怕!但是github不能与更安全的方法良好地配合。)

2.18.2 初次使用GitHub或Git?

我们的开发工作流程建立在Git和GitHub之上。请花时间了解这些。如果您是GitHub新手,GitHub有指导您入门的说明。如果您是Git新手,则有在线教程和优秀的书籍可供阅读。

进一步阅读

  • “请编写好的提交消息”
  • “创建拉请求”
  • “更新拉请求”
  • “PyInstaller的分支模型”

2.18.3 编码约定

PyInstaller项目遵循PEP 8 Python代码样式指南。它使用yapf自动执行大部分格式化(主要是自动把空格放在正确的位置),并使用ruff验证PEP 8规则,yapf不支持的地方。

在提交更改到PyInstaller之前,请使用这两个工具检查您的代码。

要安装它们,请运行:

pip install ruff toml yapf==0.32.0

使用yapf自动重新格式化您的代码:

yapf -rip.

然后根据ruff给出的建议手动调整您的代码:

ruff --fix.

请勿重新格式化现有的代码,即使它没有遵循PEP 8。我们不会接受重新格式化的更改,因为它们使审查更加困难,并且在长期内跟进更改更加困难。有关完整的理由,请参见#2727。

2.18.4运行测试套件

请按以下方式运行测试套件。

1.如果您没有PyInstaller的git克隆,请首先使用pip获取当前的开发主要版本,…:

pip download --no-deps https://github.com/pyinstaller/pyinstaller/archive/develop.
˓→zip
unzip develop.zip
cd pyinstaller-develop/

…或使用git:

git clone https://github.com/pyinstaller/pyinstaller.git
cd pyinstaller

2.然后设置一个新的虚拟环境以运行测试套件,并安装所有必需的工具:

pip install --user virtualenv
virtualenv /tmp/venv

。/tmp/venv/bin/activate
pip install -r tests/requirements-tools.txt
3.要运行单个测试,请使用例如:

pytest tests/unit -k test_collect_submod_all_included

4.运行测试套件:

pytest tests/unit tests/functional
这仅运行核心功能的测试以及Python标准库中的一些软件包的测试。

2.18.发展指南195个

5.要获得更好的覆盖范围,包括许多可用的挂钩,需要下载要测试的Python软件包。请运行:

pip install -U -r tests/requirements-libraries.txt
pytest tests/unit tests/functional

要了解如何在持续集成测试中运行测试套件,请参见.travis.yml(适用于GNU / Linux和macOS)和appveyor.yml(适用于Windows)。

2.18.5提交指南

请帮助使代码和更改易于理解。提供遵循本指南的易于阅读的提交历史。

提交

  • 作为一个独立的,完整的,逻辑性的更改,
  • 具有详细的提交消息(请参见下文),
  • 没有额外的修改(空格更改,在不相关的文件中修正拼写错误等),
  • 严格遵循已建立的编码约定(** PEP8 **)。

避免一次提交几个不相关的更改。它使合并变得困难,也使确定如果出现错误,则哪个更改是罪魁祸首更加困难。

如果在提交之前进行了几个不相关的更改,git gui使提交选定的部分甚至选定行变得容易。尝试在窗口差异区域内使用上下文菜单。

这将导致更可读的历史记录,使人更容易理解为什么进行了变更。如果出现问题,可以更轻松地使用_git bisect_找到破坏变更并回滚这些破坏变更。

详述

提交应该是一个(而且仅是一个)逻辑单元。它应该是某人可能想要整体修补或还原的东西,而不是逐个修补。如果它可以分开使用,请进行单独的提交。

  • 进行小型修补(即以一致的增量工作)。
  • 通常不会接受格式化代码而没有功能更改的事实生效(有关原理,请参见#2727)。如果需要这样的更改,请将其分成自己的提交并进行文档编制。
    这意味着在以后查看补丁时,我们不必浏览大量非功能性更改,以找到补丁的相关部分。
  • 特别不要混合不同类型的更改,并为每种类型的更改放置标准前缀以在提交消息中进行标识。
  • 拒绝重构!如果有,请将不应更改功能的重构限制为它们自己的提交(并记录)。
  • 将功能更改(错误修复或新功能)限制为它们自己的更改列表(并记录)。
  • 如果您的提交系列包括任何“fix up”提交(“修正错别字。”,“修复测试。”,“删除已注释的代码。”),请使用git rebase-i …在提交拉取请求之前清理它们。尝试窗口有一个上下文菜单内部。
  • 使用git rebase-i对提交拉取请求之前的提交进行排序,组合和修复。使其成为易于理解您所做的内容的可读历史记录。

196章2。目录:

请编写好的提交消息

请帮助使代码和更改易于理解。编写好的提交消息遵循此指南。

提交消息应提供足够的信息,以使第三方能够决定更改是否与他们相关,并且是否需要阅读更改本身。

PyInstaller自2005年以来一直得到维护,我们经常需要在许多年后理解为什么特定的更改已实现如此。当更改应用时似乎很明显的内容多年后可能只是晦涩。原始贡献者可能无法联系,而其他开发人员需要理解原始作者考虑的原因,副作用和决策。

我们得知提交消息对于理解更改很重要,因此我们对它们有点挑剔。

我们可能会要求您重新编写提交消息。在这种情况下,请使用git rebase-i …和git push-f …更新您的拉取请求。有关详细信息,请参见“更新拉取请求”。

提交消息的内容

编写有意义的提交消息。

提交消息的第一行应该

  • 是一个短句(最大72个字符,但计算50个),
  • 使用现在时态(“添加令人敬畏的功能。”)^1,
  • 用于此提交相关的子系统的标识符(“tests:Fix the frob。”或“building:Make all nodes turn faster。”),
  • 总是以句号结束。
  • 句号以外的结束标点符号应用于表示汇总行不完整,并在分隔符后继续;“…”是常规的。

提交消息正文

提交日志的正文应:

  • 解释或验证更改,
    • 如果您发现自己描述实现细节,则最有可能需要将其放入源代码注释中。
    • 请包括更改的动机,并将其与先前的行为进行对比。

(^1)将这些消息作为应用提交的说明。此外,这种约定与诸如git merge和git revert命令生成的提交消息相匹配。
2.18.开发指南197

  • 对于更加复杂或严重的更改,请记录相关决策,将其与所选择的其他可能性对比,记录您的副作用或其他
    必须记住的东西,这样可以再次触及代码。 (尽管后者最好写在源代码注释中。)
  • 对于错误修复,请提供票据号码或链接到票据,
  • 说明对高层次进行的更改(GNU ChangeLog标准值得一读),每行应匹配72个字符,不要超过80个字符;和
    与第一行隔开一行。
  • 项目符号和编号列表也可以:
    • 通常使用连字号或星号用于项目符号,前面有一个单个空格,之间有空行,但是这里的约定会有所不同。
    • 使用悬挂缩进。
    • 不要以井号(#)开头的提交消息,因为git某些git命令可能会忽略这些消息 (有关详细信息,请参阅此讨论。)

标准前缀

请将此提交所涉及的“子系统”作为前缀在第一行中声明。要了解其他人使用的前缀,请使用git log --oneline path/to/file/or/dir。

“子系统”的示例包括:

-钩子用于钩子相关更改
-引导加载程序,引导加载程序构建引导加载程序或其构建系统
-依赖项检测部分(PyInstaller / depend)的依赖部分
-用于构建部分的构建部分(PyInstaller / building)
-用于不同Python版本的兼容性的代码相关的兼容性(primaryPyInstaller / compat.py)
-加载器
-工具,工具/钩子
-测试,测试/ CI:用于更改测试套件(包括要求)的,CI。.

  • modulegraph:与PyInstaller / lib / modulegraph相关的更改
  • Doc,Doc build用于文档内容的文档建设体系。您可能还想指定章节或部分。

请设置正确的作者

请确保您已设置git以使用正确的名称和电子邮件提交。在可能推送的所有机器上使用相同的姓名和电子邮件。
例如:


#设置名称和电子邮件
git config --global user.name “Firstname Lastname”
git config --global user.email “[email protected]

第198章。目录:

这将设置此名称和电子邮件地址以用于此系统上正在使用的所有git-repos。要将其设置为
仅适用于PyInstaller repo,请删除-global标志。

或者,您可以使用git gui→ _Edit_→ _Options …_来设置这些值。

进一步阅读

有关编写良好提交消息的进一步提示和教程也可以在以下位置找到:

-自由BSD Committer的指南
-[http://365git.tumblr.com/post/3308646748/writing-git-commit-messages](http://365git.tumblr.com/post/3308646748/writing-git-commit-messages)
-[http://wincent.com/blog/commit-messages:](http://wincent.com/blog/commit-messages:)好,坏和丑。
-[http://wiki.scummvm.org/index.php/Commit_Guidelines](http://wiki.scummvm.org/index.php/Commit_Guidelines)
-[http://lbrandy.com/blog/2009/03/writing-better-commit-messages/](http://lbrandy.com/blog/2009/03/writing-better-commit-messages/)
-[http://blog.looplabel.net/2008/07/28/best-practices-for-version-control/](http://blog.looplabel.net/2008/07/28/best-practices-for-version-control/)
-[http://subversion.apache.org/docs/community-guide/conventions.html](http://subversion.apache.org/docs/community-guide/conventions.html)(目标过于注重子版本使用,我们强烈要求使用如此细粒度的提交。)

积分

这个页面是从以下材料中组成的

-[http://hackage.haskell.org/trac/ghc/wiki/WorkingConventions/Git](http://hackage.haskell.org/trac/ghc/wiki/WorkingConventions/Git)
-[http://lbrandy.com/blog/2009/03/writing-better-commit-messages/](http://lbrandy.com/blog/2009/03/writing-better-commit-messages/)
-[http://365git.tumblr.com/post/3308646748/writing-git-commit-messages](http://365git.tumblr.com/post/3308646748/writing-git-commit-messages)
-[http://www.catb.org/esr/dvcs-migration-guide.html](http://www.catb.org/esr/dvcs-migration-guide.html)
-https://git.dthompson.us/presentations.git/tree/HEAD:/happy-patching
-和其他地方。

2.18.6 改进和构建文档

PyInstaller的文档使用Sphinx创建。 Sphinx使用reStructuredText作为其标记语言,许多
从reStructuredText及其解析和转换套件Docutils的强度中获得。

文档随代码一起维护在Git存储库中,推向develop分支将创建一个新版本https://pyinstaller.readthedocs.io/en/latest/。

对于小更改(如打字错误),您可以只是在Github上 fork PyInstaller,在线编辑文档并创建
拉请求。

对于任何其他事情,我们要求您克隆存储库并验证您的更改:

pip install -r doc/requirements.txt
cd doc
make html
xdg-open _build/html/index.html

2.18.开发指南199

请在构建文档时注意任何警告和错误。在推送更改和创建拉请求之前,请在浏览器中检查标记是否有效。
请也运行:

make clean
...
make html

再次验证一切是否正确。谢谢!

我们可能会要求您重新设计更改或重新设计提交消息。在这种情况下,请使用git rebase -i …和
git push -f …来更新您的拉请求。有关详细信息,请参见“更新拉请求”。

PyInstaller扩展

对于PyInstaller文档,除了Sphinx和docutils中的角色之外,还提供可用的角色*^0。

:commit:
引用提交,创建到在线git存储库的web-link。为了可读性,提交ID将缩短为8位数字。例如:commit:a1b2c3d4e5f6a7b8c9将变成@a1b2c3d。

:issue:
链接到Github的问题或拉请求编号。例如:issue:123将变成#123。

reStructuredText备忘单

  • 结合标记和链接:
安装PyInstaller最简单的方法是使用 |pip|_::
.. |pip| replace:: :command:`pip`
.. _pip: https://pip.pypa.io/

2.18.7 创建 Pull-Request

示例

  • 在 https://github.com 上创建账户
  • 在 GitHub 上创建一个 pyinstaller/pyinstaller 项目的分支。
  • 通过遵循 GitHub 上的文档来设置您的 git 客户端。
  • 将您的分支克隆到本地计算机。:
git clone [email protected]:YOUR_GITHUB_USERNAME/pyinstaller.git
cd pyinstaller
  • 开发您的更改(也称为“hack”)
    - 创建要执行的分支(可选):
git checkout -b my-patch

(^0) 具体定义在doc/_extensions/pyi_sphinx_roles.py中
第200章 内容:

- 如果你要实现一个 hook,那么请先创建一个最小化的构建测试(见下文)。你需要测试你的 hook,为什么不从一开始就用构建测试呢?
- 将您的更改合并到 PyInstaller 中。
- 运行所有构建测试以确保没有其他问题。请尽可能在尽可能多的平台上进行测试。
- 您可以在提交消息中引用相关问题(例如 #1259),以便 GitHub 将问题和提交链接在一起,而使用“fixes #1259”这样的短语,您甚至可以自动关闭相关问题。

  • 用 PyInstaller 上游仓库同步您的分支。有两种方式:
  1. 在当前开发版本头上重置您的更改(最好的选择,因为它会产生一个更直接的历史,冲突更容易解决):
git remote add upstream https://github.com/pyinstaller/pyinstaller.git
git checkout my-patch
git pull --rebase upstream develop
git log --online --graph
  1. 将当前开发头合并到您的更改中:
git remote add upstream https://github.com/pyinstaller/pyinstaller.git
git fetch upstream develop
git checkout my-patch
git merge upstream/develop
git log --online --graph
有关详细信息,请参见在 GitHub 上同步 fork。
  • 将您的更改推送到您的分支:
git push
  • 打开 https://github.com/YOUR_GITHUB_USERNAME/pyinstaller/pulls 中的 Pull Requests 页面,然后单击“New pull request”。就这样。

更新 Pull-Request

我们可能会要求您更新您的 pull-request 以提高其质量或出于其他原因。在这种情况下,使用git rebase
-i…和git push -f…如下所述。^1 请不要关闭 pull-request 并打开一个新的 one – 这会杀死讨论线程。

这是没有实际更改基础的工作流:

git checkout my-branch
# 找到您的分支从“develop”分叉的提交
mb=$(git merge-base --fork-point develop)
# 交互式变基而不实际更改基础
git rebase -i $mb
# 处理重新基础
git push -f my-fork my-branch

或者,如果您想实际基于当前的开发头:

(^1) 更新 pull-request 还有其他方法,例如“修正”提交。但对于随意(和非常随意的 用户rebase -i可能是最简单的方法。
**第2.18节 开发指南 201 **

git checkout my-branch
# 在develop上交互式变基
git rebase -i develop
# 处理重新基础
git push -f my-fork my-branch

2.18.8 更新日志条目

如果您的更改是值得注意的,则需要一条日志条目,以便我们的用户可以了解它!

为避免合并冲突,我们使用towncrier包来管理我们的更改日志。towncrier使用独立的文件为每个 pull-request – 称为_news fragments_ 而不是一个巨大的 changelog 文件。在发布时,这些新闻片段将编译成我们的doc/CHANGELOG.rst。

您不需要安装towncrier,只需要遵守一些简单的规则:

  • 对于每个 pull-request,请添加一个文件到 news/,文件名符合 pr#。
    (feature|bugfix|breaking).rst架构:例如,在 pull request #42 中提议新功能的news/42.feature.rst。
    我们的类别是:feature、bugfix、breaking(破坏性更改)、deprecation、hooks(所有钩子相关的更改)、bootloader、moduleloader、doc、process(项目基础架构、开发流程等)、core、build(引导加载程序构建流程)和 tests。
  • 与其他文档一样,请在新闻片段中使用语义化换行。
  • 偏爱使用现在时或构造以“现在”或“新”的方式。例如:
    - 为 my-fancy-library 添加 hook。
    - 修复当尝试使用–resourc选项将资源添加到 Windows 可执行文件时崩溃的问题。
    如果更改只与特定平台相关,请使用前缀,如这里所示:
    - (GNU/Linux)在构建带–debug时,将 FORTIFY_SOURCE 关闭以便于调试。
  • 将模块、函数或类等符号包裹在双引号中,以便它们呈现成单间距字体。如果提到函数或其他可调用项,请在名称的末尾添加括号:is_module()。这使得更改日志更易读。
  • 如果您想引用多个问题,请将新闻片段复制到另一个文件名中。towncrier将合并相同内容的所有新闻片段为一个条目,其中包含多个链接到相应 pull-request 的链接。您也可以引用一个现有的新闻片段来复制那个。
  • 如果您的 pull-request 包括几个不同的主题,您可能会想添加几个新闻片段文件。例如 4242.feature.rst 用于新功能, 4242.bootloader 用于 bootloader 的相关更改。

请记住,新闻条目是为最终用户而设计的,并且只应包含对最终用户相关的细节。

第202章 内容:

2.18.9 pyenv 和 PyInstaller

**注意:**此部分仍处于起草阶段。请帮助扩展它。

  • 克隆 pyenv 仓库:
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
  • 克隆 virtualenv 插件:
git clone https://github.com/yyuu/pyenv-virtualenv.git \
~/.pyenv/plugins/pyenv-virtualenv
  • 添加到 .bashrc.zshrc
# 将'pyenv'添加到PATH环境变量中。
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
# 为pyenv启用shims和自动补全。
eval "$(pyenv init -)"
# 通过将以下内容添加到〜/ .zshrc文件中来自动加载pyenv-virtualenv:
#
eval "$(pyenv virtualenv-init -)"
  • 安装具有共享libpython的Python版本(PyInstaller必须运行):
env PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.5.0
  • 设置virtualenv:pyenv virtualenv 3.5.0 venvname
  • 激活虚拟环境:pyenv activate venvname
  • 退出虚拟环境:pyenv deactivate

2.18.10 PyInstaller的分支模型

develop branch 我们将origin/ develop视为主要分支,其中HEAD的源代码始终反映了下一个发布的最新开发更改的状态。有些人称之为“集成分支”。
master branch 我们认为origin/ master是源代码的主要分支,其中HEAD始终反映出生产就绪状态。将每个提交到主分支视为新版本,并将其标记。

PyInstaller项目不使用长期存在的分支(除了_master_和_develop_),因为我们不会同时支持几个主要版本的bugfix。

偶尔地,您可能会在代码库中找到这些分支:^1

release/ branches 这些分支用于准备下一个版本的发布。例如:更新版本号、完善变更日志、重新编译引导加载程序、重建手册。有关发布过程以及必须执行哪些步骤的详细信息,请参见ref: release-workflow。

(^1)此分支模型基本上与Vincent Driessen在此博客中描述的相同。但是,目前我们并没有严格遵循它。

2.18.开发指南203

hotfix/ branches 这些分支也是为了准备新的生产版本,尽管是非计划的。这就是通常所说的“热修复”。
feature/ branches 特性分支(有时也称为主题分支)用于开发即将发布或将来发布的新功能。

2.19索引和表格

  • 索引
  • 模块索引
  • 搜索

第204章 内容:

Python模块索引

p

pyi_splash,69
PyInstaller.compat,80
PyInstaller.isolated,89
PyInstaller.utils.hooks,80
PyInstaller.utils.hooks.conda,87

第206章 Python模块索引

索引

符号

init()( Splash方法 ), 36

  • -D
    命令行选项,13
  • -F
    命令行选项,13
  • –add-binary
    命令行选项,14
  • –add-data
    命令行选项,14
  • –additional-hooks-dir HOOKSPATH
    命令行选项,14
  • –argv-emulation
    命令行选项,16
  • –ascii
    命令行选项,13
  • –bootloader-ignore-signals
    命令行选项,17
  • –clean
    命令行选项,13
  • –codesign-identity IDENTITY
    命令行选项,16
  • –collect-all MODULENAME
    命令行选项,14
  • –collect-binaries MODULENAME
    命令行选项,14
  • –collect-data MODULENAME
    命令行选项,14
  • –collect-datas MODULENAME
    命令行选项,14
  • –collect-submodules MODULENAME
    命令行选项,14
  • –console
    命令行选项,15
  • –copy-metadata PACKAGENAME
    命令行选项,14
  • –debug {all,imports,bootloader,noarchive}
    命令行选项,15
  • –disable-windowed-traceback
    命令行选项,15
  • –distpath DIR
    命令行选项,13
  • –exclude-module EXCLUDES
    命令行选项,14
  • –help
    命令行选项,13
  • –hidden-import MODULENAME
    命令行选项,14
  • –hiddenimport MODULENAME
    命令行选项,14
  • –icon
    命令行选项,15
  • –log-level LEVEL
    命令行选项,13
  • –manifest
    命令行选项,16
  • –name NAME
    命令行选项,13
  • –no-embed-manifest
    命令行选项,16
  • –noconfirm
    命令行选项,13
  • –noconsole
    命令行选项,15
  • –noupx
    命令行选项,15
  • –nowindowed
    命令行选项,15
  • –onedir
    命令行选项,13
  • –onefile
    命令行选项,13
  • –osx-bundle-identifier BUNDLE_IDENTIFIER
    命令行选项,16
  • –osx-entitlements-file FILENAME
    命令行选项,16
  • –paths DIR
    命令行选项,14
  • –python-option PYTHON_OPTION
    命令行选项,15
  • –recursive-copy-metadata PACKAGENAME
    命令行选项,14
  • –resource RESOURCE

207

命令行选项

  • --runtime-hook RUNTIME_HOOKS,16
  • --runtime-tmpdir PATH,14
  • --specpath DIR,17
  • --splash IMAGE_FILE,13
  • --strip,14
  • --target-arch ARCH,15
  • --target-architecture ARCH,16
  • --uac-admin,16
  • --uac-uiaccess,16
  • --upx-dir UPX_DIR,16
  • --upx-exclude FILE,13
  • --version,13
  • --version-file FILE,15
  • --win-no-prefer-redirects,16
  • --win-private-assemblies,16
  • --windowed,16
  • --workpath WORKPATH,15
  • -a,13
  • -c,13
  • -d {all,imports,bootloader,noarchive},15
  • -h,13
  • -i ,13
  • -m ,15
  • -n NAME,16
  • -p DIR,13
  • -r RESOURCE,14
  • -s,16
  • -v,15
  • -w,13
  • -y,15

B

  • base_prefix(在模块PyInstaller.compat中),80

C

  • call()(在模块PyInstaller.isolated中),89
  • call()(Python方法),91
  • CC,106
  • close()(在模块pyi_splash中),70
  • collect_all()(在模块PyInstaller.utils.hooks中),82
  • collect_data_files()(在模块PyInstaller.utils.hooks中),83
  • collect_delvewheel_libs_directory()(在模块PyInstaller.utils.hooks中),86
  • collect_dynamic_libs()(在模块PyInstaller.utils.hooks中),84
  • collect_dynamic_libs()(在模块PyInstaller.utils.hooks.conda中),88
  • collect_entry_point()(在模块PyInstaller.utils.hooks中),85
  • collect_submodules()(在模块PyInstaller.utils.hooks中),83
  • 命令行选项:
    • -D,13
    • -F,13
    • --add-binary ,14
    • --add-data ,14
    • --additional-hooks-dir HOOKSPATH,14
    • --argv-emulation,16
    • --ascii,13
    • --bootloader-ignore-signals,17
    • --clean,13
    • --codesign-identity IDENTITY,16
    • --collect-all MODULENAME,14
    • --collect-binaries MODULENAME,14
    • --collect-data MODULENAME,14
    • --collect-datas MODULENAME,14
    • --collect-submodules MODULENAME,14
    • --console,15
    • --copy-metadata PACKAGENAME,14
    • --debug {all,imports,bootloader,noarchive},15
    • --disable-windowed-traceback,15
    • --distpath DIR,13
    • --exclude-module EXCLUDES,14
    • --help,13
    • --hidden-import MODULENAME,15
    • --hiddenimport MODULENAME,14
    • --icon ,15
    • --log-level LEVEL,16
    • --manifest ,13
    • --name NAME,16
    • --no-embed-manifest,15
    • --noconfirm,13
    • --noconsole,15
    • --noupx,15
    • --nowindowed,15
    • --onedir,13
    • --onefile,13
    • --osx-bundle-identifier BUNDLE_IDENTIFIER,16
    • --osx-entitlements-file FILENAME,16
    • --paths DIR,14
    • --python-option PYTHON_OPTION,15
    • --recursive-copy-metadata PACKAGENAME,14
    • --resource RESOURCE,16
    • --runtime-hook RUNTIME_HOOKS,14
    • --runtime-tmpdir PATH,17
    • --specpath DIR,13
    • --splash IMAGE_FILE,14
    • --strip,15
    • --target-arch ARCH,16
    • --target-architecture ARCH,16
    • --uac-admin,16
    • --uac-uiaccess,16
    • --upx-dir UPX_DIR,13
    • --upx-exclude FILE,15
    • --version,13
    • --version-file FILE,16
get_homebrew_path() (在 PyInstaller.utils.hooks 模块中),86
get_hook_config() (在 PyInstaller.utils.hooks 模块中),92
get_module_attribute() (在 PyInstaller.utils.hooks 模块中),84
get_module_file_attribute() (在 PyInstaller.utils.hooks 模块中),84
get_package_paths() (在 PyInstaller.utils.hooks 模块中),85

I

include_or_exclude_file() (在 PyInstaller.utils.hooks 模块中),86
is_aix(在 PyInstaller.compat 模块中),80
is_alive()(在 pyi_splash 模块中),69
is_cygwin(在 PyInstaller.compat 模块中),80
is_darwin(在 PyInstaller.compat 模块中),80
is_freebsd(在 PyInstaller.compat 模块中),80
is_linux(在 PyInstaller.compat 模块中),80
is_module_or_submodule() (在 PyInstaller.utils.hooks 模块中),83
is_module_satisfies() (在 PyInstaller.utils.hooks 模块中),81
is_openbsd(在 PyInstaller.compat 模块中),80
is_package()(在 PyInstaller.utils.hooks 模块中),83

第209条索引

is_solar (在 PyInstaller.compat 模块中),80
is_venv (在 PyInstaller.compat 模块中),80
is_win (在 PyInstaller.compat 模块中),80
issue(角色),200

L

locate()(PackagePath 方法中),88

M

模块
pyi_splash,69
PyInstaller.compat,80
PyInstaller.isolated,89
PyInstaller.utils.hooks,80
PyInstaller.utils.hooks.conda,87

O

OBJECT_MODE,25,105,106

P

package_distribution()(在 PyInstaller.utils.hooks.conda 模块中),87
PackagePath(PyInstaller.utils.hooks.conda 中的类),88
pyi_splash
模块,69
PyInstaller.compat
模块,80
PyInstaller.isolated
模块,89
PyInstaller.utils.hooks
模块,80
PyInstaller.utils.hooks.conda
模块,87
Python(PyInstaller.isolated 中的类),91
Python增强提案
PEP 0440,81
PEP 239,126
PEP 263,108
PEP 302,68
PEP 405,20
PEP 527,154
PEP 552,144
PEP 8,195,196
PYTHONHASHSEED,75
PYTHONPATH,30

R

requires()(在 PyInstaller.utils.hooks.conda 模块中),88

S

脚本名称
命令行选项,13

U

update_text()(在 pyi_splash 模块中),69

W

walk_dependency_tree()(在 PyInstaller.utils.hooks.conda 模块中),88

第210条索引

你可能感兴趣的:(docs-translated,python,文档资料)