327 lines
8.9 KiB
Python
327 lines
8.9 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
跨平台构建脚本
|
||
在macOS上构建Windows x86/x64版本的exe文件
|
||
使用Wine和PyInstaller实现跨平台编译
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import subprocess
|
||
import platform
|
||
import shutil
|
||
from pathlib import Path
|
||
|
||
def check_dependencies():
|
||
"""检查必要的依赖"""
|
||
print("检查构建依赖...")
|
||
|
||
# 检查是否在macOS上
|
||
if platform.system() != 'Darwin':
|
||
print(f"当前系统: {platform.system()}")
|
||
print("此脚本专为macOS设计,用于构建Windows版本")
|
||
return False
|
||
|
||
# 检查Python包
|
||
required_packages = ['pandas', 'openpyxl', 'pyinstaller']
|
||
missing_packages = []
|
||
|
||
for package in required_packages:
|
||
try:
|
||
__import__(package)
|
||
print(f"✅ {package} 已安装")
|
||
except ImportError:
|
||
missing_packages.append(package)
|
||
print(f"❌ {package} 未安装")
|
||
|
||
if missing_packages:
|
||
print(f"\n安装缺失的包...")
|
||
for package in missing_packages:
|
||
try:
|
||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', package])
|
||
print(f"✅ {package} 安装成功")
|
||
except subprocess.CalledProcessError:
|
||
print(f"❌ {package} 安装失败")
|
||
return False
|
||
|
||
return True
|
||
|
||
def install_wine():
|
||
"""安装Wine(如果需要)"""
|
||
print("\n检查Wine环境...")
|
||
|
||
# 检查是否已安装Wine
|
||
try:
|
||
result = subprocess.run(['wine', '--version'], capture_output=True, text=True)
|
||
if result.returncode == 0:
|
||
print(f"✅ Wine已安装: {result.stdout.strip()}")
|
||
return True
|
||
except FileNotFoundError:
|
||
pass
|
||
|
||
print("Wine未安装,开始安装...")
|
||
print("请按照以下步骤手动安装Wine:")
|
||
print("1. 安装Homebrew (如果未安装): /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"")
|
||
print("2. 安装Wine: brew install --cask wine-stable")
|
||
print("3. 配置Wine: winecfg")
|
||
|
||
response = input("是否已完成Wine安装? (y/N): ")
|
||
return response.lower() == 'y'
|
||
|
||
def setup_wine_python():
|
||
"""在Wine中设置Python环境"""
|
||
print("\n设置Wine Python环境...")
|
||
|
||
# 检查Wine中是否已安装Python
|
||
try:
|
||
result = subprocess.run(['wine', 'python', '--version'], capture_output=True, text=True)
|
||
if result.returncode == 0:
|
||
print(f"✅ Wine Python已安装: {result.stdout.strip()}")
|
||
return True
|
||
except:
|
||
pass
|
||
|
||
print("需要在Wine中安装Python...")
|
||
print("请按照以下步骤:")
|
||
print("1. 下载Windows版Python: https://www.python.org/downloads/windows/")
|
||
print("2. 使用Wine安装: wine python-3.10.x-amd64.exe")
|
||
print("3. 安装pip包: wine python -m pip install pandas openpyxl pyinstaller")
|
||
|
||
response = input("是否已完成Wine Python安装? (y/N): ")
|
||
return response.lower() == 'y'
|
||
|
||
def create_build_spec(target_arch='x64'):
|
||
"""创建构建规格文件"""
|
||
exe_name = f"座位分配系统_{target_arch}"
|
||
|
||
spec_content = f'''# -*- mode: python ; coding: utf-8 -*-
|
||
|
||
block_cipher = None
|
||
|
||
a = Analysis(
|
||
['seat_allocation_system.py'],
|
||
pathex=[],
|
||
binaries=[],
|
||
datas=[],
|
||
hiddenimports=[
|
||
'pandas',
|
||
'openpyxl',
|
||
'numpy',
|
||
'xlsxwriter',
|
||
'xlrd',
|
||
'datetime',
|
||
'pathlib'
|
||
],
|
||
hookspath=[],
|
||
hooksconfig={{}},
|
||
runtime_hooks=[],
|
||
excludes=[
|
||
'matplotlib',
|
||
'scipy',
|
||
'IPython',
|
||
'jupyter',
|
||
'notebook',
|
||
'tkinter'
|
||
],
|
||
win_no_prefer_redirects=False,
|
||
win_private_assemblies=False,
|
||
cipher=block_cipher,
|
||
noarchive=False,
|
||
)
|
||
|
||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||
|
||
exe = EXE(
|
||
pyz,
|
||
a.scripts,
|
||
a.binaries,
|
||
a.zipfiles,
|
||
a.datas,
|
||
[],
|
||
name='{exe_name}',
|
||
debug=False,
|
||
bootloader_ignore_signals=False,
|
||
strip=False,
|
||
upx=True,
|
||
upx_exclude=[],
|
||
runtime_tmpdir=None,
|
||
console=True,
|
||
disable_windowed_traceback=False,
|
||
argv_emulation=False,
|
||
target_arch=None,
|
||
codesign_identity=None,
|
||
entitlements_file=None,
|
||
icon=None,
|
||
)
|
||
'''
|
||
|
||
spec_file = f'{exe_name}.spec'
|
||
with open(spec_file, 'w', encoding='utf-8') as f:
|
||
f.write(spec_content)
|
||
|
||
return spec_file, exe_name
|
||
|
||
def build_with_docker():
|
||
"""使用Docker构建Windows版本"""
|
||
print("\n使用Docker构建Windows版本...")
|
||
|
||
# 创建Dockerfile
|
||
dockerfile_content = '''FROM python:3.10-windowsservercore
|
||
|
||
# 设置工作目录
|
||
WORKDIR /app
|
||
|
||
# 复制文件
|
||
COPY requirements.txt .
|
||
COPY seat_allocation_system.py .
|
||
|
||
# 安装依赖
|
||
RUN pip install -r requirements.txt
|
||
|
||
# 构建exe
|
||
RUN pyinstaller --onefile --console --name "座位分配系统_x64" seat_allocation_system.py
|
||
|
||
# 输出目录
|
||
VOLUME ["/app/dist"]
|
||
'''
|
||
|
||
with open('Dockerfile.windows', 'w') as f:
|
||
f.write(dockerfile_content)
|
||
|
||
print("Docker方法需要Docker Desktop和Windows容器支持")
|
||
print("这是一个高级选项,建议使用其他方法")
|
||
return False
|
||
|
||
def build_native_macos():
|
||
"""在macOS上直接构建(生成macOS版本)"""
|
||
print("\n在macOS上构建本地版本...")
|
||
|
||
# 清理之前的构建
|
||
if os.path.exists('dist'):
|
||
shutil.rmtree('dist')
|
||
if os.path.exists('build'):
|
||
shutil.rmtree('build')
|
||
|
||
# 构建命令
|
||
cmd = [
|
||
sys.executable, '-m', 'PyInstaller',
|
||
'--onefile',
|
||
'--console',
|
||
'--clean',
|
||
'--name', '座位分配系统_macos',
|
||
'seat_allocation_system.py'
|
||
]
|
||
|
||
try:
|
||
print(f"执行命令: {' '.join(cmd)}")
|
||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||
|
||
if result.returncode == 0:
|
||
print("✅ macOS版本构建成功!")
|
||
|
||
# 检查生成的文件
|
||
app_path = Path('dist') / '座位分配系统_macos'
|
||
if app_path.exists():
|
||
file_size = app_path.stat().st_size / (1024 * 1024) # MB
|
||
print(f"生成文件: {app_path}")
|
||
print(f"文件大小: {file_size:.1f} MB")
|
||
return True, app_path
|
||
else:
|
||
print("❌ 构建失败!")
|
||
print("错误输出:")
|
||
print(result.stderr)
|
||
return False, None
|
||
|
||
except Exception as e:
|
||
print(f"❌ 构建过程中出现错误: {e}")
|
||
return False, None
|
||
|
||
def create_cross_compile_script():
|
||
"""创建跨编译脚本"""
|
||
script_content = '''#!/bin/bash
|
||
# Windows交叉编译脚本
|
||
|
||
echo "座位分配系统 - Windows交叉编译"
|
||
echo "================================"
|
||
|
||
# 检查是否安装了mingw-w64
|
||
if ! command -v x86_64-w64-mingw32-gcc &> /dev/null; then
|
||
echo "安装mingw-w64..."
|
||
brew install mingw-w64
|
||
fi
|
||
|
||
# 设置交叉编译环境
|
||
export CC=x86_64-w64-mingw32-gcc
|
||
export CXX=x86_64-w64-mingw32-g++
|
||
|
||
# 构建Windows版本
|
||
echo "开始构建Windows x64版本..."
|
||
python -m PyInstaller \\
|
||
--onefile \\
|
||
--console \\
|
||
--clean \\
|
||
--name "座位分配系统_x64" \\
|
||
--target-arch x86_64 \\
|
||
seat_allocation_system.py
|
||
|
||
echo "构建完成!"
|
||
'''
|
||
|
||
with open('cross_compile.sh', 'w') as f:
|
||
f.write(script_content)
|
||
|
||
# 设置执行权限
|
||
os.chmod('cross_compile.sh', 0o755)
|
||
print("✅ 已创建交叉编译脚本: cross_compile.sh")
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print("座位分配系统 - 跨平台构建工具")
|
||
print("=" * 50)
|
||
print("在macOS上构建Windows版本")
|
||
|
||
# 检查依赖
|
||
if not check_dependencies():
|
||
return
|
||
|
||
print("\n选择构建方法:")
|
||
print("1. 构建macOS版本(推荐)")
|
||
print("2. 使用Wine构建Windows版本(复杂)")
|
||
print("3. 创建交叉编译脚本(实验性)")
|
||
print("4. 生成Docker构建文件(高级)")
|
||
|
||
choice = input("\n请选择 (1-4): ").strip()
|
||
|
||
if choice == '1':
|
||
print("\n构建macOS版本...")
|
||
success, app_path = build_native_macos()
|
||
if success:
|
||
print(f"\n🎉 构建完成!")
|
||
print(f"生成文件: {app_path}")
|
||
print("\n注意: 这是macOS版本,不能在Windows上运行")
|
||
print("如需Windows版本,请在Windows系统上运行构建脚本")
|
||
|
||
elif choice == '2':
|
||
print("\n使用Wine构建Windows版本...")
|
||
if install_wine() and setup_wine_python():
|
||
print("Wine环境已准备就绪")
|
||
print("请手动在Wine中运行: wine python windows_build.py")
|
||
else:
|
||
print("Wine环境设置失败")
|
||
|
||
elif choice == '3':
|
||
print("\n创建交叉编译脚本...")
|
||
create_cross_compile_script()
|
||
print("请运行: ./cross_compile.sh")
|
||
|
||
elif choice == '4':
|
||
print("\n生成Docker构建文件...")
|
||
build_with_docker()
|
||
|
||
else:
|
||
print("无效选择")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|