我动态加载Pythondlopen
and RTLD_LOCAL
以避免与另一个库发生冲突,该库碰巧包含一些同名的符号。执行我的MVCE上面在 macOS 上使用 Xcode 失败了,因为它期望_PyBuffer_Type
在全局命名空间中。
Traceback (most recent call last):
File "...lib/python2.7/ctypes/__init__.py", line 10, in <module>
from _ctypes import Union, Structure, Array
ImportError: dlopen(...lib/python2.7/lib-dynload/_ctypes.so, 2):
Symbol not found: _PyBuffer_Type
Referenced from: ...lib/python2.7/lib-dynload/_ctypes.so
Expected in: flat namespace
in ...lib/python2.7/lib-dynload/_ctypes.so
Program ended with exit code: 255
但为什么?做RTLD_LOCAL
覆盖二级命名空间?
I used otool -hV
检查 _ctypes.so 是否使用两级命名空间选项进行编译。根据我的理解,符号解析需要库名称+符号名称本身。为什么它期望_PyBuffer_Type
在平面命名空间中和/或为什么找不到它?看TWOLEVEL
向右滚动
> otool -hV /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_ctypes.so
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 X86_64 ALL 0x00 BUNDLE 14 1536 NOUNDEFS DYLDLINK TWOLEVEL
知道这是怎么回事吗?
MVCE
可以复制到新的Xcode项目中,只需编译并执行即可。
#include </System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7/Python.h>
#include <dlfcn.h>
int main(int argc, const char * argv[])
{
auto* dl = dlopen("/System/Library/Frameworks/Python.framework/Versions/2.7/Python", RTLD_LOCAL | RTLD_NOW);
if (dl == nullptr)
return 0;
// Load is just a macro to hide dlsym(..)
#define Load(name) ((decltype(::name)*)dlsym(dl, # name))
Load(Py_SetPythonHome)("/System/Library/Frameworks/Python.framework/Versions/2.7");
Load(Py_Initialize)();
auto* readline = Load(PyImport_ImportModule)("ctypes");
if (readline == nullptr)
{
Load(PyErr_Print)();
dlclose(dl);
return -1;
}
Py_DECREF(readline);
Load(Py_Finalize)();
return 0;
}