pyinstaller打包pyqt5,从入坑到填坑,详解
以上省略pyinstaller安装步骤,直入主题。先分享我的心路历程。
1.pyinstaller -F -i 1.ico UI_Main.py (先在CMD中 cd到 py文件对应的路径)
第一步打包成功,打开EXE,界面正常显示,但是连不上项目的IC板。故看到打包时的warning,怀疑是受此影响,几经辗转查阅,发现所缺的dll都是QT的dll,这里的QT指的是C++版的QT,于是我专程去官网下载安装了一个QT。
于是将所缺的dll如数转移到我的 UI_Main.py的同一根目录下:
2. 再次 pyinstaller -F -i 1.ico UI_Main.py
此时 warning: lib not found 已无,打包完成,再次打开EXE,本人的UI还是无法连结到IC板,而在pycharm工程程序中却是完美运行。这验证说明这些Qt53xx文件是无害的。
3.查阅论坛,很多文章说到pyinstaller 打包时,导入路径的问题,我整理了些许方法,并进行了验证:
(1).主函数 import xx 导入模块,可免去其他形式导入【这里解决:pyinstaller打包后,打开报错:not find xx module】
(2).pyinstaller -F -i 1.ico UI_Main.py 后加 -p 路径/文件【主要解决:import 引发的路径查找不到的问题】
(3).UI_Main.spec文件中 pathex=[],binaries=[],datas=[] 分别添加需要额外添加的导入路径,额外添加的二进制文件,额外添加的数据文件。注意,spec文件搭配的CMD指令是 pyinstaller –clean -F UI_Main.spec -i 1.ico,–cean是清除pyinstaller 缓存文件,如何后接UI_Main.py则会使 spec文件被刷新
(4).CMD: pyinstaller -F -i 1.ico UI_Main.py –add-datas=xxx.dll;. 【其实与(3)中添加datas=[]是一样的效果】
(5).主函数添加相应的路径 sys.path.append() 【其实也是和(1)差不多,能添加打包的搜索路径。】
以下是 spec文件的全内容,datas=[]中的”.”表示将该文件复制到根路径(UI_Main.py同),并从根路径搜索,添加到打包内容。
# -*- mode: python ; coding: utf-8 -*- block_cipher = None a = Analysis(['UI_Main.py'], pathex=['D:\\PyQt\\module\\AxpSys_DEBUG\\axp\\drivers', 'C:\\Python36\\Lib', 'D:\\PyQt'], binaries=[], datas=[('xxx1.dll', "."), ('xxx2.dll', "."), ('xxx3.csv', ".")], 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='UI_Main', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=False , icon='1.ico')
4.我将这4种方法都试过,确实能解决相应问题,应该也能解决普遍问题。
但仍未能解决我的UI不能连结IC板卡的问题。于是我思考一下,想到windows连结IC卡时,我是有安装过基于通讯的驱动,那怀疑坚定加肯定一定是,驱动部分的相关文件没有被打包进去。于是,我独立写了一个简单demo,对IC进行通讯的实验,并进行了每一个步骤的print侦测。惊奇的发现成功了!
这里demo已经连上了IC板卡(也就是单片机啦啦啦),然后我葫芦画瓢,在UI_Main.py上造车,一样的轮子,竟然还是不行!
我努力对照spec 文件发现一模一样,也是根据 pyinstaller –clean -F UI_Main.spec -i 1.ico 相同的指令。我仔细反复查找,终于找到了两者唯一的不同!!!二者唯一不用的是 spec文件中 xxx1.dll 与 xxx2.dll的顺序是相反的【也就是一个1,2,3;另一个2,1,3】,我怀揣着忐忑试探着最后那一丝不似希望的希望。
最后终于成功了!!!原理驱动装载的顺序也是影响最后IC读写的,我猜测是因为xxx2.dll 中有调用到 xxx1.dll的函数,但是因为我放的顺序是datas=[(‘xxx2.dll’, ‘.’), (‘xxx1.dll’,’.’), (‘xxx3.csv’,’.’)] 导致系统pyinstaller 先导入的xxx2.dll 因为引用不到 xxx1.dll中的函数,而在打包的时候直接报错,当我把顺序调整之后,才能完美运行!
总结,关于程序需要额外加载的dll 文件【比如:上文提到的Qt53xx.dll此类与程序相关的,皆为内部导入,非额外】,额外具体指的是,在python 程序中使用到的WinDLL等,相关windows驱动时,可视为额外加载dll。
impor ctypes ctypes.WinDLL('xxx1.dll') ctypes.CDLL(path,'xxx2.dll')
故,我这里因为是和单片机通讯,需要加载额外dll,所以会遇到这个问题,希望和我遇到类似问题与坑的同鞋们看到这篇文章与有此受益,感谢阅读,请不要怜惜自己给我点个赞吧。
欢迎评论交流 pyinstaller 等的相关问题。
补充一点:我的验证demo是在虚拟环境pipenv中验证的,其实pyinstaller网上的文章大部分是可以借鉴的,只是指令不同而使用时有所误导而已。