在以dlopen方式打开另一个C库的Python中加载C库-未解析的共享符号

时间:2018-07-26 17:00:46

标签: python c linux ctypes dlopen

我有一个商业c库(a.so),它具有多个功能。当您调用a.open()函数时,它将动态地对另一个库执行dlopen()调用。如果调用a.open('b'),它将打开b.so。如果调用a.open('c'),它将打开c.so。

问题是a.so和b.so共享一个在a.so中定义的全局变量,但被b.so(和c.so等)引用。我能够使用ctypes在python中正确加载a.so并查看Python中的所有符号。但是,当我调用a.open('b')时,它将尝试加载b.so但返回未定义的符号。

//a.c -source for a.so library
int aglobal = 0;
void open(char* lib)
{ dlopen(lib); }

//b.c - source for b.so library
extern int aglobal;

这是我要加载的python代码:

from ctypes import cdll
p = ctypes.CDLL('a.so')
p.open('b')

返回错误代码:未定义的符号:aglobal

其他一些注意事项:

  • 文件与-fPIC -rdynamic -shared

  • 链接
  • 当我编写一个与python程序相同的C程序时, 没问题。

  • 我还尝试了swig来包装库以及其他许多东西,构建选项等,但是结果相同。

Python是否以不同的方式绑定符号?

1 个答案:

答案 0 :(得分:2)

加载a.so时需要使用RTLD_GLOBAL

  

该对象的符号应可用于任何其他对象的重定位处理。此外,使用dlopen(0, mode)和关联的dlsym()进行符号查找允许搜索以这种模式加载的对象。

Linux man page更加简单:

  

将创建此共享库定义的符号                 可用于后续加载共享的符号解析                 对象。

python documentation描述了选项的存在,但没有描述其作用。

  

2.6版中的新增功能:添加了use_last_error和use_errno可选参数。

     

ctypes.RTLD_GLOBAL
  标记用作模式参数。在此标志不可用的平台上,它定义为整数零。

     

ctypes.RTLD_LOCAL
  标记用作模式参数。在不可用的平台上,它与RTLD_GLOBAL相同。

     

ctypes.DEFAULT_MODE
  用于加载共享库的默认模式。在OSX 10.3上,该值为RTLD_GLOBAL,否则与RTLD_LOCAL相同。

从文档中可以看出,您所处的系统上DEFAULT_MODERTLD_LOCAL相同,这与RTLD_GLOBAL相反。