PyArmor 8.4.4 PyInstaller 6.2.0 多模块项目加密打包实战指南1. 多模块加密打包的核心挑战当Python项目规模扩展到包含多个子模块时传统的单文件加密方式往往会遇到依赖解析失效的问题。PyArmor对模块的加密会改变其内部结构导致PyInstaller无法自动识别依赖关系。以下是典型的多模块项目结构示例project/ ├── main.py ├── utils/ │ ├── __init__.py │ ├── network.py │ └── logger.py └── core/ ├── __init__.py └── processor.py关键痛点表现为相对导入失效ImportError: attempted relative import with no known parent package依赖模块丢失ModuleNotFoundError: No module named utils运行时解密失败pyarmor_runtime加载异常2. 分步加密方案设计2.1 模块级加密策略避免使用-r参数递归加密整个目录改为显式指定每个需要加密的模块pyarmor gen -O build/encrypted \ --prefix prefix \ ./main.py \ ./utils/__init__.py \ ./utils/network.py \ ./utils/logger.py \ ./core/__init__.py \ ./core/processor.py参数解析-O指定加密输出目录--prefix设置运行时前缀解决相对导入问题显式列出每个.py文件确保完整加密注意prefix需要替换为实际项目前缀如myproject2.2 依赖自动发现脚本创建generate_hidden_imports.py自动分析项目依赖import ast from pathlib import Path def extract_imports(filepath): with open(filepath) as f: tree ast.parse(f.read()) imports set() for node in ast.walk(tree): if isinstance(node, ast.Import): for alias in node.names: imports.add(alias.name.split(.)[0]) elif isinstance(node, ast.ImportFrom): if node.module: imports.add(node.module.split(.)[0]) return imports project_imports set() for py_file in Path(.).rglob(*.py): project_imports.update(extract_imports(py_file)) print( .join(f--hidden-import {imp} for imp in sorted(project_imports)))执行后将输出所有需要手动指定的--hidden-import参数。3. 高级打包配置3.1 定制化spec文件创建build.spec文件实现精细控制# -*- mode: python -*- block_cipher None a Analysis( [build/encrypted/main.py], pathex[.], binaries[], datas[ (build/encrypted/utils/*, utils), (build/encrypted/core/*, core) ], hiddenimports[ logging, json, # 添加generate_hidden_imports.py输出的依赖 ], hookspath[], runtime_hooks[], excludes[], win_no_prefer_redirectsFalse, win_private_assembliesFalse, cipherblock_cipher, noarchiveFalse, ) pyz PYZ(a.pure, a.zipped_data, cipherblock_cipher) exe EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, namemyapp, debugFalse, bootloader_ignore_signalsFalse, stripFalse, upxTrue, upx_exclude[], runtime_tmpdirNone, consoleTrue, disable_windowed_tracebackFalse, argv_emulationFalse, target_archNone, codesign_identityNone, entitlements_fileNone, )3.2 打包命令优化使用优化后的打包命令pyinstaller --clean \ --pathsbuild/encrypted \ --additional-hooks-dirhooks \ --onefile \ build.spec关键改进--paths指定加密后代码的搜索路径创建hooks/目录存放自定义hook脚本使用预生成的spec文件确保配置一致性4. 典型问题解决方案4.1 相对导入修复当遇到ImportError时修改加密命令pyarmor gen --prefix prefix \ -O build/encrypted \ --enable-suffix \ --mix-str \ --private \ ./main.py新增参数--enable-suffix为运行时模块添加唯一后缀--mix-str混淆字符串常量--private启用私有模式增强保护4.2 运行时路径处理在入口文件添加路径修复代码import sys from pathlib import Path # 解决加密后模块查找路径问题 if getattr(sys, frozen, False): base_path Path(sys.executable).parent sys.path.insert(0, str(base_path / utils)) sys.path.insert(0, str(base_path / core))4.3 依赖缺失诊断使用pyi-archive_viewer检查打包结果pyi-archive_viewer dist/myapp x main out main.pyc ^Z通过反编译main.pyc验证关键模块是否包含uncompyle6 main.pyc5. 安全增强措施5.1 代码混淆配置在项目根目录创建.pyarmor_config[options] enable_jit 1 obf_mod 2 obf_code 1 wrap_mode 1 restrict_mode 1 [runtime] license_file license.lic expired_date 2025-12-315.2 打包后加固使用UPX进行二次压缩upx --best --lzma dist/myapp验证加固效果strings dist/myapp | grep -i pyarmor应无敏感信息泄露6. 跨平台打包策略6.1 Windows特定配置添加资源文件声明# 在spec文件中追加 exe EXE( # ...其他参数... iconassets/icon.ico, versionversion.txt, )6.2 macOS签名处理打包后执行代码签名codesign --deep --force --verify \ --sign Developer ID Application \ --timestamp \ dist/myapp6.3 Linux兼容性解决glibc依赖问题patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 \ --set-rpath $ORIGIN/lib \ dist/myapp7. 效能优化技巧7.1 模块排除列表在spec文件中精简依赖excludes [ tkinter, unittest, email, xml, pydoc, test ]7.2 编译缓存利用启用PyInstaller缓存加速export PYINSTALLER_CONFIG_DIR$HOME/.pyinstaller pyinstaller --clean --noconfirm build.spec7.3 并行构建使用多核加速pyarmor gen -j 4 -O build/encrypted main.py utils/*.py core/*.py