# -*- mode: python ; coding: utf-8 -*- """ PyInstaller spec for SSHClient 在 Windows 上构建: pip install -r requirements.txt pyinstaller build.spec --clean --noconfirm 产物: dist/SSHClient.exe (单文件, ~50MB) """ import sys from pathlib import Path block_cipher = None # 项目根 ROOT = Path(SPECPATH).resolve() if 'SPECPATH' in dir() else Path('.').resolve() # 隐式导入(PyQt5 + paramiko 有动态导入,PyInstaller 偶尔抓不全) hiddenimports = [ "paramiko", "cryptography", "requests", "psutil", # PyQt5 子模块 "PyQt5.QtCore", "PyQt5.QtGui", "PyQt5.QtWidgets", ] a = Analysis( ['main.py'], pathex=[str(ROOT)], binaries=[], datas=[ ('resources/icon.png', 'resources'), ('resources/icon.ico', 'resources'), ], hiddenimports=hiddenimports, hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[ # 砍掉体积 "tkinter", "matplotlib", "numpy", "pandas", "scipy", "PyQt5.QtBluetooth", "PyQt5.QtDBus", "PyQt5.QtDesigner", "PyQt5.QtHelp", "PyQt5.QtLocation", "PyQt5.QtMultimedia", "PyQt5.QtMultimediaWidgets", "PyQt5.QtNetwork", "PyQt5.QtNetworkAuth", "PyQt5.QtNfc", "PyQt5.QtOpenGL", "PyQt5.QtPositioning", "PyQt5.QtPrintSupport", "PyQt5.QtQml", "PyQt5.QtQuick", "PyQt5.QtQuickWidgets", "PyQt5.QtRemoteObjects", "PyQt5.QtSensors", "PyQt5.QtSerialPort", "PyQt5.QtSql", "PyQt5.QtSvg", "PyQt5.QtTest", "PyQt5.QtWebChannel", "PyQt5.QtWebSockets", "PyQt5.QtXml", "PyQt5.QtXmlPatterns", ], 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(启动稍慢但分发简单);如需启动更快可改成 COLLECT + EXE exe = EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='SSHClient', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, # 如果装了 UPX 会进一步压缩 upx_exclude=[], runtime_tmpdir=None, console=False, # GUI 模式不弹黑窗 disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, icon='resources/icon.ico' if Path('resources/icon.ico').exists() else None, )