#!/usr/bin/env python3 """ 优化的EXE加密工具构建脚本 支持多种构建方式,自动处理依赖和错误恢复 """ import os import sys import shutil import subprocess import platform from pathlib import Path import json class BuildTool: def __init__(self): self.root_dir = Path.cwd() self.dist_dir = self.root_dir / "dist" self.build_dir = self.root_dir / "build" self.temp_files = [] def cleanup(self): """清理临时文件和目录""" print("🧹 清理临时文件...") # 清理目录 dirs_to_clean = [self.build_dir, self.dist_dir] for dir_path in dirs_to_clean: if dir_path.exists(): try: shutil.rmtree(dir_path) print(f" 删除目录: {dir_path}") except Exception as e: print(f" 删除目录失败 {dir_path}: {e}") # 清理临时文件 patterns = ["*.spec", "setup_*.py", "*.pyc", "*.pyo"] for pattern in patterns: for file_path in self.root_dir.glob(pattern): try: file_path.unlink() print(f" 删除文件: {file_path}") except Exception as e: print(f" 删除文件失败 {file_path}: {e}") # 清理__pycache__目录 for pycache_dir in self.root_dir.rglob("__pycache__"): try: shutil.rmtree(pycache_dir) print(f" 删除缓存: {pycache_dir}") except: pass def check_dependencies(self): """检查依赖包""" print("📦 检查依赖包...") required_packages = [ "mysql-connector-python", "cryptography", "pyperclip" ] missing_packages = [] for package in required_packages: try: __import__(package.replace('-', '_')) print(f" ✓ {package}") except ImportError: missing_packages.append(package) print(f" ✗ {package}") if missing_packages: print(f"❌ 缺少依赖包: {', '.join(missing_packages)}") print("正在安装缺少的依赖包...") for package in missing_packages: try: subprocess.run([sys.executable, "-m", "pip", "install", package], check=True, capture_output=True) print(f" ✓ 安装成功: {package}") except subprocess.CalledProcessError as e: print(f" ✗ 安装失败: {package} - {e}") return False return True def create_setup_file(self, script_name, exe_name, base_type="Console"): """创建setup文件""" packages = [ "mysql.connector", "cryptography", "uuid", "hashlib", "datetime", "platform", "subprocess", "json", "tempfile", "atexit", "ctypes" ] # 主程序需要额外的包 if script_name == "main.py": packages.extend(["tkinter", "pyperclip"]) setup_content = f'''#!/usr/bin/env python3 from cx_Freeze import setup, Executable import sys import os # 构建选项 build_exe_options = {{ "packages": {packages}, "include_files": [], "excludes": ["unittest", "test", "distutils", "email"], "build_exe": "dist_{exe_name.replace('.exe', '')}", "optimize": 0, "include_msvcrt": True }} # 如果存在配置文件,包含它 if os.path.exists("db_config.json"): build_exe_options["include_files"].append("db_config.json") # 可执行文件配置 executables = [ Executable( "{script_name}", base="{base_type}" if sys.platform == "win32" else None, target_name="{exe_name}", icon=None ) ] setup( name="{exe_name.replace('.exe', '')}", version="2.0", description="EXE Encryption Tool Component", options={{"build_exe": build_exe_options}}, executables=executables ) ''' return setup_content def build_with_cx_freeze(self): """使用cx_Freeze构建""" print("🏗️ 使用cx_Freeze构建...") # 检查cx_Freeze try: import cx_Freeze print(f" cx_Freeze版本: {cx_Freeze.version}") except ImportError: print(" 安装cx_Freeze...") try: subprocess.run([sys.executable, "-m", "pip", "install", "cx_Freeze"], check=True) except subprocess.CalledProcessError: print(" ❌ cx_Freeze安装失败") return False # 构建配置 builds = [ ("validator.py", "validator.exe", "Console"), ("main.py", "EXE加密工具.exe", "Win32GUI") ] success_count = 0 for script, exe_name, base_type in builds: print(f" 构建 {script} -> {exe_name}") # 创建setup文件 setup_filename = f"setup_{exe_name.replace('.exe', '').replace('EXE加密工具', 'main')}.py" setup_content = self.create_setup_file(script, exe_name, base_type) try: with open(setup_filename, 'w', encoding='utf-8') as f: f.write(setup_content) self.temp_files.append(setup_filename) # 执行构建 result = subprocess.run( [sys.executable, setup_filename, "build"], capture_output=True, text=True, cwd=self.root_dir ) if result.returncode == 0: print(f" ✓ {exe_name} 构建成功") success_count += 1 else: print(f" ✗ {exe_name} 构建失败:") print(f" 错误: {result.stderr}") except Exception as e: print(f" ✗ {exe_name} 构建异常: {e}") return success_count == len(builds) def build_with_pyinstaller(self): """使用PyInstaller构建""" print("🏗️ 使用PyInstaller构建...") # 检查PyInstaller try: import PyInstaller except ImportError: print(" 安装PyInstaller...") try: subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller"], check=True) except subprocess.CalledProcessError: print(" ❌ PyInstaller安装失败") return False # 构建命令 commands = [ [ sys.executable, "-m", "PyInstaller", "--onefile", "--console", "--name=validator", "validator.py" ], [ sys.executable, "-m", "PyInstaller", "--onefile", "--windowed", "--name=EXE加密工具", "main.py" ] ] success_count = 0 for cmd in commands: print(f" 执行: {' '.join(cmd)}") try: result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.root_dir) if result.returncode == 0: print(f" ✓ 构建成功") success_count += 1 else: print(f" ✗ 构建失败: {result.stderr}") except Exception as e: print(f" ✗ 构建异常: {e}") return success_count == len(commands) def organize_cx_freeze_output(self): """整理cx_Freeze输出""" print("📁 整理cx_Freeze构建输出...") # 创建最终输出目录 final_dir = self.root_dir / "dist_final" final_dir.mkdir(exist_ok=True) # 查找所有构建目录 dist_dirs = [d for d in self.root_dir.iterdir() if d.is_dir() and d.name.startswith("dist_")] if not dist_dirs: print(" ❌ 没有找到构建输出目录") return False # 收集所有文件 all_files = {} for dist_dir in dist_dirs: print(f" 处理目录: {dist_dir}") for file_path in dist_dir.rglob("*"): if file_path.is_file(): # 避免重复的DLL文件,保留EXE文件 if file_path.name in all_files and not file_path.suffix == '.exe': continue all_files[file_path.name] = file_path # 复制文件到最终目录 for filename, filepath in all_files.items(): dest_path = final_dir / filename try: shutil.copy2(filepath, dest_path) print(f" 复制: {filename}") except Exception as e: print(f" 复制失败 {filename}: {e}") # 清理临时构建目录 for dist_dir in dist_dirs: try: shutil.rmtree(dist_dir) except: pass print(f" ✓ 文件已整理到: {final_dir}") return True def organize_pyinstaller_output(self): """整理PyInstaller输出""" print("📁 整理PyInstaller构建输出...") dist_dir = self.root_dir / "dist" if not dist_dir.exists(): print(" ❌ dist目录不存在") return False exe_files = list(dist_dir.glob("*.exe")) if not exe_files: print(" ❌ 没有找到可执行文件") return False print(f" ✓ 找到 {len(exe_files)} 个可执行文件") for exe_file in exe_files: print(f" {exe_file.name}") return True def cleanup_temp_files(self): """清理临时文件""" for temp_file in self.temp_files: try: if os.path.exists(temp_file): os.remove(temp_file) except: pass def validate_build_output(self): """验证构建输出""" print("✅ 验证构建结果...") # 查找可执行文件 exe_files = [] # 检查cx_Freeze输出 final_dir = self.root_dir / "dist_final" if final_dir.exists(): exe_files.extend(final_dir.glob("*.exe")) # 检查PyInstaller输出 if not exe_files: dist_dir = self.root_dir / "dist" if dist_dir.exists(): exe_files.extend(dist_dir.glob("*.exe")) if not exe_files: print(" ❌ 没有找到可执行文件") return False required_exes = ["validator.exe", "EXE加密工具.exe"] found_exes = [exe.name for exe in exe_files] success = True for required in required_exes: if required in found_exes: print(f" ✓ {required}") else: print(f" ✗ {required} - 未找到") success = False if success: print(f" ✓ 构建验证通过,共 {len(exe_files)} 个文件") for exe_file in exe_files: size_mb = exe_file.stat().st_size / (1024 * 1024) print(f" {exe_file.name}: {size_mb:.1f} MB") return success def build(self): """主构建流程""" print("🚀 开始构建EXE加密工具...") print(f"Python版本: {sys.version}") print(f"操作系统: {platform.system()} {platform.release()}") print(f"工作目录: {self.root_dir}") try: # 1. 清理环境 self.cleanup() # 2. 检查依赖 if not self.check_dependencies(): return False # 3. 尝试cx_Freeze构建 cx_success = self.build_with_cx_freeze() if cx_success: if self.organize_cx_freeze_output(): if self.validate_build_output(): print("🎉 cx_Freeze构建成功!") return True print("⚠️ cx_Freeze构建失败,尝试PyInstaller...") self.cleanup() # 4. 尝试PyInstaller构建 py_success = self.build_with_pyinstaller() if py_success: if self.organize_pyinstaller_output(): if self.validate_build_output(): print("🎉 PyInstaller构建成功!") return True print("❌ 所有构建方法都失败了") return False except KeyboardInterrupt: print("\n⏹️ 构建被用户中断") return False except Exception as e: print(f"❌ 构建过程出现异常: {e}") return False finally: # 清理临时文件 self.cleanup_temp_files() def show_usage_info(self): """显示使用说明""" print("\n📖 使用说明:") print("1. 确保所有Python文件在同一目录") print("2. 运行此构建脚本") print("3. 构建完成后,可执行文件将在dist或dist_final目录中") print("4. validator.exe是验证程序,用于加密过程") print("5. EXE加密工具.exe是主程序界面") print("\n⚠️ 注意事项:") print("- 确保有稳定的网络连接以下载依赖包") print("- 首次构建可能需要较长时间") print("- 如果遇到权限问题,请以管理员身份运行") def main(): builder = BuildTool() if len(sys.argv) > 1 and sys.argv[1] == "--help": builder.show_usage_info() return success = builder.build() if success: print("\n🎊 构建完成!") builder.show_usage_info() else: print("\n💥 构建失败!") print("请检查错误信息并解决相关问题") sys.exit(1) if __name__ == "__main__": main()