在 C++ 中为共享对象添加动态依赖

Add dynamic dependency to shared object in C++

我想创建动态 link 到共享对象 A 的共享对象 B。我正在使用以下命令编译共享对象 B:

g++ -fPIC -shared -L/path/to/directory -lA -o libB.so B.cpp

据我了解,-lA 告诉 linker libB.so 应该动态地 link 到 /path/to/directory/libA.so。但是,当我对最终产品执行 ldd 时,未列出依赖项(由于缺少这些依赖项,加载 libB.so 失败)。

ldd libB.so

linux-vdso.so.1 =>  (0x00007ffd4233e000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f35072fe000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f35070e7000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3506de1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3506a1c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3507807000)

我对 -l 应该做什么有错吗?我假设以上是 C++ 的最小动态依赖集。

是否有任何陷阱需要寻找?例如,当 linker 找不到文件或其他东西时,它是否会简单地忽略 -l 请求(而且我必须比现有路径更多地调试我的路径)?

我是否必须在我的 C++ 代码中放置一些东西来指示依赖性(例如 "extern" 函数或其他东西)?

更新:

我确定 ld 报告的动态依赖集 确实 依赖于我的 C++ 代码并且 似乎不 取决于我提供的任何 -L-l 标志。 linker 会自动猜测我的 libB.so 应该依赖哪些共享对象,而且它的假设还不够。

例如,我知道我需要 B 来加载 A,因为我调用了一些最终调用 libA.so 中的代码的代码。我如何向 link 人员提供此信息?

说明:

我所说的 "shared object A" 是一个复杂的东西,可能会动态加载一些代码。我想包含足够的依赖项,以便它在尝试动态加载此代码时不会因 "missing symbols" 而失败。这就是为什么我想在 B 中强制依赖,因为 linker 可能无法在依赖树中静态地找到它们。

此外,我使用的是 g++ 4.8.4 (Ubuntu 14.04)。这是相关的,因为 g++ 从 4.6 版开始隐式应用 -Wl,--as-needed

您正在编译一个奇怪的对象名称。创建可执行文件时将发生链接。 然后你不得不提到你的各种对象和库。

可能 ldd 的输出中没有列出相关性,因为 libA.so 中没有找到 B.cpp 中使用的符号。这可能是因为 C++ 符号名称混淆:如果 libA.so 已被 C 编译器编译,它可能会将函数 void foo() 的符号存储在漂亮名称 foo 下,而 C++ 编译器会混淆它变成类似 _Z3foov 的东西。您可以使用以下命令检查它:

$ # Replace "SomeSharedObject" with the actual name of symbol exported by libA.so.
$ strings libA.so | grep SomeSharedObject
$ strings libB.so | grep SomeSharedObject

为避免这种情况,可以将符号 foo 的声明放入 extern "C" {} 子句中。然后编译器不会破坏这个名字,链接器可能会在 libA.so.

中找到这个名字

-l 选项在实验室环境中如您预期的那样工作:

$ cat bar.cpp 
extern void foo();

void bar()
{
    foo();
}
$ cat baz.cpp 
extern void bar();

void baz()
{
    bar();
}
$ # Link against libssl.so (OpenSSL).
$ # Obviously libssl.so is unnecessary in libbar.so.
$ g++ -fPIC -shared bar.cpp -o libbar.so -lssl 
$ ldd libbar.so 
    statically linked
$ # Link against libbar.so in the current directory
$ g++ -fPIC -shared baz.cpp -o libbaz.so -L`pwd` -lbar
$ ldd libbaz.so 
    linux-vdso.so.1 =>  (0x00007fff7cfe2000)
    libbar.so => not found

这里libbar.so依赖函数foo。但是在任何图书馆都没有找到它,包括 libssl.so。因此 ldd 将共享对象 libbar.so 报告为 "statically linked"。在生成 libbar.so 时未找到的所有符号,将在创建依赖于 libbar.so.

的最终可执行文件时进行搜索

反过来,libbaz.so 依赖于 libbar.so,因为函数 void bar() 是在我们通过 -l 选项指定的上述共享对象中找到的。如果我们省略 -L 选项,链接器将报告类似 -lbar: not found 的错误。如果我们省略 -L-llibbaz.so 将不会像 libbar.so.

那样依赖于任何共享对象