303 lines
8.3 KiB
Python
303 lines
8.3 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
修复DLL加载失败的专用构建脚本
|
||
专门解决pandas._libs.window.aggregations DLL问题
|
||
"""
|
||
|
||
import sys
|
||
import subprocess
|
||
import platform
|
||
import site
|
||
from pathlib import Path
|
||
|
||
def get_pandas_libs_path():
|
||
"""获取pandas库文件路径"""
|
||
try:
|
||
import pandas
|
||
pandas_path = Path(pandas.__file__).parent
|
||
libs_path = pandas_path / '_libs'
|
||
return libs_path
|
||
except ImportError:
|
||
return None
|
||
|
||
def create_dll_fix_spec():
|
||
"""创建修复DLL问题的spec文件"""
|
||
|
||
# 获取pandas库路径
|
||
pandas_libs = get_pandas_libs_path()
|
||
if not pandas_libs or not pandas_libs.exists():
|
||
print("❌ 无法找到pandas库路径")
|
||
return None
|
||
|
||
print(f"✅ 找到pandas库路径: {pandas_libs}")
|
||
|
||
# 查找所有.pyd文件(Windows DLL)
|
||
pyd_files = list(pandas_libs.glob('**/*.pyd'))
|
||
print(f"✅ 找到 {len(pyd_files)} 个pandas DLL文件")
|
||
|
||
# 构建binaries列表
|
||
binaries_list = []
|
||
for pyd_file in pyd_files:
|
||
rel_path = pyd_file.relative_to(pandas_libs.parent)
|
||
binaries_list.append(f"(r'{pyd_file}', r'{rel_path.parent}')")
|
||
|
||
binaries_str = ',\n '.join(binaries_list)
|
||
|
||
spec_content = f'''# -*- mode: python ; coding: utf-8 -*-
|
||
# 专门修复pandas DLL加载问题的配置
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
block_cipher = None
|
||
|
||
a = Analysis(
|
||
['seat_allocation_system.py'],
|
||
pathex=[],
|
||
binaries=[
|
||
# 手动包含所有pandas DLL文件
|
||
{binaries_str}
|
||
],
|
||
datas=[],
|
||
hiddenimports=[
|
||
# 核心模块
|
||
'pandas',
|
||
'numpy',
|
||
'openpyxl',
|
||
|
||
# pandas核心库(必须)
|
||
'pandas._libs',
|
||
'pandas._libs.lib',
|
||
'pandas._libs.hashtable',
|
||
'pandas._libs.tslib',
|
||
'pandas._libs.algos',
|
||
'pandas._libs.join',
|
||
'pandas._libs.index',
|
||
'pandas._libs.internals',
|
||
'pandas._libs.writers',
|
||
'pandas._libs.parsers',
|
||
'pandas._libs.testing',
|
||
'pandas._libs.sparse',
|
||
'pandas._libs.reduction',
|
||
'pandas._libs.ops',
|
||
'pandas._libs.missing',
|
||
'pandas._libs.groupby',
|
||
'pandas._libs.reshape',
|
||
|
||
# pandas时间序列库
|
||
'pandas._libs.tslibs',
|
||
'pandas._libs.tslibs.base',
|
||
'pandas._libs.tslibs.ccalendar',
|
||
'pandas._libs.tslibs.conversion',
|
||
'pandas._libs.tslibs.dtypes',
|
||
'pandas._libs.tslibs.fields',
|
||
'pandas._libs.tslibs.nattype',
|
||
'pandas._libs.tslibs.np_datetime',
|
||
'pandas._libs.tslibs.offsets',
|
||
'pandas._libs.tslibs.parsing',
|
||
'pandas._libs.tslibs.period',
|
||
'pandas._libs.tslibs.strptime',
|
||
'pandas._libs.tslibs.timedeltas',
|
||
'pandas._libs.tslibs.timestamps',
|
||
'pandas._libs.tslibs.timezones',
|
||
'pandas._libs.tslibs.tzconversion',
|
||
'pandas._libs.tslibs.vectorized',
|
||
|
||
# pandas窗口函数库(关键!)
|
||
'pandas._libs.window',
|
||
'pandas._libs.window.aggregations',
|
||
'pandas._libs.window.indexers',
|
||
|
||
# numpy核心
|
||
'numpy.core._methods',
|
||
'numpy.core._dtype_ctypes',
|
||
'numpy.core.multiarray',
|
||
'numpy.core.umath',
|
||
|
||
# 其他必要模块
|
||
'ctypes.util',
|
||
'pkg_resources.py2_warn',
|
||
'encodings.utf_8',
|
||
'encodings.gbk',
|
||
|
||
# openpyxl
|
||
'openpyxl.workbook',
|
||
'openpyxl.worksheet',
|
||
'openpyxl.styles',
|
||
],
|
||
hookspath=[],
|
||
hooksconfig={{}},
|
||
runtime_hooks=[],
|
||
excludes=[
|
||
'matplotlib',
|
||
'scipy',
|
||
'IPython',
|
||
'jupyter',
|
||
'tkinter',
|
||
'PyQt5',
|
||
'PyQt6',
|
||
'PIL',
|
||
'cv2',
|
||
'sklearn',
|
||
'tensorflow',
|
||
'torch',
|
||
],
|
||
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='座位分配系统_修复版',
|
||
debug=False,
|
||
bootloader_ignore_signals=False,
|
||
strip=False,
|
||
upx=False, # 禁用UPX压缩,避免DLL问题
|
||
upx_exclude=[],
|
||
runtime_tmpdir=None,
|
||
console=True,
|
||
disable_windowed_traceback=False,
|
||
argv_emulation=False,
|
||
target_arch=None,
|
||
codesign_identity=None,
|
||
entitlements_file=None,
|
||
)
|
||
'''
|
||
|
||
spec_file = Path('dll_fix.spec')
|
||
with open(spec_file, 'w', encoding='utf-8') as f:
|
||
f.write(spec_content)
|
||
|
||
print(f"✅ 创建DLL修复spec文件: {spec_file}")
|
||
return spec_file
|
||
|
||
def build_with_dll_fix():
|
||
"""使用DLL修复配置构建"""
|
||
print("=" * 60)
|
||
print("DLL修复构建")
|
||
print("=" * 60)
|
||
|
||
# 检查环境
|
||
if platform.system() != 'Windows':
|
||
print("❌ 此脚本仅适用于Windows")
|
||
return False
|
||
|
||
print(f"✅ 系统: {platform.system()} {platform.release()}")
|
||
|
||
# 检查主文件
|
||
main_file = Path('seat_allocation_system.py')
|
||
if not main_file.exists():
|
||
print("❌ 未找到主程序文件")
|
||
return False
|
||
|
||
# 创建修复spec文件
|
||
spec_file = create_dll_fix_spec()
|
||
if not spec_file:
|
||
return False
|
||
|
||
# 清理旧文件
|
||
dist_dir = Path('dist')
|
||
if dist_dir.exists():
|
||
import shutil
|
||
shutil.rmtree(dist_dir)
|
||
print("✅ 清理dist目录")
|
||
|
||
# 构建命令
|
||
cmd = [
|
||
sys.executable, '-m', 'PyInstaller',
|
||
'--clean',
|
||
'--noconfirm',
|
||
'--log-level=WARN', # 减少输出
|
||
str(spec_file)
|
||
]
|
||
|
||
print(f"\n执行命令: {' '.join(cmd)}")
|
||
print("开始DLL修复构建...")
|
||
|
||
try:
|
||
# 执行构建
|
||
result = subprocess.run(
|
||
cmd,
|
||
capture_output=True,
|
||
text=True,
|
||
encoding='utf-8',
|
||
errors='ignore'
|
||
)
|
||
|
||
# 显示结果
|
||
if result.returncode == 0:
|
||
print("✅ DLL修复构建成功!")
|
||
|
||
# 检查生成的文件
|
||
exe_path = Path('dist/座位分配系统_修复版.exe')
|
||
if exe_path.exists():
|
||
size_mb = exe_path.stat().st_size / (1024 * 1024)
|
||
print(f"✅ 生成文件: {exe_path}")
|
||
print(f"✅ 文件大小: {size_mb:.1f} MB")
|
||
|
||
# 测试运行
|
||
print("\n🧪 测试运行...")
|
||
test_cmd = [str(exe_path), '--help']
|
||
try:
|
||
test_result = subprocess.run(
|
||
test_cmd,
|
||
capture_output=True,
|
||
text=True,
|
||
timeout=10
|
||
)
|
||
if test_result.returncode == 0:
|
||
print("✅ 程序可以正常启动")
|
||
else:
|
||
print("⚠️ 程序启动有问题,但文件已生成")
|
||
except subprocess.TimeoutExpired:
|
||
print("⚠️ 测试超时,但文件已生成")
|
||
except Exception as e:
|
||
print(f"⚠️ 测试失败: {e}")
|
||
|
||
return True
|
||
else:
|
||
print("❌ 未找到生成的exe文件")
|
||
return False
|
||
else:
|
||
print("❌ DLL修复构建失败!")
|
||
print("错误输出:")
|
||
print(result.stderr)
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ 构建出错: {e}")
|
||
return False
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print("🔧 pandas DLL加载失败修复工具")
|
||
print("专门解决: ImportError: DLL load failed while importing aggregations")
|
||
print()
|
||
|
||
success = build_with_dll_fix()
|
||
|
||
if success:
|
||
print("\n🎉 DLL修复构建完成!")
|
||
print("可执行文件: dist/座位分配系统_修复版.exe")
|
||
print("\n💡 如果仍有问题,请尝试:")
|
||
print("1. 在目标机器上安装 Visual C++ Redistributable")
|
||
print("2. 确保目标机器有相同的Windows版本")
|
||
else:
|
||
print("\n❌ DLL修复构建失败!")
|
||
print("请检查pandas安装是否完整")
|
||
|
||
input("\n按Enter键退出...")
|
||
|
||
if __name__ == '__main__':
|
||
main()
|