在 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
和 -l
,libbaz.so
将不会像 libbar.so
.
那样依赖于任何共享对象
我想创建动态 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
和 -l
,libbaz.so
将不会像 libbar.so
.