假设我们有一个库libutils。
ldd libutils.so
...
libdependency.so
...
让我们进一步假设我们需要构建一个应用程序:
g++ appliation.cpp -lutils -o application
我们是否可以省略上述命令中的-ldependency,或者必须写入:
g++ appliation.cpp -lutils -ldependency -o application
最佳答案
我们可以省略上面命令中的-ldependence吗
如果控制libutils.so
本身的链接,可以。一个例子:
主C
extern void foo(void);
int main(void)
{
foo();
return 0;
}
食品
extern void bar(void);
void foo(void)
{
bar();
}
钢筋混凝土
#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
现在链接到无装饰的方式:
$ gcc -shared -o libbar.so bar.o
下一个链接如下:
$ gcc -shared -o libfoo.so foo.o -L. -lbar -Wl,-rpath=$(pwd)
libbar.so
的影响是:-rpath=目录
将目录添加到运行库搜索路径。将ELF可执行文件与共享对象链接时使用此选项。
所有-rpath参数都被连接起来并传递给运行时链接器,后者使用它们在运行时定位共享对象。
当定位链接中显式包含的共享对象所需的共享对象时,还使用-rpath选项;
请参阅-rpath链接选项的说明。如果链接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
在其-rpath linker option
部分有一个libfoo.so
条目,表示库在运行时依赖于
NEEDED
。同样地一个
.dynamic
条目,表示可以在libbar.so
中搜索运行时依赖项。这就是我做链接的地方:只要确实是
当链接器或加载程序来查找时,可以在其中找到
RUNPATH
的目录。当
/home/imk/develop/so/scrap
与其他内容链接时,链接器可以读取此信息,在运行时由加载程序执行。最后我可以这样链接:
$ gcc -o prog main.o -L. -lfoo -Wl,-rpath=$(pwd)
我不需要提到
pwd
,因为libbar.so
本身为链接器提供了libbar.so
依赖于prog
的信息,以及在哪里查找它。由于我也通过了
-lbar
的链接,我们看到将提供此信息
$ objdump -x -j .dynamic prog | egrep '(RUNPATH|NEEDED)'
NEEDED libfoo.so
NEEDED libc.so.6
RUNPATH /home/imk/develop/so/scrap
对于运行时加载程序:
libfoo.so
需要libfoo.so
,可以查找在
libbar.so
中。当加载程序找到并加载-rpath=$(pwd)
时,它将从中发现:
NEEDED libbar.so
RUNPATH /home/imk/develop/so/scrap
然后依次查找并加载
prog
,这将使它能够解析所有在建工程中所指的符号。因此,
prog
可以立即运行:$ ./prog
bar
我不需要在
libfoo.so
的链接中通过/home/imk/develop/so/scrap
。但如果我没有:$ 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,这足以在链接期间忽略-ldependency。
对于
libbar.so
的输出,您至少需要问一个问题,最多需要问两个问题:-prog
输出是否报告了so name-rpath=$(pwd)
?如果对1为“是”,它是否也将该so名称解析为实际文件?
如果否为1,则
prog
不包含有关其依赖性的信息。您必须在任何进一步的链接中指定
libfoo.so
。如果对1是但对2否(即
ldd utils.so
报告ldd libutils.so
),则libdependency.so
具有so name
libdutils.so
的一个libdependency.so
条目,但不是链接器或加载程序可以将该so名称解析为任何实际文件。在这种情况下,如果链接
-lutils -ldependency
,则必须链接ldd libutils.so
,以便链接器随后搜索解析libdependency.so => not found
的文件。至少,只要在进行链接时libutils.so
仍然报告NEEDED
,就必须这样做。继续读…如果是到1和是到2,那么您可以在进一步的链接中删除
libdependency.so
,只要它是在运行
RUNPATH
这个警告是必要的,因为如果
-lutils -ldependency
解决了-lutils
,所有你知道的是否
-ldependency
能够使用加载程序的搜索算法解析ldd libutils.so
:libdependency.so => not found
环境变量(在active shell中)列出了一个目录其中
-ldependency
被发现,或ldd libutils.so
提供一个ldd libutils.so
中找到libdependency.so
的,或ldd
位于libdependency.so
中列出的其中一个目录中(或其递归展开),或LD_LIBRARY_PATH
位于加载程序的一个可信搜索目录中,libdependency.so
和libutils.so
如果
RUNPATH
可以用这四种方法之一解析libdependency.so
,那么链接器将能够以同样的方式来做,只要在你做链接时仍然成功。
回到我的例子,我的联系:
$ gcc -shared -o libfoo.so foo.o -L. -lbar -Wl,-rpath=$(pwd)
之后,多亏了
libdependency.so
。我可以链接如下:$ gcc -o prog main.o -L. -lfoo
没有提到
/etc/ld.so.conf
,它成功了。现在我链接include
而没有一个
libdependency.so
:$ gcc -shared -o libfoo.so foo.o -L. -lbar
之后:
$ objdump -x -j .dynamic libfoo.so | egrep '(RUNPATH|NEEDED)'
NEEDED libbar.so
不再有
/lib
了,因此:$ ldd libfoo.so
linux-vdso.so.1 (0x00007ffda05e6000)
libbar.so => not found
因为加载程序也不能以任何其他方式解析
/usr/lib
。现在我不能再链接没有
ldd
的libdependency.so
:$ 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)
-rpath=$(pwd)
的依赖关系由加载程序使用prog
解析,并在链接器也是这样:
$ gcc -o prog main.o -L. -lfoo; echo Done
Done
如果我再次清除
-lbar
:$ 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
回到失败。
关于linux - 从构建命令中排除动态依赖项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54181491/