1、系统、pyinstaller、python、PyQt5版本对应:
1:第一组(已验证)
win10
python==3.7.4
pyinstaller==3.6
PyQt5==5.13.2
matplotlib==3.0.3
2:第二组(未验证)
Win10
Python==3.6.2
Pyinstaller==3.4
PyQT==5.9.2
3:第三组(未验证)
Win7
Python==3.6.4
Pyinstaller==3.5
PyQT==5.8.0
4:第四组(未验证)
Python==3.4
PyQt==5.4
Pyinstaller==3.2.1
5:第五组(未验证)
Python==3.5
PyQt==5.8
Pyinstaller==3.2.1
2、pyinstaller手册
3、pyinstaller命令常用选项及含义
-F, --onefile 打包一个单个文件,如果你的代码都写在一个.py文件的话,可以用这个,如果是多个.py文件就别用
-D, --onedir 打包多个文件,在dist中生成很多依赖文件,适合以框架形式编写工具代码,我个人比较推荐这样,代码易于维护
-K, --tk 在部署时包含 TCL/TK
-a, --ascii 不包含编码.在支持Unicode的python版本上默认包含所有的编码.
-d, --debug 产生debug版本的可执行文件(对于多文件打包,使用此参数, 可能会报错)
-w,--windowed,--noconsole 使用Windows子系统执行.当程序启动的时候不会打开命令行(只对Windows有效)
-c,--nowindowed,--console 使用控制台子系统执行(默认)(只对Windows有效)pyinstaller -c xxxx.pypyinstaller xxxx.py –console
-s,--strip 可执行文件和共享库将run through strip.注意Cygwin的strip往往使普通的win32 Dll无法使用.
-X, --upx 如果有UPX安装(执行Configure.py时检测),会压缩执行文件(Windows系统中的DLL也会)
--clean 在构建之前,请清理PyInstaller缓存并删除临时文件。
-o DIR, --out=DIR 指定spec文件的生成目录,如果没有指定,而且当前目录是PyInstaller的根目录,
会自动创建一个用于输出(spec和生成的可执行文件)的目录.如果没有指定,
而当前目录不是PyInstaller的根目录,则会输出到当前的目录下.
-p DIR, --path=DIR 设置导入路径(和使用PYTHONPATH效果相似).可以用路径分割符(Windows使用分号,
Linux使用冒号)分割,指定多个目录.也可以使用多个-p参数来设置多个导入路径,
让pyinstaller自己去找程序需要的资源
--icon=<FILE.ICO> 将file.ico添加为可执行文件的资源(只对Windows系统有效),
改变程序的图标 pyinstaller -i ico路径 xxxxx.py
–icon=<FILE.EXE,N> 将file.exe的第n个图标添加为可执行文件的资源(只对Windows系统有效)
-v FILE, --version=FILE 将verfile作为可执行文件的版本资源(只对Windows系统有效)
-n NAME, --name=NAME 可选的项目(产生的spec的)名字.如果省略,第一个脚本的主文件名将作为spec的名字```
--paths=C:\xxx # 用于指定pyinstaller搜索包的路径,通常不需要指定
# 因为site-packages下的都会被搜索
--icon=C:\xxx # 用于设置exe程序的ico图标,亲测必须为ico且要求ico图片分辨率(建议64x64)
# 需要打包一个单独的.py文件时
-F # 带控制台
-F -w # 不带控制台,直接以Windows窗体打开
# 需要打包多py文件的项目时
-w或-D -w # 不带控制台,直接以windows窗体打开
# 第一次打包时建议用-c模式,让程序以控制台子系统执行,方便调试,无错误后用-F或-w进行打包
4、单个文件打包
# 命令
# 带有终端窗口
pyinstaller -F xxx.py
# 不带终端窗口
pyinstaller -F -w xxx.py
5、多文件打包流程
00、打包流程简介
以上的选项是大多是对于生成spec文件的 pyi-makespec 命令的 :pyi-makespec -option xxx.py
当生成spec文件后进行编辑,然后执行命令: pyinstaller xxx.spec
01、安装pyinstaller打包环境
win10(可使用虚拟机搭建)
安装 python==3.7.4
pip install pyinstaller==3.6
pip install PyQt5==5.13.2
02、创建spec文件
创建一个文件夹, 将项目放到文件夹中, 然后cd到这个文件夹执行pyi
# xxx.py 是要打包的python项目的启动文件
pyi-makespec -w xxx.py
如:
pyi-makespec -w C:\Users\61980\Desktop\pyzo\pyzo\pyzo\__main__.py
生成的__main__.spec文件内容 如下:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['C:\\Users\\61980\\Desktop\\pyzo\\pyzo\\__main__.py'],
pathex=['C:\\Users\\61980\\Desktop\\pyzo'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='__main__',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='__main__')
03、编辑spec文件
1、更改生成可执行exe的名字,及包的名字。
将生成__main__.spec文件改名为pyzo.spec, 并将文件中name字段对应的"__main__"改为"pyzo"
更改为pyzo.spec内容如下:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['C:\\Users\\61980\\Desktop\\pyzo\\pyzo\\__main__.py'],
pathex=['C:\\Users\\61980\\Desktop\\pyzo'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='pyzo',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='pyzo')
2、spec文件常用参数含义
01、Analysis
文件打包目录路径: 打包目录的绝对路径, 打包目录默认dist目录下, 名字是spec文件中COLLECT参数name,
dist目录默认生成在执行"pyinstaller xxx.spec"命令的目录下。
第一个参数是:指定启动项目的启动入口文件, 是个列表
pathex : 指定项目的导包路径,是一个列表, 可以指定多个
binaries : 添加dll、so等文件到打包目录, 类型:列表, 列表元素是元祖, (文件在系统中的绝对路径, 文件相对于打包目录的路径)
datas : 添加数据文件打包目录, 类型:列表, 列表元素是元祖, (文件在系统中的绝对路径, 文件相对于打包目录的路径)
hiddenimports : 对于pyinstaller无法收集但项目又需要导入的模块, 可以使用这个参数, 类型:列表
02、EXE
name : 生成exe可执行文件的名字,
debug : 是否进行debug, True或False, 需要console配合,
console : 是否显示调用终端显示运行信息
3、编辑后的完整的pyzo.spec文件
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
root_dir = "C:\\Users\\61980\\Desktop\\pyzo"
a = Analysis(["C:\\Users\\61980\\Desktop\\pyzo\\pyzo\\__main__.py"],
pathex=[
root_dir],
binaries=[(root_dir + "\\pyzo\\resources\\libs\\mips64", "pyzo\\resources\\libs\\mips64"),
(root_dir + "\\pyzo\\resources\\libs\\x86_64", "pyzo\\resources\\libs\\x86_64"),
(root_dir + "\\pyzo\\resources\\libs\\x86_64\\old", "pyzo\\resources\\libs\\x86_64\\old")],
datas=[(root_dir + "\\pyzo\\resources\\appicons", "pyzo\\resources\\appicons"),
(root_dir + "\\pyzo\\resources\\fonts", "pyzo\\resources\\fonts"),
(root_dir + "\\pyzo\\resources\\icons", "pyzo\\resources\\icons"),
(root_dir + "\\pyzo\\resources\\images", "pyzo\\resources\\images"),
(root_dir + "\\pyzo\\resources\\themes", "pyzo\\resources\\themes"),
(root_dir + "\\pyzo\\resources\\translations", "pyzo\\resources\\translations"),
(root_dir + "\\pyzo\\resources\\translations", "pyzo\\resources\\translations"),
(root_dir + "\\pyzo\\contributors.txt", "pyzo"),
(root_dir + "\\pyzo\\license.txt", "pyzo")],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='pyzo',
debug=False,
bootloader_ignore_signals=False,
strip=True,
upx=True,
console=True,
icon="C:\\Users\\61980\\Desktop\\pyzo\\pyzo\\resources\\appicons\\pyzologo.ico")
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='pyzo')
04、使用pyinstaller命令打包文件
pyinstaller pyzo.spec
05、将项目代码放到打包目录中
注: 去掉导入器,只使用"import pyzo"及pyzo.py文件中的启动方法就可以将源码隐藏, 使用导入器相当于将项目环境打包, 配合源码可以在其他机器上进行调试
import sys, os
class SourceImporter:
"""导入器定义"""
def __init__(self, dir):
self.module_names = {"pyzo"}
for name in os.listdir(dir):
self.module_names.add(name)
def find_spec(self, fullname, path, target=None):
if fullname.split(".")[0] in self.module_names:
li = [i for i in sys.meta_path if i.__class__.__name__ == "type"]
return li[2].find_spec(fullname, path, target)
else:
return None
if getattr(sys, "frozen", False):
source_dir= os.path.join(sys._MEIPASS, 'source')
sys.path.insert(0, source_dir)
sys.meta_path.insert(0, SourceImporter(source_dir))
else:
# Try importing
try:
import pyzo
except ImportError:
thisDir = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.split(thisDir)[0])
try:
import pyzo
except ImportError:
raise ImportError('Could not import Pyzo in either way.')
01:冻结路径(固定项目导包路径)
在pyinstaller导包的程序运行时会设置: sys.freeze 、sys._MEIPASS
sys.freeze : 设置为True
sys._MEIPASS:保存项目代码所在绝对路径,项目代码一般放在打包目录中,
放在打包目录的那个路径下可以自己设置。 打包目录存放在 ./dist 目录下
02:冻结路径方式
pyzo项目中冻结路路径的方式:通过在启动文件中执行这段代码, 不论是打包后还是不打包, 都导入pyzo包, pyzo包就是整个项目的根目录,
这相当于将项目所在目录加入了环境变量,然后项目中导包都根据这个路径来做。
pzyo项目打包前的导包路径: 'C:\\Users\\61980\\Desktop\\pyzo'
pyzo项目打包后的导包路径:'C:\\Users\\61980\\Desktop\\pyzo\\dist\\pyzo\\source'
1、将pyzo项目文件夹放到 ./dist/pyzo/source 目录下
因为pyzo有这个设置, 所以spec文件的Analysis中binaries、datas保持为空即可
6、调试方法
在编写spec是将spec文件中的debug、console设置为True, 然后运行生成的可执行文件可以看到详细运行信息, 有错误方便查找
7、bug
Failed to execute script xxxx
原因: pyinstaller、python、系统、摸个模块版本不匹配。
项目或编写spec文件是路径不对, 具体原因可以通过调试去分析。
NameError: name “‘defaultParams’” is not defined
安装:pip install matplotlib==3.0.3
参考:
https://yujunjiex.gitee.io/2018/10/18/PyInstaller%E6%89%93%E5%8C%85%E8%AF%A6%E8%A7%A3/
https://blog.csdn.net/weixin_42052836/article/details/82315118#Pyinstaller%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95
https://blog.csdn.net/u014563989/article/details/80940321
练习项目pyzo
pyinstaller打包生成可执行exe练习:http://download.csdn.net/download/YPFeime/12606553