我们可以在上面的命令中省略 -ldependency
如果你控制libutils.so本身的链接,是的,你可以。插图:
main.c
extern void foo(void);
int main(void)
{
foo();
return 0;
}
foo.c
extern void bar(void);
void foo(void)
{
bar();
}
bar.c
#include <stdio.h>
void bar(void)
{
puts(__func__);
}
我们将创建一个依赖于libfoo.so 的程序,该程序依赖于libbar.so。
制作目标文件:
$ gcc -Wall -c -fPIC foo.c bar.c
gcc -Wall -c main.c
现在链接libbar.so 简洁的方式:
$ gcc -shared -o libbar.so bar.o
下一个链接libfoo.so这样:
$ gcc -shared -o libfoo.so foo.o -L. -lbar -Wl,-rpath=$(pwd)
-rpath linker option的效果是:
-rpath=目录
将目录添加到运行时库搜索路径。这在将 ELF 可执行文件与共享对象链接时使用。
所有 -rpath 参数都连接起来并传递给运行时链接器,运行时链接器使用它们在运行时定位共享对象。
-rpath 选项也用于定位明确包含在链接中的共享对象所需的共享对象;
请参阅 -rpath-link 选项的说明。如果在链接 ELF 可执行文件时未使用 -rpath,
如果定义了环境变量 LD_RUN_PATH 的内容将被使用。
结果是:
$ objdump -x -j .dynamic libfoo.so | egrep '(RUNPATH|NEEDED)'
NEEDED libbar.so
RUNPATH /home/imk/develop/so/scrap
libfoo.so 在其.dynamic 部分中有一个NEEDED 条目,说明
该库对libbar.so 具有运行时依赖项。同样它有
那里有一个RUNPATH 条目,表示可以在/home/imk/develop/so/scrap 中搜索运行时依赖项
那只是我进行链接的pwd:不一定是这样,只要确实如此
当链接器或加载器来寻找它时,可以找到libbar.so 的目录。
链接器可以读取此信息,当libbar.so 与其他内容链接时,
并在运行时由加载程序。所以最后我可以像这样链接prog:
$ gcc -o prog main.o -L. -lfoo -Wl,-rpath=$(pwd)
-lbar 就不用提了,因为libfoo.so 本身就为链接器提供了
libfoo.so 依赖于 libbar.so 的信息,以及在哪里寻找它。
由于我在prog的链接中也通过了-rpath=$(pwd),所以我们看到了prog
将提供此信息
$ objdump -x -j .dynamic prog | egrep '(RUNPATH|NEEDED)'
NEEDED libfoo.so
NEEDED libc.so.6
RUNPATH /home/imk/develop/so/scrap
到运行时加载器:prog需要libfoo.so,可以找
在/home/imk/develop/so/scrap。当加载器找到libfoo.so并加载它时,它会
从中发现:
NEEDED libbar.so
RUNPATH /home/imk/develop/so/scrap
然后会找到并加载libbar.so,这将使它能够解析所有
施工过程中引用的符号。因此,prog 可以立即运行:
$ ./prog
bar
我没有有在prog 的链接中传递-rpath=$(pwd)。但如果我没有:
$ gcc -o prog main.o -L. -lfoo
$ ./prog
./prog: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
加载程序不知道在哪里可以找到libfoo.so。见:
$ ldd prog
linux-vdso.so.1 (0x00007ffffcc35000)
libfoo.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4d1aff9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4d1b5ec000)
然后我不得不求助于:
$ export LD_LIBRARY_PATH=.
$ ldd prog
linux-vdso.so.1 (0x00007fff964dc000)
libfoo.so => ./libfoo.so (0x00007fc2a7f35000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc2a7b44000)
libbar.so => ./libbar.so (0x00007fc2a7942000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc2a8339000)
$ ./prog
bar
稍后
ldd libutils.so 的输出中是否存在 libdependency.so 是否足以在链接期间省略 -ldependencny 尚不清楚
关于ldd utils.so:-
-
ldd libutils.so 输出是否报告了别名 libdependency.so?
- 如果 1 为“是”,它是否也会将该 so-name 解析为实际文件?
如果 1 为否,则 libdutils.so 不包含有关其对 libdependency.so 的依赖性的信息
并且您必须在任何进一步的链接中指定-lutils -ldependency。
如果对 1 表示“是”但对 2 表示“否”(即ldd libutils.so 报告libdependency.so => not found),则libutils.so 有
一个名为libdependency.so 的NEEDED 条目,但不是一个RUNPATH 条目,链接器或
loader 可以将该名称解析为任何实际文件。在这种情况下,如果链接-lutils,则必须链接-lutils -ldependency,以便链接器然后搜索解析-ldependency 的文件。至少,只要在您进行链接时ldd libutils.so 仍然 报告libdependency.so => not found,您就必须这样做。继续阅读...
如果 1 是“是”,2 是“是”,那么您可以在进一步的链接中删除 -ldependency,前提是它是
在你运行的相同环境中运行 ldd libutils.so
这个警告是必要的,因为如果ldd libutils.so 解析为libdependency.so,你就知道
是ldd 能够使用加载程序的搜索算法解析libdependency.so:-
-
LD_LIBRARY_PATH 环境变量(在活动 shell 中)列出了一个目录
在其中找到libdependency.so,或
-
libutils.so 提供了一个 RUNPATH,其中找到了 libdependency.so,或者
-
libdependency.so 位于/etc/ld.so.conf(或其递归include-扩展)中列出的目录之一中,或
-
libdependency.so 位于加载程序的受信任搜索目录之一,/lib 和 /usr/lib
如果ldd 可以通过这四种方式之一解析libdependency.so,那么链接器将能够
以同样的方式进行操作,只要在您进行链接时该方式仍然成功。
回到我的例子和我的链接:
$ gcc -shared -o libfoo.so foo.o -L. -lbar -Wl,-rpath=$(pwd)
在那之后,感谢-rpath=$(pwd)。我可以链接prog 喜欢:
$ gcc -o prog main.o -L. -lfoo
不提-lbar,就成功了。现在我链接libfoo.so 而不是没有
-rpath:
$ gcc -shared -o libfoo.so foo.o -L. -lbar
之后:
$ objdump -x -j .dynamic libfoo.so | egrep '(RUNPATH|NEEDED)'
NEEDED libbar.so
不再有RUNPATH,因此:
$ ldd libfoo.so
linux-vdso.so.1 (0x00007ffda05e6000)
libbar.so => not found
因为加载器也无法以任何其他方式解析libbar.so。
现在如果没有-lbar,我将无法再链接prog:
$ gcc -o prog main.o -L. -lfoo
/usr/bin/ld: warning: libbar.so, needed by ./libfoo.so, not found (try using -rpath or -rpath-link)
./libfoo.so: undefined reference to `bar'
但如果我这样做:
$ export LD_LIBRARY_PATH=$(pwd)
然后:
$ ldd libfoo.so
linux-vdso.so.1 (0x00007ffe56d1e000)
libbar.so => /home/imk/develop/so/scrap/libbar.so (0x00007fd2456e8000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd2452f7000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd245aec000)
libfoo.so 的依赖 libbar.so 由加载器解析,使用 LD_LIBRARY_PATH,并在
链接器以同样的方式:
$ gcc -o prog main.o -L. -lfoo; echo Done
Done
如果我再次清除LD_LIBRARY_PATH:
$ unset LD_LIBRARY_PATH
$ gcc -o prog main.o -L. -lfoo; echo Done
/usr/bin/ld: warning: libbar.so, needed by ./libfoo.so, not found (try using -rpath or -rpath-link)
./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
Done
回到失败。