Я пытаюсь связать разделяемую библиотеку с помощью механизма ctypes
в Python. Это хорошо работает с обычными библиотеками, но теперь мне приходится иметь дело с библиотекой, которая расширяет свои собственные функции с помощью набора плагинов. Когда я загружаю эту библиотеку, используя
import ctypes
lib = ctypes.cdll.LoadLibrary('./liblibrary.so')
, она сначала инициализирует все найденные плагины. И в этой ситуации плагины пытаются получить доступ к символам в liblibrary.so
, которые не найдены. Если я использую его из программы C и связываю liblibrary
как обычный общий объект, все работает как шарм. liblibrary.so
связан с включенным флагом --export-dynmaic
.
Вот минимальный рабочий пример: liblibrary. c:
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
typedef int (*func_t)(int);
static int verbosity = 0;
static func_t worker;
__attribute__((constructor))
void lib_init()
{
void * handle;
dlerror();
handle = dlopen("./plugin.so", RTLD_NOW);
if (!handle) {
fprintf(stderr, "error open: %s\n", dlerror());
abort();
}
dlerror();
worker = (func_t) dlsym(handle, "worker_function");
if (!worker) {
fprintf(stderr, "error dlsym: %s\n", dlerror());
abort();
}
}
int lib_getverbosity()
{
return verbosity;
}
void lib_setverbosity( int _v )
{
verbosity = _v;
}
int lib_work(int v)
{
return worker(v);
}
Вот пример плагина:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
extern int lib_getverbosity();
extern int lib_setverbosity(int v);
int worker_function(int v)
{
int verb = lib_getverbosity();
printf("verbosity (plugin) : %d \n", v);
return v * v;
}
и Makefile:
all: liblibrary.so plugin.so
liblibrary.so: liblibrary.c
gcc -shared -O2 -fPIC -g -rdynamic -Wl,--export-dynamic liblibrary.c -o liblibrary.so
plugin.so:
gcc -shared -O2 -fPIC -g -rdynamic -Wl,--export-dynamic plugin.c -o plugin.so
clean:
rm *.so
.PHONY: clean
Теперь, когда я запускаю код Python, я получаю:
>>> import ctypes
>>> ctypes.cdll.LoadLibrary('./liblibrary.so')
error open: ./plugin.so: undefined symbol: lib_getverbosity
Почему это происходит и как могу ли я предотвратить это?
Удаление автоматической инициализации или превращение ее в функцию, которая должна быть вызвана пользователем, не является вариантом, поскольку в моем приложении это сломает очень старый API / ABI .
Если посмотреть глубже в liblibrary.so
с помощью readelf, вы увидите:
readelf --dyn-syms library.so
Symbol table '.dynsym' contains 15 entries:
Num: Wert Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND dlopen
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND abort@GLIBC_2.2.5 (2)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND dlerror
6: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND dlsym
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __fprintf_chk@GLIBC_2.3.4 (3)
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
9: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2)
10: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND stderr@GLIBC_2.2.5 (2)
11: 0000000000001230 11 FUNC GLOBAL DEFAULT 14 lib_setverbosity
12: 00000000000010e0 128 FUNC GLOBAL DEFAULT 14 lib_init
13: 0000000000001240 10 FUNC GLOBAL DEFAULT 14 lib_work
14: 0000000000001220 11 FUNC GLOBAL DEFAULT 14 lib_getverbosity
Что выглядит нормально.