考虑以下文件
# Makefile
all: libdyn.so libmain.so app
libdyn.so: libdyn.cpp
g++ -fPIC -shared -o libdyn.so libdyn.cpp
libso.so: libso.cpp
g++ -fPIC -shared -o libso.so libso.cpp
libmain.so: libmain.cpp libso.so
g++ -Wl,--no-as-needed -fPIC -shared -o libmain.so libmain.cpp -ldl -L`pwd` -lso
app: main.cpp g++ -o app main.cpp -ldl
g++ -o app main.cpp -ldl
// libdyn.cpp
#include <iostream>
extern "C" {
extern void foo();
void bar() {
std::cout << "Calling foo..." << std::endl;
foo();
}
};
// libso.cpp
#include <iostream>
extern "C" {
void foo() {
std::cout << "Hello from foo" << std::endl;
}
};
// libmain.cpp
#include <iostream>
#include <dlfcn.h>
int main_fun() {
void* handle = dlopen("./libdyn.so", RTLD_LAZY);
void (*bar_ptr)() = reinterpret_cast<void(*)()>(dlsym(handle, "bar"));
std::cout << "Calling bar..." << std::endl;
(*bar_ptr)();
return 0;
}
// main.cpp
#include <iostream>
#include <dlfcn.h>
int main() {
void* handle = dlopen("./libmain.so", RTLD_LAZY);
int (*main_fun_ptr)() = reinterpret_cast<int(*)()>(dlsym(handle, "_Z8main_funv"));
std::cout << "Calling main_fun..." << std::endl;
(*main_fun_ptr)();
}
调用./app
产生
Calling main_fun...
Calling bar...
Calling foo...
./app: symbol lookup error: ./libdyn.so: undefined symbol: foo
CCD_ 2产生
linux-vdso.so.1 (0x00007ffd903f8000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe05cdb8000)
libso.so (0x00007fe05cdb3000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe05cb99000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe05ca4a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe05ca2f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe05c83b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe05cddf000)
我不明白为什么libdyn
不能访问foo
。libmain
链接到提供foo
的libso
,而libdyn
是由libmain
加载的,那么不应该找到foo
吗?
我对解决这个问题很感兴趣,但也有一些限制。可以怀疑,这是我真正问题的MWE。在我的应用程序中,libmain.so
是使用Java Native Interface调用的。此外,只有libmain
是用户代码。libso
和libdyn
是外部库,对我来说很难重新编译,但这是可行的。最后,没有一个foo
函数,而是必须以foo
的共享方式共享数千个全局变量。
在main.cpp
中,使用dlopen中的openRTLD_GLOBAL
。
来自手册:
RTLD_GLOBAL
The symbols defined by this shared object will be
made available for symbol resolution
of subsequently loaded shared objects.
编辑:或者,不将libso.so
作为依赖项链接到ldd libmain.so
0,而是从main_fun
:调用dlopen
dlopen("libso.so", RTLD_LAZY|RTLD_GLOBAL)
或者可能来自共享对象初始化器:
static void init(void) __attribute__((constructor));
static void init(void) {
fprintf(stderr, "libmain constructor %s runningn", __func__);
if (!dlopen("libso.so", RTLD_LAZY|RTLD_GLOBAL)) {
fprintf(stderr, "dlopen("libso.so"): *** %sn", dlerror());
exit(1);
}
}