chore: replace app icon uitubiao.ico -> app.ico (converted from app.png)
This commit is contained in:
BIN
data/icons-1/app.ico
Normal file
BIN
data/icons-1/app.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
@ -336,7 +336,7 @@ class WaterQualityGUI(QMainWindow):
|
||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(my_appid)
|
||||
super().__init__()
|
||||
|
||||
icon_path = get_resource_path("data/icons-1/uitubiao.ico")
|
||||
icon_path = get_resource_path("data/icons-1/app.ico")
|
||||
self.setWindowIcon(QIcon(icon_path))
|
||||
|
||||
# 第一步:创建各 Manager(纯连线,不执行业务)
|
||||
|
||||
225
water_quality_app.spec
Normal file
225
water_quality_app.spec
Normal file
@ -0,0 +1,225 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ==============================================================================
|
||||
# 水质参数反演分析系统 - 终极纯净版 PyInstaller Spec 配置文件
|
||||
# 彻底斩断 venv 交叉污染,强制 Conda 原生环境全量解析
|
||||
# 用法: pyinstaller --clean water_quality_app.spec
|
||||
# ==============================================================================
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
import shutil
|
||||
|
||||
block_cipher = None
|
||||
|
||||
# ==============================================================================
|
||||
# 0. 基础路径配置 (❌ 彻底移除了 VENV_SITE 变量,拒绝交叉环境污染!)
|
||||
# ==============================================================================
|
||||
PROJECT_ROOT = os.path.abspath(os.getcwd())
|
||||
SRC_DIR = os.path.join(PROJECT_ROOT, "src")
|
||||
BUILD_DIR = os.path.join(PROJECT_ROOT, "build")
|
||||
DIST_DIR = os.path.join(PROJECT_ROOT, "dist")
|
||||
|
||||
# Conda WQ_GUI 环境 DLL 路径(MSVC 运行时 + GIS 核心库原生纯净副本)
|
||||
CONDA_ENV_DLLS = r"D:\111\changyongruanjian\anconda\envs\WQ_GUI"
|
||||
CONDA_OSGEO_DLLS = os.path.join(CONDA_ENV_DLLS, "Lib", "site-packages", "osgeo")
|
||||
|
||||
# ==============================================================================
|
||||
# 1. 静态资源与数据文件收集 (datas)
|
||||
# ==============================================================================
|
||||
def get_data_files():
|
||||
datas = []
|
||||
|
||||
# 1-1. 根目录核心配置文件 (包含内置公式 CSV)
|
||||
single_files = [
|
||||
"waterindex.csv",
|
||||
"requirements.txt",
|
||||
"README.md",
|
||||
"软件说明.md",
|
||||
]
|
||||
for f in single_files:
|
||||
if os.path.exists(os.path.join(PROJECT_ROOT, f)):
|
||||
datas.append((os.path.join(PROJECT_ROOT, f), "."))
|
||||
|
||||
# 1-2. data/ 目录(全量递归映射,确保代码通过 get_resource_path 能读到任务栏图标)
|
||||
data_dir = os.path.join(PROJECT_ROOT, "data")
|
||||
if os.path.isdir(data_dir):
|
||||
datas.append((data_dir, "data"))
|
||||
|
||||
# 1-3. src/gui/model/ 模型参数文件
|
||||
model_dir = os.path.join(SRC_DIR, "gui", "model")
|
||||
if os.path.isdir(model_dir):
|
||||
datas.append((model_dir, "src/gui/model"))
|
||||
|
||||
# 1-4. src/auth/ 离线授权验证模块
|
||||
auth_dir = os.path.join(SRC_DIR, "auth")
|
||||
if os.path.isdir(auth_dir):
|
||||
datas.append((auth_dir, "src/auth"))
|
||||
|
||||
# 1-5. 运行时环境变量与 DLL 挂载钩子
|
||||
rthook_script = os.path.join(PROJECT_ROOT, "scripts", "rthook_add_dll_dirs.py")
|
||||
if os.path.exists(rthook_script):
|
||||
datas.append((rthook_script, "scripts"))
|
||||
|
||||
return datas
|
||||
|
||||
datas = get_data_files()
|
||||
|
||||
# ==============================================================================
|
||||
# 2. 核心二进制文件搜集 (binaries) - 强制抓取纯净运行库防静默崩溃
|
||||
# ==============================================================================
|
||||
def get_binaries():
|
||||
binaries = []
|
||||
|
||||
# 2-1. 精准提取 Conda 环境下与编译完全匹配的 MSVC 运行库
|
||||
if os.path.isdir(CONDA_ENV_DLLS):
|
||||
for dll_name in [
|
||||
"msvcp140.dll",
|
||||
"msvcp140_1.dll",
|
||||
"msvcp140_2.dll",
|
||||
"msvcp140_atomic_wait.dll",
|
||||
"msvcp140_codecvt_ids.dll",
|
||||
"vcruntime140.dll",
|
||||
"vcruntime140_1.dll",
|
||||
"vcruntime140_threads.dll",
|
||||
"concrt140.dll",
|
||||
"vcomp140.dll",
|
||||
"vcamp140.dll",
|
||||
"vccorlib140.dll",
|
||||
]:
|
||||
dll_path = os.path.join(CONDA_ENV_DLLS, dll_name)
|
||||
if os.path.exists(dll_path):
|
||||
binaries.append((dll_path, "."))
|
||||
|
||||
# 2-2. 搜集底层 GDAL/GEOS/PROJ 核心框架与二进制扩展
|
||||
if os.path.isdir(CONDA_OSGEO_DLLS):
|
||||
for dll_name in ["gdal.dll", "geos.dll", "geos_c.dll", "proj_9.dll"]:
|
||||
dll_path = os.path.join(CONDA_OSGEO_DLLS, dll_name)
|
||||
if os.path.exists(dll_path):
|
||||
binaries.append((dll_path, "."))
|
||||
|
||||
# 映射 Python 3.12 对应的底层二进制接口 (C-Extension)
|
||||
for pyd_name in [
|
||||
"_gdal.cp312-win_amd64.pyd",
|
||||
"_gdal_array.cp312-win_amd64.pyd",
|
||||
"_gdalconst.cp312-win_amd64.pyd"
|
||||
]:
|
||||
pyd_path = os.path.join(CONDA_OSGEO_DLLS, pyd_name)
|
||||
if os.path.exists(pyd_path):
|
||||
binaries.append((pyd_path, "osgeo"))
|
||||
|
||||
return binaries
|
||||
|
||||
binaries = get_binaries()
|
||||
|
||||
# ==============================================================================
|
||||
# 3. 隐式依赖与底层动态加载池 (hiddenimports)
|
||||
# ==============================================================================
|
||||
hidden_imports = [
|
||||
"PyQt5.sip",
|
||||
# GDAL 空间处理核心
|
||||
"osgeo", "osgeo.gdal", "osgeo.gdalconst", "osgeo.gdalnumeric", "osgeo.ogr", "osgeo.osr",
|
||||
# 解决 rasterio 与 fiona 二进制隐藏扩展的断层报错
|
||||
"rasterio._base", "rasterio._env", "rasterio._io", "rasterio._warp",
|
||||
"rasterio._features", "rasterio._path", "rasterio.crs", "rasterio.env",
|
||||
"rasterio.features", "rasterio.warp", "rasterio.windows", "rasterio.sample", "rasterio.vrt",
|
||||
"fiona._env", "fiona._geometry", "fiona.ogrext", "fiona.io", "fiona.env", "fiona.features",
|
||||
# 几何计算与坐标转换
|
||||
"shapely._geos", "shapely._geometry", "shapely.lib",
|
||||
"pyproj", "pyproj._datadir", "pyproj._crs",
|
||||
"geopandas", "geopandas._compat", "geopandas.io",
|
||||
# 底层科学计算库支持
|
||||
"scipy.special._orthogonal", "scipy.spatial", "scipy.linalg",
|
||||
"sklearn.utils._index_deprecations", "sklearn.utils._testing", "sklearn._loss",
|
||||
"sklearn.ensemble", "sklearn.preprocessing", "sklearn.model_selection",
|
||||
# 报告与文档导出组件
|
||||
"docx", "docx.oxml", "docx.table", "docx.text",
|
||||
"lxml.etree", "lxml.objectify",
|
||||
# 业务面板与自定义挂载
|
||||
"src.gui.styles", "src.gui.components.custom_widgets",
|
||||
]
|
||||
|
||||
# ==============================================================================
|
||||
# 4. 运行时前置初始化钩子 (runtime_hooks)
|
||||
# ==============================================================================
|
||||
runtime_hooks = []
|
||||
rthook_path = os.path.join(PROJECT_ROOT, "scripts", "rthook_add_dll_dirs.py")
|
||||
if os.path.exists(rthook_path):
|
||||
runtime_hooks.append(rthook_path)
|
||||
|
||||
# ==============================================================================
|
||||
# 5. 精简排除列表 (excludes) - 严格保留标准库防级联瘫痪
|
||||
# ==============================================================================
|
||||
excludes = [
|
||||
"tkinter",
|
||||
"matplotlib.tests",
|
||||
"PyQt5.QtTest",
|
||||
"PyQt5.QtWebEngine",
|
||||
"PyQt5.QtWebEngineWidgets",
|
||||
"pytest",
|
||||
]
|
||||
|
||||
# ==============================================================================
|
||||
# 6. 核心构建流程 (Analysis -> PYZ -> EXE -> COLLECT)
|
||||
# ==============================================================================
|
||||
appname = "MegaWater"
|
||||
|
||||
a = Analysis(
|
||||
["src/gui/water_quality_gui_v2.py"],
|
||||
# ⚠️ 绝对关键:仅保留项目原生搜索路径,彻底切断与混合虚拟环境的联系
|
||||
pathex=[PROJECT_ROOT, SRC_DIR],
|
||||
binaries=binaries,
|
||||
datas=datas,
|
||||
hiddenimports=hidden_imports,
|
||||
hookspath=["scripts"] if os.path.isdir(os.path.join(PROJECT_ROOT, "scripts")) else [],
|
||||
hooksconfig={},
|
||||
runtime_hooks=runtime_hooks,
|
||||
excludes=excludes,
|
||||
win_no_prefer_redirects=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
# 强制清洗可能由于第三方包引入导致的、存在版本冲突的残缺 MSVC 动态库
|
||||
a.binaries = [
|
||||
x for x in a.binaries
|
||||
if not x[0].lower().startswith(('msvcp140', 'vcruntime140'))
|
||||
]
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
# 生成物理启动核心
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name=appname,
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False, # 禁用 UPX 暴力压缩,保护二进制 C++ 区段完整性
|
||||
console=False, # ⚠️ 维持开启控制台,拒绝绝对静默崩溃
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon="data/icons-1/app.ico", # 锁定物理执行文件桌面正方形主图标
|
||||
)
|
||||
|
||||
# 组装最终绿色分发目录 (_internal + EXE) - 引入全自动纯净 DLL 填坑机制
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
# 强制将原生编译的底层运行库塞入分发根目录,终结指针断层!
|
||||
[
|
||||
('msvcp140.dll', os.path.join(CONDA_ENV_DLLS, 'msvcp140.dll'), 'BINARY'),
|
||||
('vcruntime140.dll', os.path.join(CONDA_ENV_DLLS, 'vcruntime140.dll'), 'BINARY')
|
||||
],
|
||||
strip=False,
|
||||
upx=False,
|
||||
upx_exclude=[],
|
||||
name=appname,
|
||||
)
|
||||
Reference in New Issue
Block a user