From 1e9925a9f2c23cee4b9496d7b77b57a9512689da Mon Sep 17 00:00:00 2001 From: yovinchen Date: Wed, 2 Jul 2025 20:08:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=89=93=E5=8C=85=E4=BA=A4?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fix_dll_build.bat | 42 +++++++ fix_dll_build.py | 302 +++++++++++++++++++++++++++++++++++++++++++++ test_pandas_dll.py | 169 +++++++++++++++++++++++++ 3 files changed, 513 insertions(+) create mode 100644 fix_dll_build.bat create mode 100644 fix_dll_build.py create mode 100644 test_pandas_dll.py diff --git a/fix_dll_build.bat b/fix_dll_build.bat new file mode 100644 index 0000000..33c2959 --- /dev/null +++ b/fix_dll_build.bat @@ -0,0 +1,42 @@ +@echo off +chcp 65001 >nul +echo ============================================================ +echo pandas DLL修复构建脚本 +echo 专门解决: ImportError: DLL load failed while importing aggregations +echo ============================================================ +echo. + +echo 检查Python环境... +python --version +if errorlevel 1 ( + echo ❌ Python未安装或未添加到PATH + pause + exit /b 1 +) + +echo. +echo 检查pandas安装... +python -c "import pandas; print(f'✅ pandas版本: {pandas.__version__}')" +if errorlevel 1 ( + echo ❌ pandas未安装 + echo 正在安装pandas... + pip install pandas +) + +echo. +echo 检查PyInstaller... +python -c "import PyInstaller; print('✅ PyInstaller已安装')" +if errorlevel 1 ( + echo ❌ PyInstaller未安装 + echo 正在安装PyInstaller... + pip install pyinstaller +) + +echo. +echo 开始DLL修复构建... +python fix_dll_build.py + +echo. +echo 构建完成! +echo 如果成功,可执行文件位于: dist\座位分配系统_修复版.exe +pause diff --git a/fix_dll_build.py b/fix_dll_build.py new file mode 100644 index 0000000..c8062b2 --- /dev/null +++ b/fix_dll_build.py @@ -0,0 +1,302 @@ +#!/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() diff --git a/test_pandas_dll.py b/test_pandas_dll.py new file mode 100644 index 0000000..36c1c8a --- /dev/null +++ b/test_pandas_dll.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +测试pandas DLL模块加载 +专门检查可能导致PyInstaller问题的模块 +""" + +import sys +import traceback +from pathlib import Path + +def test_pandas_core(): + """测试pandas核心模块""" + print("=" * 50) + print("测试pandas核心模块") + print("=" * 50) + + modules_to_test = [ + 'pandas', + 'pandas._libs', + 'pandas._libs.lib', + 'pandas._libs.hashtable', + 'pandas._libs.algos', + 'pandas._libs.index', + 'pandas._libs.writers', + 'pandas._libs.parsers', + 'pandas._libs.tslibs', + 'pandas._libs.tslibs.base', + 'pandas._libs.window', + 'pandas._libs.window.aggregations', # 关键模块! + 'pandas._libs.window.indexers', + ] + + success_count = 0 + for module in modules_to_test: + try: + __import__(module) + print(f"✅ {module}") + success_count += 1 + except ImportError as e: + print(f"❌ {module}: {e}") + except Exception as e: + print(f"⚠️ {module}: {e}") + + print(f"\n成功加载: {success_count}/{len(modules_to_test)} 个模块") + return success_count == len(modules_to_test) + +def test_pandas_functionality(): + """测试pandas基本功能""" + print("\n" + "=" * 50) + print("测试pandas基本功能") + print("=" * 50) + + try: + import pandas as pd + import numpy as np + + # 创建测试数据 + df = pd.DataFrame({ + 'A': [1, 2, 3, 4, 5], + 'B': [10, 20, 30, 40, 50] + }) + + print("✅ DataFrame创建成功") + + # 测试窗口函数(这是出错的关键) + result = df['A'].rolling(window=2).sum() + print("✅ rolling窗口函数正常") + + # 测试聚合函数 + agg_result = df.groupby('A').agg({'B': 'sum'}) + print("✅ groupby聚合函数正常") + + # 测试Excel读写 + test_file = Path('test_pandas.xlsx') + df.to_excel(test_file, index=False) + df_read = pd.read_excel(test_file) + test_file.unlink() # 删除测试文件 + print("✅ Excel读写功能正常") + + return True + + except Exception as e: + print(f"❌ pandas功能测试失败: {e}") + traceback.print_exc() + return False + +def check_pandas_installation(): + """检查pandas安装信息""" + print("\n" + "=" * 50) + print("pandas安装信息") + print("=" * 50) + + try: + import pandas as pd + print(f"✅ pandas版本: {pd.__version__}") + print(f"✅ pandas路径: {pd.__file__}") + + # 检查_libs目录 + pandas_path = Path(pd.__file__).parent + libs_path = pandas_path / '_libs' + + if libs_path.exists(): + print(f"✅ _libs目录存在: {libs_path}") + + # 统计.pyd文件 + pyd_files = list(libs_path.glob('**/*.pyd')) + print(f"✅ 找到 {len(pyd_files)} 个.pyd文件") + + # 检查关键文件 + key_files = [ + 'window/aggregations.cp310-win_amd64.pyd', + 'window/indexers.cp310-win_amd64.pyd', + 'hashtable.cp310-win_amd64.pyd', + 'lib.cp310-win_amd64.pyd' + ] + + for key_file in key_files: + file_path = libs_path / key_file + if file_path.exists(): + print(f"✅ 关键文件存在: {key_file}") + else: + print(f"❌ 关键文件缺失: {key_file}") + else: + print(f"❌ _libs目录不存在: {libs_path}") + return False + + return True + + except Exception as e: + print(f"❌ 检查pandas安装失败: {e}") + return False + +def main(): + """主函数""" + print("🔍 pandas DLL模块测试工具") + print("用于诊断PyInstaller构建问题") + print() + + # 基本信息 + print(f"Python版本: {sys.version}") + print(f"平台: {sys.platform}") + + # 运行测试 + install_ok = check_pandas_installation() + core_ok = test_pandas_core() + func_ok = test_pandas_functionality() + + print("\n" + "=" * 50) + print("测试结果总结") + print("=" * 50) + + if install_ok and core_ok and func_ok: + print("✅ 所有测试通过!pandas安装正常") + print("💡 如果PyInstaller仍有问题,请使用 fix_dll_build.py") + else: + print("❌ 存在问题,建议:") + if not install_ok: + print(" 1. 重新安装pandas: pip uninstall pandas && pip install pandas") + if not core_ok: + print(" 2. 检查pandas C扩展是否正确编译") + if not func_ok: + print(" 3. 检查依赖库(numpy等)是否正常") + + print("=" * 50) + input("\n按Enter键退出...") + +if __name__ == '__main__': + main()