说明
在使用pyinstaller打包py文件时候,竟然会有一个需求是要求在允许exe的时候不带控制台,这并不是一个很难的操作,但是往往在打包之后,允许exe时会弹出Failed to execute script xxx.exe的报错信息,折腾了一下午,终于搞明白了原因以及解决方法.
预备知识
-
根据打包时输入的参数的不同,可以进行不同类型的打包,首先需要大致了解一下几个常用的参数,或许有助于对解决方法的理解:
-
-D Create a one-file bundled executable(创建一个包含可执行文件的单文件夹包,换句话说,就是打包出来的程序,会是一个文件夹,里面包含了许多的依赖文件等等,和一个exe可执行文件,就像windows的许多软件一样的形式。).
-
-F Create a one-file bundled executable(创建一个单文件绑定的可执行文件,换句话说,就是只会打包出一个exe可执行文件,没有多余的文件。).
-
w Windows and Mac OS X: do not provide a console window
for standard i/o. On Mac OS X this also triggers
building an OS X .app bundle. On Windows this option
will be set if the first script is a ‘.pyw’ file. This
option is ignored in NIX systems(Windows和Mac OSX:不提供控制台窗口标准i / o。在Mac OS X上也会触发构建一个OS X .app包。在Windows上这个选项。如果第一个脚本是’,则设置。pyw”文件。这选项在NIX系统中被忽略。简而言之,在windows上运行时不显示cmd窗口。).
简单示例
- 最简单的打包
# 这是最简单的打包
pyinstaller main.py
- 使用参数-D
"""
加上-D的打包可以理解为是打包的第一种方式,和上面是一样的效果,因为-D是属于默认的。
此时打包完成后,在main.py的路径下会又一个dist文件夹,dist文件夹下是一个main文件夹,
再往里面打开,就会像我们大多数windows软件一样,有一个目录专门放
一堆运行时所需要的依赖文件等等,但一定有一个main.exe文件用于运行。
"""
pyinstaller -D main.py
- 使用参数-F
"""
加上-F可以理解是打包的第二种方式,与-D不能同时使用。
打包完成后,在main.py路径下同样会有一个dist文件夹,但不同的是,
dist文件夹下只有一个main.exe的可运行文件。
"""
pyinstaller -F main.py
- 使用参数-w
"""
无论是使用-F 还是 -D参数,打包出来的exe文件在运行的时候都会自动打开一个cmd窗口,
如果我们想让他关闭而不影响程序运行的话,需要在打包时再加上-w参数。
无论是-F 还是-D都支持和-w参数配合使用,以此来关闭运行时打开的cmd窗口。
"""
pyinstaller -F -w main.py
# 或者
pyinstaller -D -w main.py
打包的生成的文件.spec文件
- 当我们每次打包的时候,除了生成的dist、build、__pycache__三个文件夹外,还有一份后缀为.spec的文件。通过pycharm(或者其他IDE)打开后内容如下:
无需过多关注这份代码,需要用到的下面会提到,并且我们可能有所差异
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['main.py'],
pathex=['C:\\Users\\HYT\\Desktop\\shili'],
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,
a.binaries,
a.zipfiles,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True )
- 关于这份代码,我们需要知道的是,将console的值即代表着运行时是否打开cmd窗口。
- 而hiddenimports可以帮助我们解决许多报错信息。
- 并且我们可以通过修改.spec文件,然后进行二次打包,速度相对快得多,格式如下:
"""
注意不在是main.py,而是main.spec。
比如将原本的console=True改为console=False再进行打包,
就不会显示cmd窗口了
"""
pyinstaller -D -w main.spec
打包的常见误区
- 打包完成,并不意味着打包成功,这就是为什么有时候生成的exe文件无法运行,仔细观察打包过程的日志信息,往往会有一些报错信息藏在里头,通过这些报错信息,可以很高效的在网上搜索到解决方法。
- 需要打包一个不带命令行窗口的exe时,不要直接一上来就加上-w参数,因为这样可能导致查看不了报错信息,因此无法解决问题。当我们执行带cmd窗口的exe时,即使报错了,也可以在cmd窗口看到报错信息,根据报错信息找到对应的解决方法,然后再进行二次打包,并加上-w参数,就可以完美的打包出一个可以运行的无cmd窗口的exe文件了。
解决方法
- 当发现打包完成后的exe无法运行,报出Failed to execute script xxx.exe时,可以去除-w参数重新进行打包。再次运行后可以捕捉到报错信息。
- 常见的报错信息如下:
No such file or directory:
'C:\\Users\\HYT\\AppData\\Local\\Temp\\_MExx\\xx\xx错误
- 关于这个错误,一个可行的解决方法是替换pyinstaller下的hooks文件,以及添加一些缺失的module到.spec文件下的hiddenimports中,然后对该.spec文件进行二次打包。
详细的修改方法可以查看大佬的博客。点击这里
一个可行的打包流程
- 1.首先不带-w参数打包一份可以显示cmd窗口的exe,进行运行测试。
- 2.注意cmd窗口的日志信息,如果出现报错信息,根据上面的解决方法修改.spec文件的内容以及hooks-xx.py文件。
- 3.确认程序无误后修改.spec文件的console为False,重新对该.spec文件进行二次打包。
-F -D 打包出来的区别
- -F打包处理的exe占用的空间通常会比-D打包出来的exe大得多,启动速度上也会快得多,但是只有一个exe,没有多余的文件,使用起来相对也比较方便。