#!/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()