diff --git a/BUILD_FIXES.md b/BUILD_FIXES.md new file mode 100644 index 0000000..43a9082 --- /dev/null +++ b/BUILD_FIXES.md @@ -0,0 +1,85 @@ +# Windows构建问题修复指南 + +## 🔧 已修复的问题 + +### 1. Hidden import 'numpy.core._methods' not found +**解决方案**: 在spec文件中添加了完整的numpy隐藏导入 +```python +'numpy.core._methods', +'numpy.core._dtype_ctypes', +'numpy.core._internal', +``` + +### 2. Hidden import "jinja2" not found +**解决方案**: 添加了jinja2相关导入 +```python +'jinja2', +'jinja2.ext', +'markupsafe', +``` + +### 3. Library not found: msvcp140-1a0962f2a91a74c6d7136a768987a591.dll +**解决方案**: +- 禁用UPX压缩 (`upx=False`) +- 添加pandas完整依赖收集 +- 使用`--collect-all=pandas`选项 + +## 🚀 使用修复后的构建脚本 + +### 1. 测试环境 +```bash +python test_build.py +``` + +### 2. 运行构建 +```bash +python windows_build.py +``` + +## 📋 构建选项说明 + +### PyInstaller命令行选项 +- `--clean`: 清理缓存 +- `--noconfirm`: 不询问确认 +- `--log-level=INFO`: 详细日志 +- `--collect-all=pandas`: 收集pandas所有模块 +- `--collect-all=numpy`: 收集numpy所有模块 +- `--collect-all=openpyxl`: 收集openpyxl所有模块 + +### 关键隐藏导入 +```python +'numpy.core._methods', +'pandas._libs.window.aggregations', +'ctypes.util', +'pkg_resources.py2_warn', +``` + +## ⚠️ 常见问题 + +### 1. 构建时间长 +- 正常现象,首次构建可能需要5-10分钟 +- 后续构建会使用缓存,速度更快 + +### 2. 文件大小大 +- 包含完整Python环境和所有依赖 +- 可以通过排除不必要的模块来减小大小 + +### 3. 警告信息 +- 大部分WARNING可以忽略 +- 只要没有ERROR,构建通常能成功 + +## 🎯 构建成功标志 + +``` +✅ 构建成功! 耗时: XX.X秒 +✅ 生成文件: dist/座位分配系统.exe +✅ 文件大小: XX.X MB +``` + +## 📦 分发包内容 + +构建成功后会生成: +- `座位分配系统_Windows_分发包/` + - `座位分配系统.exe` - 主程序 + - `README.txt` - 使用说明 + - `示例文件/` - 示例Excel文件(如果存在) diff --git a/test_build.py b/test_build.py new file mode 100644 index 0000000..6cc46e2 --- /dev/null +++ b/test_build.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +测试构建脚本 - 验证依赖和配置 +""" + +import sys +import subprocess +import platform + +def test_dependencies(): + """测试关键依赖""" + print("=" * 50) + print("测试关键依赖") + print("=" * 50) + + dependencies = [ + 'pandas', + 'numpy', + 'openpyxl', + 'pyinstaller' + ] + + for dep in dependencies: + try: + __import__(dep) + print(f"✅ {dep} - 已安装") + except ImportError: + print(f"❌ {dep} - 未安装") + return False + + return True + +def test_hidden_imports(): + """测试隐藏导入""" + print("\n" + "=" * 50) + print("测试隐藏导入") + print("=" * 50) + + hidden_imports = [ + 'numpy.core._methods', + 'pandas._libs.window.aggregations', + 'ctypes.util' + ] + + for imp in hidden_imports: + try: + parts = imp.split('.') + module = __import__(parts[0]) + for part in parts[1:]: + module = getattr(module, part) + print(f"✅ {imp} - 可访问") + except (ImportError, AttributeError) as e: + print(f"⚠️ {imp} - 无法访问: {e}") + + return True + +def test_pyinstaller(): + """测试PyInstaller""" + print("\n" + "=" * 50) + print("测试PyInstaller") + print("=" * 50) + + try: + result = subprocess.run([ + sys.executable, '-m', 'PyInstaller', '--version' + ], capture_output=True, text=True) + + if result.returncode == 0: + version = result.stdout.strip() + print(f"✅ PyInstaller版本: {version}") + return True + else: + print(f"❌ PyInstaller测试失败: {result.stderr}") + return False + except Exception as e: + print(f"❌ PyInstaller测试出错: {e}") + return False + +def main(): + """主函数""" + print(f"Python版本: {sys.version}") + print(f"操作系统: {platform.system()} {platform.release()}") + print(f"架构: {platform.machine()}") + + success = True + success &= test_dependencies() + success &= test_hidden_imports() + success &= test_pyinstaller() + + print("\n" + "=" * 50) + if success: + print("✅ 所有测试通过,可以进行构建") + else: + print("❌ 存在问题,请先解决依赖问题") + print("=" * 50) + + return success + +if __name__ == '__main__': + main() diff --git a/windows_build.py b/windows_build.py index 217847a..6755366 100644 --- a/windows_build.py +++ b/windows_build.py @@ -53,38 +53,64 @@ class WindowsBuilder: print("\n" + "=" * 60) print("安装构建依赖") print("=" * 60) - + required_packages = [ 'pandas>=1.3.0', 'openpyxl>=3.0.0', 'numpy>=1.20.0', - 'pyinstaller>=4.0' + 'pyinstaller>=5.0', + 'pywin32>=227' # Windows特定依赖 ] - + for package in required_packages: print(f"\n检查 {package}...") package_name = package.split('>=')[0] - - try: - __import__(package_name) - print(f"✅ {package_name} 已安装") - except ImportError: - print(f"📦 安装 {package}...") + + # 特殊处理pywin32 + if package_name == 'pywin32': try: - cmd = [sys.executable, '-m', 'pip', 'install', package, '--user'] - result = subprocess.run(cmd, capture_output=True, text=True, - encoding='utf-8', errors='ignore') - - if result.returncode == 0: - print(f"✅ {package} 安装成功") - else: - print(f"❌ {package} 安装失败") - print(f"错误信息: {result.stderr}") - return False - except Exception as e: - print(f"❌ 安装过程出错: {e}") + import win32api + print(f"✅ {package_name} 已安装") + continue + except ImportError: + pass + else: + try: + __import__(package_name) + print(f"✅ {package_name} 已安装") + continue + except ImportError: + pass + + print(f"📦 安装 {package}...") + try: + cmd = [sys.executable, '-m', 'pip', 'install', package, '--upgrade'] + result = subprocess.run(cmd, capture_output=True, text=True, + encoding='utf-8', errors='ignore') + + if result.returncode == 0: + print(f"✅ {package} 安装成功") + else: + print(f"❌ {package} 安装失败") + print(f"错误信息: {result.stderr}") + # 对于pywin32,尝试替代安装方法 + if package_name == 'pywin32': + print("尝试使用conda安装pywin32...") + try: + cmd_conda = ['conda', 'install', '-y', 'pywin32'] + result_conda = subprocess.run(cmd_conda, capture_output=True, text=True) + if result_conda.returncode == 0: + print("✅ pywin32 通过conda安装成功") + continue + except: + pass + print("⚠️ pywin32安装失败,但可能不影响构建") + continue return False - + except Exception as e: + print(f"❌ 安装过程出错: {e}") + return False + return True def clean_build_dirs(self): @@ -128,7 +154,7 @@ a = Analysis( hiddenimports=[ # 核心依赖 'pandas', - 'openpyxl', + 'openpyxl', 'numpy', 'xlsxwriter', 'xlrd', @@ -138,7 +164,7 @@ a = Analysis( 'platform', 'sys', 'os', - + # openpyxl相关 'openpyxl.workbook', 'openpyxl.worksheet', @@ -148,30 +174,59 @@ a = Analysis( 'openpyxl.reader.excel', 'openpyxl.cell', 'openpyxl.formatting', - + # pandas相关 'pandas.io.excel', 'pandas.io.common', 'pandas.io.parsers', 'pandas.io.formats.excel', + 'pandas._libs', + 'pandas._libs.tslibs', + 'pandas._libs.tslibs.base', 'pandas._libs.tslibs.timedeltas', 'pandas._libs.tslibs.np_datetime', 'pandas._libs.tslibs.nattype', - + 'pandas._libs.window', + 'pandas._libs.window.aggregations', + 'pandas._libs.hashtable', + 'pandas._libs.algos', + 'pandas._libs.index', + # numpy相关 + 'numpy.core', 'numpy.core.multiarray', 'numpy.core.umath', 'numpy.core._methods', + 'numpy.core._dtype_ctypes', + 'numpy.core._internal', 'numpy.lib.format', - + 'numpy.random', + 'numpy.random._pickle', + # 编码相关 'encodings', 'encodings.utf_8', 'encodings.gbk', - + 'encodings.cp1252', + 'encodings.latin1', + # 其他必要模块 '_ctypes', - 'ctypes.util' + 'ctypes.util', + 'pkg_resources', + 'pkg_resources.py2_warn', + 'pkg_resources.markers', + + # Jinja2相关(可能被某些依赖使用) + 'jinja2', + 'jinja2.ext', + 'markupsafe', + + # Windows特定模块(仅在Windows上可用) + # 'win32api', + # 'win32con', + # 'pywintypes', + # 'pythoncom' ], hookspath=[], hooksconfig={}, @@ -179,7 +234,11 @@ a = Analysis( excludes=[ # 排除不必要的大型库 'matplotlib', + 'matplotlib.pyplot', 'scipy', + 'sklearn', + 'tensorflow', + 'torch', 'IPython', 'jupyter', 'notebook', @@ -188,12 +247,37 @@ a = Analysis( 'PyQt6', 'PySide2', 'PySide6', + 'PIL', + 'cv2', + 'seaborn', + 'plotly', + 'bokeh', + + # 测试和开发工具 'test', 'tests', 'unittest', + 'pytest', 'setuptools', 'pip', - 'wheel' + 'wheel', + 'distutils', + + # 文档和示例 + 'sphinx', + 'docutils', + 'examples', + 'sample', + + # 其他不需要的模块 + 'curses', + 'readline', + 'sqlite3', + 'xml.etree.ElementTree', + 'html', + 'http', + 'urllib3', + 'requests' ], win_no_prefer_redirects=False, win_private_assemblies=False, @@ -244,6 +328,14 @@ exe = EXE( sys.executable, '-m', 'PyInstaller', '--clean', '--noconfirm', + '--log-level=INFO', + '--collect-all=pandas', + '--collect-all=numpy', + '--collect-all=openpyxl', + '--hidden-import=numpy.core._methods', + '--hidden-import=pandas._libs.window.aggregations', + '--hidden-import=ctypes.util', + '--hidden-import=pkg_resources.py2_warn', str(spec_file) ]