# main.spec import sys import os import pkgutil import glob # 新增:匹配所有 module_* 目录 from pathlib import Path # 1. 动态获取项目根目录(无需手动写死) PROJECT_ROOT = Path('/root/.hd/hd-crane-gs/backend').absolute() # spec文件所在目录 = 项目根目录 # 修复:扫描所有 module_* 目录并构建 datas 配置 def get_module_datas(): """获取所有 module_* 目录的打包配置""" api_v1_dir = PROJECT_ROOT / "app" / "api" / "v1" module_datas = [] if api_v1_dir.exists(): # 匹配所有 module_* 目录(兼容所有系统) module_dirs = glob.glob(str(api_v1_dir / "module_*")) for mod_dir in module_dirs: mod_dir_path = Path(mod_dir) if mod_dir_path.is_dir(): # 格式:(源目录, 目标目录) → 保持原结构 app/api/v1/module_xxx target_path = str(mod_dir_path.relative_to(PROJECT_ROOT)) module_datas.append((str(mod_dir_path), target_path)) return module_datas def get_all_needed_modules(): all_modules = [] # 扫描 app 目录下所有 .py 文件(排除 __init__.py) all_py_files = PROJECT_ROOT / "app" for file in all_py_files.rglob("*.py"): if file.name == "__init__.py": continue rel_path = file.relative_to(PROJECT_ROOT) mod_name = rel_path.with_suffix("").as_posix().replace("/", ".") all_modules.append(mod_name) all_modules = list(set(all_modules)) print(f"✅ 扫描到 {len(all_modules)} 个模块") return all_modules # 执行扫描,获取所有模块 hidden_imports = get_all_needed_modules() # 获取 module_* 目录的 datas 配置 module_datas = get_module_datas() # 2. 导入PyInstaller核心模块 from PyInstaller.utils.hooks import collect_all from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT # 基础配置 block_cipher = None # 3. 收集第三方依赖(asyncmy) asyncmy_datas, asyncmy_binaries, asyncmy_hiddenimports = collect_all('asyncmy') # 4. 分析项目代码(核心修复:添加 module_datas) a = Analysis( ['main.py'], # 主文件(确保在 PROJECT_ROOT 下) pathex=[str(PROJECT_ROOT)], # 项目根目录 binaries=asyncmy_binaries, datas=[ *asyncmy_datas, *module_datas, # 关键:添加所有 module_* 目录的打包配置 # 新增:打包所有 __init__.py(确保包目录被识别) (str(PROJECT_ROOT / "app"), "app"), (os.path.join(PROJECT_ROOT, "env"), "env"), (os.path.join(PROJECT_ROOT, "static"), "static"), (os.path.join(PROJECT_ROOT, "banner.txt"), "."), (os.path.join(PROJECT_ROOT, "app/api/v1/module_generator/gencode/templates"), "app/api/v1/module_generator/gencode/templates"), (os.path.join(PROJECT_ROOT, "app/scripts/data"), "app/scripts/data"), ], hiddenimports=[ # 第三方依赖 *asyncmy_hiddenimports, 'asyncmy.auth', 'asyncmy.connection', 'asyncmy.cursors', 'asyncmy.protocol', 'asyncmy.utils', 'passlib', 'passlib.context', 'passlib.handlers', 'passlib.handlers.bcrypt', 'passlib.handlers.md5_crypt', # 项目模块 *hidden_imports, ], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], noarchive=False, # 关键:不归档,保留目录结构 ) # 5. 打包为PYZ归档 pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) # 6. 生成可执行文件 exe = EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='main', debug=False, bootloader_ignore_signals=False, strip=False, upx=False, # 欧拉系统禁用UPX runtime_tmpdir=None, console=True, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, )