You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

macOS下PyInstaller.spec生成Bundle频繁遇模块缺失问题

PyInstaller打包macOS Bundle反复出现ModuleNotFoundError的解决思路

我在为项目生成macOS平台Bundle时遇到问题:仓库中的.spec文件在Windows上运行正常,但macOS下打包后启动总是抛出ModuleNotFoundError——先是缺openai,手动添加路径后又缺pydantic,逐个手动添加依赖显然不是长久之计。修改后的.spec文件如下:

# -*- mode: python ; coding: utf-8 -*-
import os.path
from pathlib import Path
from PyInstaller.compat import is_darwin, is_win
from PyInstaller.utils.hooks import copy_metadata, collect_data_files, collect_all


datas = []

datas += collect_data_files("transformers", include_py_files=True)
datas += collect_data_files("lightning")
datas += collect_data_files("lightning_fabric")
datas += collect_data_files("speechbrain")
datas += collect_data_files("pyannote")
datas += collect_data_files("asteroid_filterbanks")
datas += collect_data_files("whisperx")
datas += collect_data_files("librosa")

datas += copy_metadata("tqdm")
datas += copy_metadata("regex")
datas += copy_metadata("requests")
datas += copy_metadata("packaging")
datas += copy_metadata("filelock")
datas += copy_metadata("numpy")
datas += copy_metadata("tokenizers")
datas += copy_metadata("pillow")
datas += copy_metadata("huggingface_hub")
datas += copy_metadata("safetensors")
datas += copy_metadata("pyyaml")

datas += [("res", "res")]
datas += [("config.ini", ".")]
datas += [(".env", ".")]
datas += [("venv/lib/python3.10/site-packages/customtkinter", "customtkinter")]
datas += [("venv/lib/python3.10/site-packages/torch", "torch")]
datas += [("venv/lib/python3.10/site-packages/torchgen", "torchgen")]
datas += [("venv/lib/python3.10/site-packages/speech_recognition", "speech_recognition")]
datas += [("venv/lib/python3.10/site-packages/moviepy", "moviepy")]
datas += [("venv/lib/python3.10/site-packages/dotenv", "dotenv")]
datas += [("venv/lib/python3.10/site-packages/openai", "openai")]

hiddenimports = [
    "huggingface_hub.repository",
    "pytorch",
    "sklearn.utils._cython_blas",
    "sklearn.neighbors.typedefs",
    "sklearn.neighbors.quad_tree",
    "sklearn.tree",
    "sklearn.tree._utils",
    "darkdetect",
    "tkinter.font",
    "tkinter.ttk",
    "cmath",
    "pickletools",
    "unittest.mock",
    "aifc",
    "proglog",
    "imageio",
    "decorator",
]

block_cipher = None

debug = True
if debug:
    options = [("v", None, "OPTION")]
else:
    options = []

a = Analysis(
    ["src/app.py"],
    pathex=[],
    binaries=[],
    datas=datas,
    hiddenimports=hiddenimports,
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

macos_icon = "res/macos/icon.icns"
windows_icon = "res/windows/icon.ico"

exe = EXE(
    pyz,
    a.scripts,
    options,
    exclude_binaries=True, #NEW
    name="Audiotext",
    debug=debug,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=debug,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file="res/macos/entitlements.plist" if is_darwin else None,
    icon=windows_icon if is_win else macos_icon,
)

coll = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name="Audiotext",
)

app = BUNDLE(
    coll,
    name="Audiotext.app",
    icon=macos_icon,
    bundle_identifier="com.henestrosadev.audiotext",
    version="2.3.0",
    info_plist={
        "NSPrincipalClass": "NSApplication",
        "NSAppleScriptEnabed": False,
        "NSHighResolutionCapable": True,
        "NSMicrophoneUsageDescription": "Allow Audiotext to record audio from your microphone to generate transcriptions.",
    }
)

问题根源分析

  1. 硬编码虚拟环境路径干扰自动收集:.spec中手动添加venv/lib/python3.10/site-packages/xxx路径,会绕过PyInstaller的自动依赖扫描逻辑,导致间接依赖(比如pydantic是openai的依赖)无法被自动收集。
  2. 依赖收集方式单一:仅用collect_data_files无法完整收集复杂库的二进制文件和隐式导入,部分库需要专用钩子才能正确处理。
  3. 环境不一致:macOS和Windows的Python环境、虚拟环境结构存在差异,直接复用Windows的.spec逻辑会导致依赖扫描不完整。

针对性解决方案

1. 移除硬编码的venv路径,让PyInstaller自动收集依赖

删掉所有形如datas += [("venv/lib/python3.10/site-packages/xxx", "xxx")]的行,改用collect_all()工具批量收集库的模块、数据文件和二进制文件:

# 替换原有单个collect_data_files调用
datas = []
binaries = []
hiddenimports = []

# 批量收集复杂库的所有资源
for pkg in ["transformers", "lightning", "lightning_fabric", "speechbrain", "pyannote", "asteroid_filterbanks", "whisperx", "librosa", "customtkinter", "torch", "speech_recognition", "moviepy", "dotenv", "openai"]:
    pkg_datas, pkg_binaries, pkg_hidden = collect_all(pkg)
    datas += pkg_datas
    binaries += pkg_binaries
    hiddenimports += pkg_hidden

# 保留必要的元数据收集
datas += copy_metadata("tqdm")
datas += copy_metadata("regex")
datas += copy_metadata("requests")
datas += copy_metadata("packaging")
datas += copy_metadata("filelock")
datas += copy_metadata("numpy")
datas += copy_metadata("tokenizers")
datas += copy_metadata("pillow")
datas += copy_metadata("huggingface_hub")
datas += copy_metadata("safetensors")
datas += copy_metadata("pyyaml")
datas += copy_metadata("pydantic")  # 若仍有缺失可手动添加元数据

# 保留项目自有资源
datas += [("res", "res")]
datas += [("config.ini", ".")]
datas += [(".env", ".")]

# 添加额外需要的隐式导入(仅保留确实缺失的)
hiddenimports += [
    "huggingface_hub.repository",
    "sklearn.utils._cython_blas",
    "sklearn.neighbors.typedefs",
    "sklearn.neighbors.quad_tree",
    "sklearn.tree",
    "sklearn.tree._utils",
    "darkdetect",
    "tkinter.font",
    "tkinter.ttk",
    "proglog",
    "imageio",
    "decorator",
]

2. 更新PyInstaller及钩子库

确保使用最新版PyInstaller和第三方钩子,以支持更多库的自动收集:

pip install --upgrade pyinstaller pyinstaller-hooks-contrib

3. 重建macOS虚拟环境

在macOS上重新创建干净的虚拟环境,确保依赖安装完整:

rm -rf venv
python3.10 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

激活环境后再运行pyinstaller audiotext.spec打包。

4. 调试依赖收集过程

添加调试日志查看依赖收集详情,定位缺失模块:

pyinstaller --log-level DEBUG audiotext.spec

根据日志中的WARNING: Missing module信息,针对性补充hiddenimports或钩子。

优化后的完整.spec示例

# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.compat import is_darwin, is_win
from PyInstaller.utils.hooks import copy_metadata, collect_all


datas = []
binaries = []
hiddenimports = []

# 批量收集第三方库资源
for pkg in ["transformers", "lightning", "lightning_fabric", "speechbrain", "pyannote", "asteroid_filterbanks", "whisperx", "librosa", "customtkinter", "torch", "speech_recognition", "moviepy", "dotenv", "openai"]:
    pkg_datas, pkg_binaries, pkg_hidden = collect_all(pkg)
    datas += pkg_datas
    binaries += pkg_binaries
    hiddenimports += pkg_hidden

# 收集元数据
datas += copy_metadata("tqdm")
datas += copy_metadata("regex")
datas += copy_metadata("requests")
datas += copy_metadata("packaging")
datas += copy_metadata("filelock")
datas += copy_metadata("numpy")
datas += copy_metadata("tokenizers")
datas += copy_metadata("pillow")
datas += copy_metadata("huggingface_hub")
datas += copy_metadata("safetensors")
datas += copy_metadata("pyyaml")
datas += copy_metadata("pydantic")

# 项目自有资源
datas += [("res", "res")]
datas += [("config.ini", ".")]
datas += [(".env", ".")]

# 额外隐式导入
hiddenimports += [
    "huggingface_hub.repository",
    "sklearn.utils._cython_blas",
    "sklearn.neighbors.typedefs",
    "sklearn.neighbors.quad_tree",
    "sklearn.tree",
    "sklearn.tree._utils",
    "darkdetect",
    "tkinter.font",
    "tkinter.ttk",
    "proglog",
    "imageio",
    "decorator",
]

block_cipher = None

debug = True
options = [("v", None, "OPTION")] if debug else []

a = Analysis(
    ["src/app.py"],
    pathex=[],
    binaries=binaries,
    datas=datas,
    hiddenimports=hiddenimports,
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

macos_icon = "res/macos/icon.icns"
windows_icon = "res/windows/icon.ico"

exe = EXE(
    pyz,
    a.scripts,
    options,
    exclude_binaries=True,
    name="Audiotext",
    debug=debug,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=debug,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file="res/macos/entitlements.plist" if is_darwin else None,
    icon=windows_icon if is_win else macos_icon,
)

coll = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name="Audiotext",
)

app = BUNDLE(
    coll,
    name="Audiotext.app",
    icon=macos_icon,
    bundle_identifier="com.henestrosadev.audiotext",
    version="2.3.0",
    info_plist={
        "NSPrincipalClass": "NSApplication",
        "NSAppleScriptEnabled": False,  # 修正原拼写错误
        "NSHighResolutionCapable": True,
        "NSMicrophoneUsageDescription": "Allow Audiotext to record audio from your microphone to generate transcriptions.",
    }
)

内容的提问来源于stack exchange,提问作者user15675885

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 03:45:54