329 lines
7.3 KiB
Python
329 lines
7.3 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
PyInstaller 打包配置生成器
|
|
|
|
使用方法:
|
|
1. 将此文件复制到后台工程根目录
|
|
2. 运行: python build_spec_example.py
|
|
3. 会生成三个 .spec 文件:
|
|
- build_backend.spec : 打包后台服务
|
|
- build_frontend.spec : 打包 GUI 前端
|
|
- build_all.spec : 统一打包
|
|
|
|
4. 执行打包:
|
|
pyinstaller build_backend.spec
|
|
pyinstaller build_frontend.spec
|
|
或
|
|
pyinstaller build_all.spec
|
|
"""
|
|
|
|
import os
|
|
|
|
|
|
# ============== 后台服务打包配置 ==============
|
|
BACKEND_SPEC = """# -*- mode: python ; coding: utf-8 -*-
|
|
# DTM 后台服务打包配置
|
|
|
|
block_cipher = None
|
|
|
|
a = Analysis(
|
|
['main.py'],
|
|
pathex=[],
|
|
binaries=[],
|
|
datas=[
|
|
('backend', 'backend'),
|
|
('config', 'config'),
|
|
# 添加其他需要的资源文件
|
|
],
|
|
hiddenimports=[
|
|
'flask',
|
|
'flask_socketio',
|
|
'flask_cors',
|
|
'sqlite3',
|
|
'requests',
|
|
],
|
|
hookspath=[],
|
|
hooksconfig={},
|
|
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='dtm_backend',
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
upx=True,
|
|
console=True, # 显示控制台,便于查看日志
|
|
disable_windowed_traceback=False,
|
|
argv_emulation=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='dtm_backend',
|
|
)
|
|
"""
|
|
|
|
|
|
# ============== GUI 前端打包配置 ==============
|
|
FRONTEND_SPEC = """# -*- mode: python ; coding: utf-8 -*-
|
|
# DTM GUI 前端打包配置
|
|
|
|
block_cipher = None
|
|
|
|
a = Analysis(
|
|
['frontend_gui/dtmgtUI.py'],
|
|
pathex=[],
|
|
binaries=[],
|
|
datas=[
|
|
('frontend_gui/styles', 'styles'),
|
|
('frontend_gui/qml', 'qml'),
|
|
# 如果有图标、图片等资源,也添加进来
|
|
# ('frontend_gui/resources', 'resources'),
|
|
],
|
|
hiddenimports=[
|
|
'PyQt5',
|
|
'PyQt5.QtCore',
|
|
'PyQt5.QtGui',
|
|
'PyQt5.QtWidgets',
|
|
'PyQt5.QtWebEngineWidgets',
|
|
'PyQt5.QtQml',
|
|
'requests',
|
|
'websocket',
|
|
],
|
|
hookspath=[],
|
|
hooksconfig={},
|
|
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='dtm_gui',
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
upx=True,
|
|
console=False, # GUI 程序不显示控制台
|
|
disable_windowed_traceback=False,
|
|
argv_emulation=False,
|
|
target_arch=None,
|
|
codesign_identity=None,
|
|
entitlements_file=None,
|
|
icon='frontend_gui/icon.ico', # 如果有图标文件
|
|
)
|
|
|
|
coll = COLLECT(
|
|
exe,
|
|
a.binaries,
|
|
a.zipfiles,
|
|
a.datas,
|
|
strip=False,
|
|
upx=True,
|
|
upx_exclude=[],
|
|
name='dtm_gui',
|
|
)
|
|
"""
|
|
|
|
|
|
# ============== 统一打包配置 ==============
|
|
ALL_SPEC = """# -*- mode: python ; coding: utf-8 -*-
|
|
# DTM 完整系统打包配置(后台 + 前端)
|
|
|
|
block_cipher = None
|
|
|
|
# ========== 后台服务分析 ==========
|
|
backend_a = Analysis(
|
|
['main.py'],
|
|
pathex=[],
|
|
binaries=[],
|
|
datas=[
|
|
('backend', 'backend'),
|
|
('config', 'config'),
|
|
],
|
|
hiddenimports=[
|
|
'flask',
|
|
'flask_socketio',
|
|
'flask_cors',
|
|
'sqlite3',
|
|
'requests',
|
|
],
|
|
hookspath=[],
|
|
hooksconfig={},
|
|
runtime_hooks=[],
|
|
excludes=[],
|
|
win_no_prefer_redirects=False,
|
|
win_private_assemblies=False,
|
|
cipher=block_cipher,
|
|
noarchive=False,
|
|
)
|
|
|
|
# ========== GUI 前端分析 ==========
|
|
frontend_a = Analysis(
|
|
['frontend_gui/dtmgtUI.py'],
|
|
pathex=[],
|
|
binaries=[],
|
|
datas=[
|
|
('frontend_gui/styles', 'frontend_gui/styles'),
|
|
('frontend_gui/qml', 'frontend_gui/qml'),
|
|
],
|
|
hiddenimports=[
|
|
'PyQt5',
|
|
'PyQt5.QtCore',
|
|
'PyQt5.QtGui',
|
|
'PyQt5.QtWidgets',
|
|
'PyQt5.QtWebEngineWidgets',
|
|
'PyQt5.QtQml',
|
|
'requests',
|
|
'websocket',
|
|
],
|
|
hookspath=[],
|
|
hooksconfig={},
|
|
runtime_hooks=[],
|
|
excludes=[],
|
|
win_no_prefer_redirects=False,
|
|
win_private_assemblies=False,
|
|
cipher=block_cipher,
|
|
noarchive=False,
|
|
)
|
|
|
|
# ========== 合并分析结果 ==========
|
|
MERGE((backend_a, 'backend', 'backend'), (frontend_a, 'frontend', 'frontend'))
|
|
|
|
# ========== 后台 EXE ==========
|
|
backend_pyz = PYZ(backend_a.pure, backend_a.zipped_data, cipher=block_cipher)
|
|
|
|
backend_exe = EXE(
|
|
backend_pyz,
|
|
backend_a.scripts,
|
|
[],
|
|
exclude_binaries=True,
|
|
name='dtm_backend',
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
upx=True,
|
|
console=True,
|
|
disable_windowed_traceback=False,
|
|
argv_emulation=False,
|
|
target_arch=None,
|
|
codesign_identity=None,
|
|
entitlements_file=None,
|
|
)
|
|
|
|
# ========== 前端 EXE ==========
|
|
frontend_pyz = PYZ(frontend_a.pure, frontend_a.zipped_data, cipher=block_cipher)
|
|
|
|
frontend_exe = EXE(
|
|
frontend_pyz,
|
|
frontend_a.scripts,
|
|
[],
|
|
exclude_binaries=True,
|
|
name='dtm_gui',
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
upx=True,
|
|
console=False,
|
|
disable_windowed_traceback=False,
|
|
argv_emulation=False,
|
|
target_arch=None,
|
|
codesign_identity=None,
|
|
entitlements_file=None,
|
|
icon='frontend_gui/icon.ico',
|
|
)
|
|
|
|
# ========== 收集所有文件 ==========
|
|
coll = COLLECT(
|
|
backend_exe,
|
|
backend_a.binaries,
|
|
backend_a.datas,
|
|
frontend_exe,
|
|
frontend_a.binaries,
|
|
frontend_a.datas,
|
|
strip=False,
|
|
upx=True,
|
|
upx_exclude=[],
|
|
name='DTM_System',
|
|
)
|
|
"""
|
|
|
|
|
|
def generate_specs():
|
|
"""生成打包配置文件"""
|
|
specs = {
|
|
'build_backend.spec': BACKEND_SPEC,
|
|
'build_frontend.spec': FRONTEND_SPEC,
|
|
'build_all.spec': ALL_SPEC,
|
|
}
|
|
|
|
print("=== PyInstaller 配置生成器 ===\n")
|
|
|
|
for filename, content in specs.items():
|
|
filepath = os.path.join(os.getcwd(), filename)
|
|
|
|
# 检查文件是否存在
|
|
if os.path.exists(filepath):
|
|
response = input(f"文件 {filename} 已存在,是否覆盖?(y/N): ")
|
|
if response.lower() != 'y':
|
|
print(f" 跳过 {filename}")
|
|
continue
|
|
|
|
# 写入文件
|
|
with open(filepath, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
|
|
print(f"✓ 已生成: {filename}")
|
|
|
|
print("\n=== 使用说明 ===")
|
|
print("1. 打包后台服务:")
|
|
print(" pyinstaller build_backend.spec")
|
|
print()
|
|
print("2. 打包 GUI 前端:")
|
|
print(" pyinstaller build_frontend.spec")
|
|
print()
|
|
print("3. 统一打包(后台+前端):")
|
|
print(" pyinstaller build_all.spec")
|
|
print()
|
|
print("4. 打包产物位于 dist/ 目录")
|
|
print()
|
|
print("注意事项:")
|
|
print("- 确保已安装 PyInstaller: pip install pyinstaller")
|
|
print("- 根据实际项目结构调整 .spec 文件中的路径和依赖")
|
|
print("- 打包前建议在虚拟环境中测试")
|
|
print()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
generate_specs()
|