Files

131 lines
5.0 KiB
RPMSpec
Raw Permalink Normal View History

2026-09-22 16:08:12 +08:00
# -*- mode: python ; coding: utf-8 -*-
"""PyInstaller 打包配置。
由 ``packaging/build_pyinstaller.py`` 调用 —— 选项通过**环境变量**传进来
(spec 文件本身不接受命令行参数,这是 PyInstaller 的既定用法):
=========================== ==========================================
环境变量 作用
=========================== ==========================================
``CLG_NAME`` 产物名(默认 chongming-license-gui)
``CLG_ONEFILE`` ``1`` = 单文件(默认),``0`` = 目录模式
``CLG_CONSOLE`` ``1`` = 带控制台窗口(排查启动问题用)
``CLG_ICON`` .ico 路径(由 ``_common.build_app_icon()`` 生成)
=========================== ==========================================
"""
import os
from pathlib import Path
ROOT = Path(SPECPATH).resolve().parent # noqa: F821 - SPECPATH 由 PyInstaller 注入
NAME = os.environ.get("CLG_NAME", "chongming-license-gui")
ONEFILE = os.environ.get("CLG_ONEFILE", "1") == "1"
CONSOLE = os.environ.get("CLG_CONSOLE", "0") == "1"
ICON = os.environ.get("CLG_ICON") or None
# PySide6 装了整套 Addons(Qt3D / WebEngine / Charts…),本工具一个都不用。
# PyInstaller 的 PySide6 hook 只打包"被 import 到的" Qt 模块,但显式排除能兜住
# 间接依赖,避免几百 MB 的模块被拖进来。
# 注:排除不存在的模块是安全的(PyInstaller 只按名字匹配)。
EXCLUDES = [
# 3D / 图形 / 可视化
"PySide6.Qt3DAnimation", "PySide6.Qt3DCore", "PySide6.Qt3DExtras",
"PySide6.Qt3DInput", "PySide6.Qt3DLogic", "PySide6.Qt3DRender",
"PySide6.QtCharts", "PySide6.QtDataVisualization", "PySide6.QtGraphs",
"PySide6.QtGraphsWidgets", "PySide6.QtCanvasPainter",
# Web / QML / Quick(体积最大的一批)
"PySide6.QtWebEngineCore", "PySide6.QtWebEngineWidgets",
"PySide6.QtWebEngineQuick", "PySide6.QtWebView", "PySide6.QtWebChannel",
"PySide6.QtWebSockets", "PySide6.QtHttpServer",
"PySide6.QtQml", "PySide6.QtQuick", "PySide6.QtQuick3D",
"PySide6.QtQuickControls2", "PySide6.QtQuickWidgets", "PySide6.QtQuickTest",
# 多媒体 / 设备 / 传感器
"PySide6.QtMultimedia", "PySide6.QtMultimediaWidgets", "PySide6.QtSpatialAudio",
"PySide6.QtTextToSpeech", "PySide6.QtBluetooth", "PySide6.QtNfc",
"PySide6.QtPositioning", "PySide6.QtLocation", "PySide6.QtSensors",
"PySide6.QtSerialPort", "PySide6.QtSerialBus", "PySide6.QtRemoteObjects",
"PySide6.QtScxml", "PySide6.QtStateMachine", "PySide6.QtAxContainer",
# 文档 / 设计器 / 测试 / 数据库 / 容器
"PySide6.QtPdf", "PySide6.QtPdfWidgets", "PySide6.QtDesigner",
"PySide6.QtUiTools", "PySide6.QtHelp", "PySide6.QtTest",
"PySide6.QtSql", "PySide6.QtDBus", "PySide6.QtConcurrent",
"PySide6.QtNetworkAuth", "PySide6.QtXml", "PySide6.QtSvgWidgets",
"PySide6.QtOpenGL", "PySide6.QtOpenGLWidgets",
# 与本工具无关的标准库大件
"tkinter", "pydoc_data",
]
a = Analysis( # noqa: F821
[str(ROOT / "packaging" / "launcher.py")],
# 用源码树解析本包,而不是依赖 editable 安装(冻结工具对 .pth 式
# editable 安装的解析并不可靠)
pathex=[str(ROOT / "src")],
binaries=[],
datas=[], # 无数据文件:图标与样式表都是运行时生成的
# PySide6.QtSvg 是显式 import,正常能被扫到;这里再钉一遍 —— 少了它
# 图标会全部变空白,而且不报错
hiddenimports=["PySide6.QtSvg"],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=EXCLUDES,
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure) # noqa: F821
if ONEFILE:
# 单文件:自解压到临时目录再运行(分发最省事,首次启动稍慢)
exe = EXE( # noqa: F821
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name=NAME,
debug=False,
bootloader_ignore_signals=False,
strip=False,
# UPX 压缩容易触发杀软误报,也会损坏部分 Qt DLL,明确关掉
upx=False,
upx_exclude=[],
runtime_tmpdir=None,
console=CONSOLE,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=ICON,
)
else:
# 目录模式:启动更快,适合放在固定办公机上长期使用
exe = EXE( # noqa: F821
pyz,
a.scripts,
[],
exclude_binaries=True,
name=NAME,
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
console=CONSOLE,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=ICON,
)
coll = COLLECT( # noqa: F821
exe,
a.binaries,
a.datas,
strip=False,
upx=False,
upx_exclude=[],
name=NAME,
)