mxivideo/scripts/build_python_core.py

266 lines
7.6 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
构建脚本 - 将Python Core打包成独立可执行文件
"""
import os
import sys
import subprocess
import shutil
import platform
from pathlib import Path
def get_project_root():
"""获取项目根目录"""
current_file = Path(__file__).resolve()
# 从 scripts/build_python_core.py 回到项目根目录
return current_file.parent.parent
def install_dependencies():
"""安装构建依赖"""
print("📦 Installing build dependencies...")
dependencies = [
'pyinstaller>=5.0',
'requests',
'Pillow',
'opencv-python-headless', # 使用headless版本减少依赖
]
for dep in dependencies:
print(f"Installing {dep}...")
result = subprocess.run([
sys.executable, '-m', 'pip', 'install', dep
], capture_output=True, text=True)
if result.returncode != 0:
print(f"❌ Failed to install {dep}")
print(result.stderr)
return False
else:
print(f"✅ Installed {dep}")
return True
def clean_build_directory(python_core_dir):
"""清理构建目录"""
print("🧹 Cleaning build directories...")
dirs_to_clean = ['build', 'dist', '__pycache__']
for dir_name in dirs_to_clean:
dir_path = python_core_dir / dir_name
if dir_path.exists():
shutil.rmtree(dir_path)
print(f"Removed {dir_path}")
def build_executable(python_core_dir, use_simple=False):
"""构建可执行文件"""
print("🔨 Building executable...")
if use_simple:
spec_file = python_core_dir / 'build_simple.spec'
print("Using simplified build for testing...")
else:
spec_file = python_core_dir / 'build.spec'
if not spec_file.exists():
print(f"❌ Spec file not found: {spec_file}")
return False
# 运行PyInstaller
cmd = [
sys.executable, '-m', 'PyInstaller',
'--clean',
'--noconfirm',
str(spec_file)
]
print(f"Running: {' '.join(cmd)}")
result = subprocess.run(
cmd,
cwd=python_core_dir,
capture_output=True,
text=True
)
if result.returncode != 0:
print("❌ Build failed!")
print("STDOUT:", result.stdout)
print("STDERR:", result.stderr)
return False
print("✅ Build completed successfully!")
return True
def copy_to_sidecar_directory(project_root, python_core_dir):
"""复制可执行文件到Tauri sidecar目录"""
print("📁 Copying executable to sidecar directory...")
# 确定可执行文件名
system = platform.system().lower()
if system == 'windows':
exe_name = 'mixvideo-python-core.exe'
else:
exe_name = 'mixvideo-python-core'
# 源文件路径
source_exe = python_core_dir / 'dist' / exe_name
if not source_exe.exists():
print(f"❌ Executable not found: {source_exe}")
return False
# 目标目录
sidecar_dir = project_root / 'src-tauri' / 'binaries'
sidecar_dir.mkdir(exist_ok=True)
# 复制文件
target_exe = sidecar_dir / exe_name
shutil.copy2(source_exe, target_exe)
# 在Unix系统上设置执行权限
if system != 'windows':
os.chmod(target_exe, 0o755)
print(f"✅ Copied to: {target_exe}")
return True
def update_tauri_config(project_root):
"""更新Tauri配置文件以包含sidecar"""
print("⚙️ Updating Tauri configuration...")
import json
config_file = project_root / 'src-tauri' / 'tauri.conf.json'
if not config_file.exists():
print(f"❌ Tauri config not found: {config_file}")
return False
# 读取配置
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
# 添加sidecar配置
if 'bundle' not in config:
config['bundle'] = {}
if 'externalBin' not in config['bundle']:
config['bundle']['externalBin'] = []
# 检查是否已经存在
sidecar_name = 'mixvideo-python-core'
existing = any(
item.get('name') == sidecar_name
for item in config['bundle']['externalBin']
if isinstance(item, dict)
)
if not existing:
config['bundle']['externalBin'].append({
"name": sidecar_name,
"src": f"binaries/{sidecar_name}",
"targets": ["all"]
})
# 写回配置
with open(config_file, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2, ensure_ascii=False)
print("✅ Updated Tauri configuration")
else:
print(" Sidecar already configured in Tauri")
return True
def verify_build(project_root):
"""验证构建结果"""
print("🔍 Verifying build...")
system = platform.system().lower()
exe_name = 'mixvideo-python-core.exe' if system == 'windows' else 'mixvideo-python-core'
sidecar_exe = project_root / 'src-tauri' / 'binaries' / exe_name
if not sidecar_exe.exists():
print(f"❌ Sidecar executable not found: {sidecar_exe}")
return False
# 测试执行
try:
result = subprocess.run([
str(sidecar_exe), '--version'
], capture_output=True, text=True, timeout=10)
if result.returncode == 0:
print("✅ Executable is working correctly")
print(f"Version output: {result.stdout.strip()}")
return True
else:
print(f"❌ Executable test failed: {result.stderr}")
return False
except subprocess.TimeoutExpired:
print("❌ Executable test timed out")
return False
except Exception as e:
print(f"❌ Executable test error: {e}")
return False
def main():
"""主函数"""
print("🚀 Building MixVideo V2 Python Core...")
project_root = get_project_root()
python_core_dir = project_root / 'python_core'
print(f"Project root: {project_root}")
print(f"Python core directory: {python_core_dir}")
if not python_core_dir.exists():
print(f"❌ Python core directory not found: {python_core_dir}")
sys.exit(1)
# 步骤1: 安装依赖
if not install_dependencies():
print("❌ Failed to install dependencies")
sys.exit(1)
# 步骤2: 清理构建目录
clean_build_directory(python_core_dir)
# 步骤3: 构建可执行文件
# 首先尝试简化版本
print("Trying simplified build first...")
if not build_executable(python_core_dir, use_simple=True):
print("❌ Simplified build failed, trying full build...")
if not build_executable(python_core_dir, use_simple=False):
print("❌ Failed to build executable")
sys.exit(1)
# 步骤4: 复制到sidecar目录
if not copy_to_sidecar_directory(project_root, python_core_dir):
print("❌ Failed to copy executable")
sys.exit(1)
# 步骤5: 更新Tauri配置
if not update_tauri_config(project_root):
print("❌ Failed to update Tauri configuration")
sys.exit(1)
# 步骤6: 验证构建
if not verify_build(project_root):
print("❌ Build verification failed")
sys.exit(1)
print("🎉 Build completed successfully!")
print("\n📋 Next steps:")
print("1. Test the sidecar: cargo tauri dev")
print("2. Build the app: cargo tauri build")
print("3. The Python core will be bundled with your app")
if __name__ == "__main__":
main()