使用Py2app打包含Tkinter/Excel的Python脚本时遇dyld链接错误
看起来你在打包带PIL(Pillow)的Python应用时遇到了动态库依赖的典型问题,别担心,我们一步步来搞定它:
问题根源
错误提示libopenjp2.2.3.1.dylib找不到,是因为Py2app打包时没有正确处理PIL的这个依赖库——要么没把它复制到App包的正确位置,要么_imaging.so里的库引用路径不对。你之前用install_name_tool修改主程序的Cocoa路径完全搞错了方向,Cocoa是macOS自带的系统UI框架,根本不需要修改它的路径~
解决方案步骤
1. 先确认依赖库的位置
首先找到你的Python环境里libopenjp2.2.3.1.dylib的实际位置,打开终端运行:
find /Library/Frameworks/Python.framework -name "libopenjp2*"
(如果是用conda或者pyenv,就换成对应的环境路径)
找到后,把这个文件复制到你的App包的Contents/Frameworks目录下:
cp /path/to/your/libopenjp2.2.3.1.dylib "/Users/James/Documents/Python/Projects/Budget/dist/automating_finances0.app/Contents/Frameworks/"
2. 修改_imaging.so的依赖路径
问题出在_imaging.so里的库引用指向了错误的位置,我们需要用install_name_tool修正它的路径:
install_name_tool -change "@loader_path/.dylibs/libopenjp2.2.3.1.dylib" "@loader_path/../../../../Frameworks/libopenjp2.2.3.1.dylib" "/Users/James/Documents/Python/Projects/Budget/dist/automating_finances0.app/Contents/Resources/lib/python3.8/lib-dynload/PIL/_imaging.so"
解释下路径:_imaging.so在Resources/lib/python3.8/lib-dynload/PIL/目录,@loader_path就是这个目录,../../../../会回到App的Contents目录,再指向Frameworks里的库,这样就能找到正确的文件了。
3. 验证修改是否成功
运行下面的命令检查_imaging.so的依赖:
otool -L "/Users/James/Documents/Python/Projects/Budget/dist/automating_finances0.app/Contents/Resources/lib/python3.8/lib-dynload/PIL/_imaging.so"
如果看到libopenjp2.2.3.1.dylib的路径变成了@loader_path/../../../../Frameworks/libopenjp2.2.3.1.dylib,就说明修改成功了。
4. (可选)用Py2app自带工具自动修复
Py2app有个fix_frameworks脚本可以尝试自动修复依赖问题,运行:
python -m py2app.fix_frameworks "/Users/James/Documents/Python/Projects/Budget/dist/automating_finances0.app"
这个工具会自动调整App包内所有动态库的引用路径,可能一步到位解决问题。
额外提醒:优化打包配置
下次打包时,可以在setup.py里添加参数,让Py2app更好地收集依赖:
from setuptools import setup APP = ['your_script.py'] OPTIONS = { 'includes': ['PIL', 'openpyxl'], # 明确指定用到的库 'frameworks': ['libopenjp2.2.3.1.dylib'], # 强制包含这个库 } setup( app=APP, options={'py2app': OPTIONS}, setup_requires=['py2app'], )
这样打包时Py2app会自动处理这个依赖,避免手动修改的麻烦。
内容的提问来源于stack exchange,提问作者margaritababy

