恐怕这些答案都不是我能接受的。因为这些答案并没有解决问题。他们中的一些人是幸运的,或者误解了,甚至是错误的。所以我将提供我自己的解决方案并详细解释问题。
dylib 加载无效。客户端不应加载未版本化的 libcrypto dylib,因为它没有稳定的 ABI。
根本原因本身就很清楚。您的 Python 正试图打开(由 dlopen)一个名为 libcrypto 的未版本化 OpenSSL 共享库。自 Catalina 以来,出于安全原因,Apple 不允许任何人使用它。所以解决方案很简单。只是使用版本控制 OpenSSL。
我编写了一个名为openlib.py 的python 脚本来重现该问题。
import sys
from ctypes.util import find_library
from ctypes import CDLL
name = sys.argv[1]
path = find_library(name)
print(f"path: {path}")
lib = CDLL(path)
我这里使用系统 Python 进行演示
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.7
BuildVersion: 19H15
$ /usr/bin/python3 --version
Python 3.8.2
$ ls -al /usr/lib/ | grep 'libcrypto\|libssl'
.rwxr-xr-x 1.1M root 22 Sep 8:29 libcrypto.0.9.7.dylib
.rwxr-xr-x 1.4M root 22 Sep 8:29 libcrypto.0.9.8.dylib
.rwxr-xr-x 1.5M root 22 Sep 8:29 libcrypto.35.dylib
.rwxr-xr-x 1.5M root 22 Sep 8:29 libcrypto.41.dylib
.rwxr-xr-x 1.5M root 22 Sep 8:29 libcrypto.42.dylib
.rwxr-xr-x 1.5M root 22 Sep 8:29 libcrypto.44.dylib
.rwxr-xr-x 32k root 22 Sep 8:29 libcrypto.dylib
.rwxr-xr-x 212k root 22 Sep 8:29 libssl.0.9.7.dylib
.rwxr-xr-x 335k root 22 Sep 8:30 libssl.0.9.8.dylib
.rwxr-xr-x 330k root 22 Sep 8:28 libssl.35.dylib
.rwxr-xr-x 313k root 22 Sep 8:29 libssl.43.dylib
.rwxr-xr-x 300k root 22 Sep 8:29 libssl.44.dylib
.rwxr-xr-x 294k root 22 Sep 8:29 libssl.46.dylib
.rwxr-xr-x 32k root 22 Sep 8:29 libssl.dylib
$ /usr/bin/python3 openlib.py libcrypto
path: /usr/lib/libcrypto.dylib
Abort trap: 6
$ /usr/bin/python3 openlib.py libcrypto.35
path: /usr/lib/libcrypto.35.dylib
$ /usr/bin/python3 openlib.py libcrypto.44
path: /usr/lib/libcrypto.44.dylib
如您所见。 Python 已崩溃,参数 libcrypto 如下诊断报告所示。看起来很相似,对吧?宾果游戏!
Process: Python [97291]
Path: /Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/Resources/Python.app/Contents/MacOS/Python
Identifier: Python
Version: 3.8.2 (3.8.2)
Build Info: python3-73040006000000~117
Code Type: X86-64 (Native)
Parent Process: bash [84388]
Responsible: iTerm2 [7705]
User ID: 501
Date/Time: 2020-12-26 00:28:00.281 +0800
OS Version: Mac OS X 10.15.7 (19H15)
Report Version: 12
Anonymous UUID: 1C43F3DB-1783-4B94-B663-7F7E8D331B56
Time Awake Since Boot: 53000 seconds
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Application Specific Information:
/usr/lib/libcrypto.dylib
abort() called
Invalid dylib load. Clients should not load the unversioned libcrypto dylib as it does not have a stable ABI.
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x00007fff69bba33a __pthread_kill + 10
1 libsystem_pthread.dylib 0x00007fff69c76e60 pthread_kill + 430
2 libsystem_c.dylib 0x00007fff69b41808 abort + 120
3 libcrypto.dylib 0x00007fff6766b7e4 __report_load + 415
基于您的 Python /usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python 的路径。显然,您的 Python 是由 Homebrew 安装的。我相信 Homebrew Python 3 一直是linked with keg-only OpenSSL。所以肯定是一些包使用了未版本化的 OpenSSL。查看文件ctypes/macholib/dyld.py2。它按指定顺序搜索以下目录中的任何库:
DEFAULT_LIBRARY_FALLBACK = [
os.path.expanduser("~/lib"),
"/usr/local/lib",
"/lib",
"/usr/lib",
]
$ /usr/bin/python3
Python 3.8.2 (default, Nov 4 2020, 21:23:28)
[Clang 12.0.0 (clang-1200.0.32.28)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes.util import find_library
>>> find_library('libcrypto')
'/usr/lib/libcrypto.dylib'
>>>
因此,简单的解决方法是将版本控制 OpenSSL 链接到主目录中的库路径。
$ pwd
/Users/gasolwu
$ ln -s /usr/lib/libcrypto.44.dylib $HOME/lib/libcrypto.dylib
$ $ ls ~/lib
libcrypto.dylib
之后。通过运行提供的脚本 openlib.py 来测试打开 OpenSSL。它成功返回库路径而不会崩溃。
$ /usr/bin/python3 openlib.py libcrypto
path: /Users/gasolwu/lib/libcrypto.dylib
我也使用Homebrew Python 3。所以我几天前修复了它并发送了a pull request。如果你已经升级到最新版本的 Python 并且如果 PR 已经合并并且瓶子已经构建和发布。只需使用brew reinstall python@3.9 运行命令将是解决问题的最简单方法。
不要通过禁用 SIP 并使用 sudo 覆盖您的系统 OpenSSL 来破坏您的系统。
不要安装浪费磁盘空间的重复库。无需在任何位置安装另一个 OpenSSL。
不要使用环境变量DYLD_LIBRARY_PATH,如下所示。如果你不将这一行添加到你的shell配置中,你必须每次都声明。如果这样做,它将影响您机器上的每个程序。
export DYLD_LIBRARY_PATH=/usr/local/opt/openssl/lib:$DYLD_LIBRARY_PATH
最后。 如果您通过更新 python 依赖项解决了问题。你可能很幸运。一些软件包通过寻找版本控制 OpenSSL 解决了这个问题。但很多不是。