修改打包交脚本
This commit is contained in:
parent
02341150a9
commit
c0568cc1ec
85
BUILD_FIXES.md
Normal file
85
BUILD_FIXES.md
Normal file
@ -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文件(如果存在)
|
101
test_build.py
Normal file
101
test_build.py
Normal file
@ -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()
|
152
windows_build.py
152
windows_build.py
@ -53,38 +53,64 @@ class WindowsBuilder:
|
|||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
print("安装构建依赖")
|
print("安装构建依赖")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
required_packages = [
|
required_packages = [
|
||||||
'pandas>=1.3.0',
|
'pandas>=1.3.0',
|
||||||
'openpyxl>=3.0.0',
|
'openpyxl>=3.0.0',
|
||||||
'numpy>=1.20.0',
|
'numpy>=1.20.0',
|
||||||
'pyinstaller>=4.0'
|
'pyinstaller>=5.0',
|
||||||
|
'pywin32>=227' # Windows特定依赖
|
||||||
]
|
]
|
||||||
|
|
||||||
for package in required_packages:
|
for package in required_packages:
|
||||||
print(f"\n检查 {package}...")
|
print(f"\n检查 {package}...")
|
||||||
package_name = package.split('>=')[0]
|
package_name = package.split('>=')[0]
|
||||||
|
|
||||||
try:
|
# 特殊处理pywin32
|
||||||
__import__(package_name)
|
if package_name == 'pywin32':
|
||||||
print(f"✅ {package_name} 已安装")
|
|
||||||
except ImportError:
|
|
||||||
print(f"📦 安装 {package}...")
|
|
||||||
try:
|
try:
|
||||||
cmd = [sys.executable, '-m', 'pip', 'install', package, '--user']
|
import win32api
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True,
|
print(f"✅ {package_name} 已安装")
|
||||||
encoding='utf-8', errors='ignore')
|
continue
|
||||||
|
except ImportError:
|
||||||
if result.returncode == 0:
|
pass
|
||||||
print(f"✅ {package} 安装成功")
|
else:
|
||||||
else:
|
try:
|
||||||
print(f"❌ {package} 安装失败")
|
__import__(package_name)
|
||||||
print(f"错误信息: {result.stderr}")
|
print(f"✅ {package_name} 已安装")
|
||||||
return False
|
continue
|
||||||
except Exception as e:
|
except ImportError:
|
||||||
print(f"❌ 安装过程出错: {e}")
|
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
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 安装过程出错: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def clean_build_dirs(self):
|
def clean_build_dirs(self):
|
||||||
@ -128,7 +154,7 @@ a = Analysis(
|
|||||||
hiddenimports=[
|
hiddenimports=[
|
||||||
# 核心依赖
|
# 核心依赖
|
||||||
'pandas',
|
'pandas',
|
||||||
'openpyxl',
|
'openpyxl',
|
||||||
'numpy',
|
'numpy',
|
||||||
'xlsxwriter',
|
'xlsxwriter',
|
||||||
'xlrd',
|
'xlrd',
|
||||||
@ -138,7 +164,7 @@ a = Analysis(
|
|||||||
'platform',
|
'platform',
|
||||||
'sys',
|
'sys',
|
||||||
'os',
|
'os',
|
||||||
|
|
||||||
# openpyxl相关
|
# openpyxl相关
|
||||||
'openpyxl.workbook',
|
'openpyxl.workbook',
|
||||||
'openpyxl.worksheet',
|
'openpyxl.worksheet',
|
||||||
@ -148,30 +174,59 @@ a = Analysis(
|
|||||||
'openpyxl.reader.excel',
|
'openpyxl.reader.excel',
|
||||||
'openpyxl.cell',
|
'openpyxl.cell',
|
||||||
'openpyxl.formatting',
|
'openpyxl.formatting',
|
||||||
|
|
||||||
# pandas相关
|
# pandas相关
|
||||||
'pandas.io.excel',
|
'pandas.io.excel',
|
||||||
'pandas.io.common',
|
'pandas.io.common',
|
||||||
'pandas.io.parsers',
|
'pandas.io.parsers',
|
||||||
'pandas.io.formats.excel',
|
'pandas.io.formats.excel',
|
||||||
|
'pandas._libs',
|
||||||
|
'pandas._libs.tslibs',
|
||||||
|
'pandas._libs.tslibs.base',
|
||||||
'pandas._libs.tslibs.timedeltas',
|
'pandas._libs.tslibs.timedeltas',
|
||||||
'pandas._libs.tslibs.np_datetime',
|
'pandas._libs.tslibs.np_datetime',
|
||||||
'pandas._libs.tslibs.nattype',
|
'pandas._libs.tslibs.nattype',
|
||||||
|
'pandas._libs.window',
|
||||||
|
'pandas._libs.window.aggregations',
|
||||||
|
'pandas._libs.hashtable',
|
||||||
|
'pandas._libs.algos',
|
||||||
|
'pandas._libs.index',
|
||||||
|
|
||||||
# numpy相关
|
# numpy相关
|
||||||
|
'numpy.core',
|
||||||
'numpy.core.multiarray',
|
'numpy.core.multiarray',
|
||||||
'numpy.core.umath',
|
'numpy.core.umath',
|
||||||
'numpy.core._methods',
|
'numpy.core._methods',
|
||||||
|
'numpy.core._dtype_ctypes',
|
||||||
|
'numpy.core._internal',
|
||||||
'numpy.lib.format',
|
'numpy.lib.format',
|
||||||
|
'numpy.random',
|
||||||
|
'numpy.random._pickle',
|
||||||
|
|
||||||
# 编码相关
|
# 编码相关
|
||||||
'encodings',
|
'encodings',
|
||||||
'encodings.utf_8',
|
'encodings.utf_8',
|
||||||
'encodings.gbk',
|
'encodings.gbk',
|
||||||
|
'encodings.cp1252',
|
||||||
|
'encodings.latin1',
|
||||||
|
|
||||||
# 其他必要模块
|
# 其他必要模块
|
||||||
'_ctypes',
|
'_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=[],
|
hookspath=[],
|
||||||
hooksconfig={},
|
hooksconfig={},
|
||||||
@ -179,7 +234,11 @@ a = Analysis(
|
|||||||
excludes=[
|
excludes=[
|
||||||
# 排除不必要的大型库
|
# 排除不必要的大型库
|
||||||
'matplotlib',
|
'matplotlib',
|
||||||
|
'matplotlib.pyplot',
|
||||||
'scipy',
|
'scipy',
|
||||||
|
'sklearn',
|
||||||
|
'tensorflow',
|
||||||
|
'torch',
|
||||||
'IPython',
|
'IPython',
|
||||||
'jupyter',
|
'jupyter',
|
||||||
'notebook',
|
'notebook',
|
||||||
@ -188,12 +247,37 @@ a = Analysis(
|
|||||||
'PyQt6',
|
'PyQt6',
|
||||||
'PySide2',
|
'PySide2',
|
||||||
'PySide6',
|
'PySide6',
|
||||||
|
'PIL',
|
||||||
|
'cv2',
|
||||||
|
'seaborn',
|
||||||
|
'plotly',
|
||||||
|
'bokeh',
|
||||||
|
|
||||||
|
# 测试和开发工具
|
||||||
'test',
|
'test',
|
||||||
'tests',
|
'tests',
|
||||||
'unittest',
|
'unittest',
|
||||||
|
'pytest',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
'pip',
|
'pip',
|
||||||
'wheel'
|
'wheel',
|
||||||
|
'distutils',
|
||||||
|
|
||||||
|
# 文档和示例
|
||||||
|
'sphinx',
|
||||||
|
'docutils',
|
||||||
|
'examples',
|
||||||
|
'sample',
|
||||||
|
|
||||||
|
# 其他不需要的模块
|
||||||
|
'curses',
|
||||||
|
'readline',
|
||||||
|
'sqlite3',
|
||||||
|
'xml.etree.ElementTree',
|
||||||
|
'html',
|
||||||
|
'http',
|
||||||
|
'urllib3',
|
||||||
|
'requests'
|
||||||
],
|
],
|
||||||
win_no_prefer_redirects=False,
|
win_no_prefer_redirects=False,
|
||||||
win_private_assemblies=False,
|
win_private_assemblies=False,
|
||||||
@ -244,6 +328,14 @@ exe = EXE(
|
|||||||
sys.executable, '-m', 'PyInstaller',
|
sys.executable, '-m', 'PyInstaller',
|
||||||
'--clean',
|
'--clean',
|
||||||
'--noconfirm',
|
'--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)
|
str(spec_file)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user