PyInstaller会在打包时自动为我们收集一些依赖项,特别是我们在打包PyQt/PySide相关的应用时,PyInstaller会自动包含我们程序通常不需要的文件,如'tanslations'文件夹,'plugins/imageformats'等,通常这些文件会使我们最终的exe文件变大。在网上没有找任何好的方法来排除这些文件,从这个Issuehttps://github.com/pyinstaller/pyinstaller/issues/5503里我们可以看到一种方法就是在打包之前先删除PyQt安装目录中的不需要文件,这种做法能达到目的,但在我看来实在是不够优雅。
PyInstaller其实最终都依靠spec文件来获取依赖及其它配置项,而生成spec文件内容是由一个模板(https://github.com/pyinstaller/pyinstaller/blob/develop/PyInstaller/building/templates.py)控制, 所以我们可以在生成之前去修改(patch)下这个模板,就可以达到控制依赖项的目的。
以下假设我们是通过代码方式来调用Pyinstaller,并使用onefile模式(onedir模块可参照修改).
注意以下
Analysis
语句后面的代码即为处理datas和binaries的代码,在这里可以添加任何过滤逻辑
import PyInsatller.building.templates as pyi_spec_templatesfrom PyInstaller.__main__ import run as pyi_build# copy from PyInsatller.building.templates.py# add datas and binaries filter after Analysisonefiletmplate ="""# -*- mode: python ; coding: utf-8 -*-%(preamble)sa = Analysis( %(scripts)s, pathex=%(pathex)s, binaries=%(binaries)s, datas=%(datas)s, hiddenimports=%(hiddenimports)s, hookspath=%(hookspath)r, hooksconfig={}, runtime_hooks=%(runtime_hooks)r, excludes=%(excludes)s, noarchive=%(noarchive)s, optimize=%(optimize)r,)# begin filter any datas you wantdatas = []for dest_name, src_name, res_type in a.datas: # 在这里添加过滤逻辑 datas.append((dest_name, src_name, res_type))a.datas = datas# end filter datas# begin filter any binaries you wantbinaries = []for dest_name, src_name, res_type in a.binaries: # 在这里添加过滤逻辑 binaries.append((dest_name, src_name, res_type))a.binaries = binaries# end filter dataspyz = PYZ(a.pure)%(splash_init)sexe = EXE( pyz, a.scripts, a.binaries, a.datas,%(splash_target)s%(splash_binaries)s %(options)s, name='%(name)s', debug=%(debug_bootloader)s, bootloader_ignore_signals=%(bootloader_ignore_signals)s, strip=%(strip)s, upx=%(upx)s, upx_exclude=%(upx_exclude)s, runtime_tmpdir=%(runtime_tmpdir)r, console=%(console)s, disable_windowed_traceback=%(disable_windowed_traceback)s, argv_emulation=%(argv_emulation)r, target_arch=%(target_arch)r, codesign_identity=%(codesign_identity)r, entitlements_file=%(entitlements_file)r,%(exe_options)s)"""pyi_spec_templates.onefiletmplt = onefiletmplate # ==> patch the template string here# build exepyi_build(['main.py', '--onefile', ...])