【发布时间】:2018-08-29 19:43:44
【问题描述】:
我使用dlopen 和RTLD_LOCAL 动态加载Python,以避免与巧合包含一些同名符号的另一个库发生冲突。使用 Xcode 在 macOS 上执行我上面的 MVCE 失败,因为它需要全局命名空间中的 _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 会覆盖两级命名空间吗?
我使用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;
}
【问题讨论】:
标签: python c++ macos linker symbols