让我们说libl1.so
,libl2.so
和libl3.so
都包含函数f
。
在没有使用{{1>的情况下,是否真的无法将所有这些f
(从libl1.so
,libl2.so
和libl3.so
)链接到我的程序中}}?
我甚至同意使用一些包装器库 - 但我仍然需要最终链接到dlopen
,libl1.so
和libl2.so
本身(而不是他们修改后的副本) 子>
P.S。:尝试澄清this问题。
答案 0 :(得分:0)
稍加注意,可以将dlopen
与链接到应用程序的共享库一起使用。
dlopen
尝试返回已加载的共享对象的句柄。只要共享对象被正确命名,如果由于链接符号而加载它,则使用dlopen
将不会导致它再次加载。
一个例子可以说明这一点。
以下是三个几乎完全相同的库。每个定义一个名为f
的函数和另一个具有唯一名称的函数。 (它们还有非导出的初始值设定项,我添加了这些,以便加载可见。):
#include <stdio.h>
int f() { return puts("I'm f1::f"); }
int f1_g() { return puts("I'm f1_g"); }
static void init() __attribute__((constructor));
void init() { puts("Initializing f1"); }
#include <stdio.h>
int f() { return puts("I'm f2::f"); }
int f2_g() { return puts("I'm f2_g"); }
static void init() __attribute__((constructor));
void init() { puts("Initializing f2"); }
#include <stdio.h>
int f() { return puts("I'm f3::f"); }
int f3_g() { return puts("I'm f3_g"); }
static void init() __attribute__((constructor));
void init() { puts("Initializing f3"); }
这些编译成共享对象,指定每个共享对象的soname:
for i in f1 f2 f3; do
gcc -Wall --shared -Wl,--soname=lib$i.so -fPIC -o lib$i.so $i.c
done
这是一个显式引用两个唯一函数名的main函数,但依赖于dlopen / dlsym来使用具有通用名称的函数。 (它指的是两个唯一的名称,而不是三个,以显示加载行为的差异,但仍然是透明的)。请注意,使用dlopen加载的库名称不包含斜杠,因此它们将与已加载的具有相同soname的库匹配。
#include <stdio.h>
#include <dlfcn.h>
extern int f1_g();
extern int f2_g();
extern int f3_g();
int (*f1_f)();
int (*f2_f)();
int (*f3_f)();
int main() {
puts("Loading f1");
f1_f = dlsym(dlopen("libf1.so", RTLD_NOW), "f");
puts("Loading f2");
f2_f = dlsym(dlopen("libf2.so", RTLD_NOW), "f");
puts("Loading f3");
f3_f = dlsym(dlopen("libf3.so", RTLD_NOW), "f");
f1_f();
f1_g();
f2_f();
f2_g();
f3_f();
// f3_g(); /* We don't explicitly use f3_g, so f3.so is not linked */
return 0;
}
现在,我们编译并运行它:
$ # Need to specify -L in the build and LD_LIBRARY_PATH when running
$ # because . is not in the default library search path.
$ gcc -o main -Wall main.c -L. -lf1 -lf2 -lf3 -ldl
$ LD_LIBRARY_PATH=. ./main
Initializing f2
Initializing f1
Loading f1
Loading f2
Loading f3
Initializing f3
I'm f1::f
I'm f1_g
I'm f2::f
I'm f2_g
I'm f3::f
因此,f1
和f2
会在main
开始之前加载(并初始化),因为明确使用的函数f1_g
和f2_g
需要它们。当请求这些共享对象的句柄时(使用dlopen
),不会再次加载库。但是,dlopen
对libf3.so
的调用未在可执行文件中找到共享对象,因此通过调用dlopen
加载(并初始化)。
随后,调用所有函数并获取各种f
函数的预期版本。