本文分为一系列步骤,使用PyInstaller将简单或复杂的 PyQt5 应用程序构建成 Windows 上的可分发 EXE 文件。
这里主要是记录将exe和dll等资源文件分离的打包形式。(把所有程序只打包成一个exe文件不做说明)
本文同样适用PySide2
建议在虚拟环境中安装,比如 conda 或者 virtualenv 或者你的应用程序虚拟环境,虚拟环境中只安装程序用到的包,以保持环境清洁。
pip3 install PyInstaller
这里我使用一个DEMO来演示打包过程,DEMO中包含窗口程序、图标等资源。其中图标你可当做是你程序中引用的外部资源,比如图片、文本、本地数据库、第三方dll等资源,他们的操作都是类似的,自己举一反三!
关于引用外部资源打包后失效,需要注意的是路径:
base_dir = os.path.dirname(__file__)
用来获取程序的路径,在引用外部资源时拼接上该路径,就能保证不管程序移动到任何文件夹下,都能正常运行!!!!!
import sys, os
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QVBoxLayout, QLabel, QPushButton, QWidget
base_dir = os.path.dirname(__file__)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Hello World")
layout = QVBoxLayout()
label = QLabel("My simple app.")
label.setMargin(10)
layout.addWidget(label)
button = QPushButton("Push")
button.setIcon(QtGui.QIcon(os.path.join(base_dir, "icons", "lightning.png")))
button.pressed.connect(self.close)
layout.addWidget(button)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
self.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon(os.path.join(base_dir, 'icons', 'hand.ico')))
w = MainWindow()
app.exec()
.spec文件包含PyInstaller用于打包应用程序的构建配置和说明,每个PyInstaller项目都有一个.spec文件。
这里只介绍常用的,配置后打包没问题的,其他的参数自己去查资料
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['app.py'], # 主程序入口
pathex=[],
binaries=[],
datas=[ # 外部资源路径,看下面单独介绍
('icons', 'icons'),
('path1', 'path2')
],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=['matplotlib', '...'], # 不需要打包的库,比如:'matplotlib'
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='Hunzi666', # 设置打包后的软件名字,最终打包后的软件名就叫 Hunzi666.exe
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False, # 关闭打包后的程序运行时的弹出的控制台
icon='icons\\hand.ico' # 图标文件
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='app')
.spec
如果在 Windows 上生成文件,则路径分隔符将为\\
。要在 macOS 上使用相同.spec
的文件,需要将分隔符切换为/
。 值得庆幸的是/
也适用于 Windows。
a = Analysis(datas=[('icons', 'icons'),
('path1', 'path2')])
括号里面的两个参数,第一个:打包前的资源文件夹
路径,第二个:打包后的资源文件夹
路径
作用就是把原来
path1
文件夹下面的所有内容拷贝到path2
文件夹中,(其中path1和path2名称要相同)
就比如demo程序中的icons
文件夹。打包完程序之后,打包后的程序目录下肯定也要有一个icons
文件夹,且引用的路径,里面的文件要和原来的一模一样。
你可以试试,如果你不配置这个参数,看看打包后的结果。在这基础上,你手动把这些文件夹复制到打包目录里面,再看看结果,你就知道有什么用了。
你会发现通过配置参数 和 你手动复制的效果是一样的,所以你可以把你引用的第三方的所有资源,都通过这种方式复制到打包目录里面!
写好.spec
文件后,可以运行它来打包程序。
pyinstaller app.spec
你将会看到,可以忽略。。。
U:\home\martin\helloworld>pyinstaller app.py
INFO: PyInstaller: 3.6
INFO: Python: 3.7.6
INFO: Platform: Windows-10-10.0.18362-SP0
...
...
...
INFO: Building EXE from EXE-00.toc completed successfully.
INFO: checking COLLECT
INFO: Building COLLECT because COLLECT-00.toc is non existent
INFO: Building COLLECT COLLECT-00.toc
INFO: Building COLLECT COLLECT-00.toc completed successfully.
你可以在程序的目录下,看到两个文件夹分别是dist
和build
。
build
文件夹来收集和准备打包文件,它包含分析结果和一些附加日志。在大多数情况下,可以忽略此文件夹的内容,除非尝试调试问题。dist
文件夹包含要分发的文件。这包括捆绑为可执行文件的应用程序,以及任何关联的库(例如 PyQt5)和二进制.dll文件。运行应用程序所需的一切都将在此文件夹中,这意味着可以使用此文件夹并将其“分发”给其他人以运行你的应用程序。现在你可以在dist
文件夹中运行Hunzi666.exe
,你就会看到你熟悉的窗口:
打包成功!
待补充、、、
待补充、、、
待补充、、、