Python 3.x Python3 CTypes在Mac 10.14(Mojave)上加载动态库时出错 背景

Python 3.x Python3 CTypes在Mac 10.14(Mojave)上加载动态库时出错 背景,python-3.x,macos,ctypes,python-c-api,dylib,Python 3.x,Macos,Ctypes,Python C Api,Dylib,我已经阅读了无数GitHub项目线程,以及我在StackOverflow上找到的关于这个问题的所有信息,尽管到目前为止还没有什么好运气。我有一个Mac10.14机器,运行着stock CommandLineTools和/或Xcode。我试图用Python 3中的cType来“端口”一个Python包装库,我用一个旧的C和C++库编写了这个库。它已经在Ubuntu Linux上运行良好。然而,自从搬到Mac平台以来,我遇到的问题没有结束。要修复我现在正在坏掉的Mac OS平台上尝试做的事情,似乎没

我已经阅读了无数GitHub项目线程,以及我在StackOverflow上找到的关于这个问题的所有信息,尽管到目前为止还没有什么好运气。我有一个Mac10.14机器,运行着stock CommandLineTools和/或Xcode。我试图用Python 3中的cType来“端口”一个Python包装库,我用一个旧的C和C++库编写了这个库。它已经在Ubuntu Linux上运行良好。然而,自从搬到Mac平台以来,我遇到的问题没有结束。要修复我现在正在坏掉的Mac OS平台上尝试做的事情,似乎没有一个简单的答案——至少对于像我这样不熟悉Linux的人来说是这样

在我描述如何编译我试图用CTypes加载的动态库之前,我有一个问题:我现在是否需要以某种方式对动态库进行签名,然后才能在Mac 10.14上使用它?否则,我想我的问题可以归结为$%^@(我现在的意思是截断的)如何使用Python C扩展接口处理Mac上的共享/动态库

我的偏好是甚至不接触Xcode,只使用系统自带的stock Mac工具。我的解决方案必须在命令行上运行,而不必遵从Xcode以GUI形式提供的一些自动配置魔法。实际上,对于Linux下的情况来说,这一切都相当轻松

汇编和链接 这个场景实际上比我所能描述的更复杂。在我看来,我将只是勾勒出解决方案的相关部分,然后让所有在这之前工作过的专家告诉我其中明显的错误

我首先使用以下方法将旧的C/C++源代码库编译为静态归档 Mac上的gcc(读取叮当声)选项(其中一些被忽略):

然后我正在编译并链接一个

-Wl,-all_load $(LIBGOMPSTATIC).a $(LIBGMPSTATIC) -Wl,-noall_load \
-ldl -lpthread -lc++ -lc++abi

生成动态库输出

为了进行比较,在Linux上,与这些标志类似的功能大致相同

-Wl,-export-dynamic -Wl,--no-undefined -shared -fPIC \
                        -fvisibility=default -Wl,-Bsymbolic
-Wl,-Bstatic -Wl,--whole-archive $(LIBGOMPSTATIC).a $(LIBGMPSTATIC) -Wl,--no-whole-archive \
                       -Wl,-Bdynamic -Wl,--no-as-needed -ldl -lpthread

动态库输出 上面的过程为我提供了一个动态库文件,我可以用
nm
扫描该文件,以查看我试图用CTypes导入的符号。这是一个良好的开端。当我试图运行testpython脚本来测试我的CTypes包装库时,我立即得到一个SEGFAULT。由于近来,
gdb
在Mac上显然是无用的(对不起),我使用库存的
llvm
加载了一个brew安装的python3,并带有额外的调试符号:

lldb /usr/local/Cellar/python-dbg\@3.7/3.7.6_13/bin/python3
(lldb) run myscript.py
Process 75435 launched: '/usr/local/Cellar/python-dbg@3.7/3.7.6_13/bin/python3' (x86_64)
Process 75435 stopped
* thread #2, stop reason = exec
    frame #0: 0x0000000100005000 dyld`_dyld_start
dyld`_dyld_start:
->  0x100005000 <+0>: popq   %rdi
    0x100005001 <+1>: pushq  $0x0
    0x100005003 <+3>: movq   %rsp, %rbp
    0x100005006 <+6>: andq   $-0x10, %rsp
Target 0: (Python) stopped.
(lldb) bt
* thread #2, stop reason = exec
  * frame #0: 0x0000000100005000 dyld`_dyld_start
(lldb) c

... redacted path information ...

File "/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 442, in LoadLibrary
    return self._dlltype(name)
  File "/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 364, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: dlopen(GTFoldPython.dylib, 6): image not found
Process 75435 exited with status = 1 (0x00000001)
lldb/usr/local/ceral/python dbg\@3.7/3.7.6_13/bin/python3
(lldb)运行myscript.py
流程75435已启动:'/usr/local/ceral/python-dbg@3.7/3.7.6_13/bin/python3'(x86_64)
进程75435已停止
*线程#2,停止原因=exec
帧0:0x0000000100005000 dyld`\u dyld\u开始
dyld`\u dyld\u开始:
->0x100005000:popq%rdi
0x10000501:pushq$0x0
0x10000503:movq%rsp,%rbp
0x10000506:andq$-0x10,%rsp
目标0:(Python)已停止。
(lldb)英国电信
*线程#2,停止原因=exec
*帧0:0x0000000100005000 dyld`\u dyld\u开始
(lldb)c
... 编辑的路径信息。。。
文件“/usr/local/ceral/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/_init__.py”,第442行,LoadLibrary中
返回自我类型(名称)
文件“/usr/local/ceral/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/_init__.py”,第364行,在_init中__
self.\u handle=\u dlopen(self.\u名称,模式)
OSError:dlopen(GTFoldPython.dylib,6):找不到映像
进程75435退出,状态为1(0x00000001)
我确实有每个环境变量
PYTHONAPPSDIR=/usr/local/ceral/python-dbg@3.7/3.7.6_13
PYTHONPATH
LD_库路径
DYLD_库路径
设置为正确路径


所以问题是我下一步要做什么才能让它工作?提前许许多多小时表示感谢

就我而言,问题是两件事

首先,我使用与C扩展链接的python不同的python版本运行python脚本。例如,下面是我的
python3 config--ldflags
命令的输出:

-L/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/config-3.7dm-darwin -lpython3.7dm -ldl -framework CoreFoundation
因此,使用
/usr/local/ceral/python运行它-dbg@3.7/3.7.6_13/bin/python3
给我造成了错误。这可以通过使用
/usr/local/ceral/python运行脚本来解决-dbg@3.7/3.7.6_13/bin/python3.7dm
。鉴于
brew
仅使用稍加修改的tap公式安装每一个,这不是一个明显的修复方案

其次,在我的C代码中,我经常向堆栈上的外部字符缓冲区写入代码。发生这种情况时,默认的
clang
堆栈保护机制会向脚本抛出SIGABRT。为了避免这种情况,您可以通过向编译器和链接器传递以下标志来重新编译(可能比实际需要的更禁用):

有了这两个补丁,我的脚本就可以运行了。由于与C中的Python多线程相关的其他原因,仍然会崩溃。然而,这是意料之中的,但在我的Linux测试中仍然没有出现


感谢@l'l'l帮助我解决了这个问题。

这个函数
ctypes.PyDLL(“mylib.so”)
在Linux上对我有用,但在Mac上不行。至少有时它会启动调用
ctypes.LoadLibrary(“dylib.dylib”)
。如果有帮助的话,我可以在CTypes中发布更多Python包装器代码。什么是
GTFoldPython.dylib
?似乎找不到dylib。dylib
GTFoldPython.dylib
是我创建的动态库(在上面的注释中称之为
mylib.dylib
)。它位于我在帖子中的环境变量路径中。你知道我是否需要对动态库签名以打开它并在Mojave++上使用它吗?我必须通过创建软件签名证书的过程来使用
gdb
(大概
lldb
是这样自动配置的
-Wl,-soname,$(MODULENAME)
lldb /usr/local/Cellar/python-dbg\@3.7/3.7.6_13/bin/python3
(lldb) run myscript.py
Process 75435 launched: '/usr/local/Cellar/python-dbg@3.7/3.7.6_13/bin/python3' (x86_64)
Process 75435 stopped
* thread #2, stop reason = exec
    frame #0: 0x0000000100005000 dyld`_dyld_start
dyld`_dyld_start:
->  0x100005000 <+0>: popq   %rdi
    0x100005001 <+1>: pushq  $0x0
    0x100005003 <+3>: movq   %rsp, %rbp
    0x100005006 <+6>: andq   $-0x10, %rsp
Target 0: (Python) stopped.
(lldb) bt
* thread #2, stop reason = exec
  * frame #0: 0x0000000100005000 dyld`_dyld_start
(lldb) c

... redacted path information ...

File "/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 442, in LoadLibrary
    return self._dlltype(name)
  File "/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 364, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: dlopen(GTFoldPython.dylib, 6): image not found
Process 75435 exited with status = 1 (0x00000001)
-L/usr/local/Cellar/python-dbg@3.7/3.7.6_13/Frameworks/Python.framework/Versions/3.7/lib/python3.7/config-3.7dm-darwin -lpython3.7dm -ldl -framework CoreFoundation
-fno-stack-check -fno-stack-protector -no-pie -D_FORTIFY_SOURCE=0