linux - 从构建命令中排除动态依赖项?

标签 linux gcc ld ldd

假设我们有一个库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 namelibdutils.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.solibutils.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
现在我不能再链接没有lddlibdependency.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/

相关文章:

ruby-on-rails - Ruby 1.9.2 和 Rails 3 无法打开 rails 控制台

java - 在 Java 中创建命名管道

linux - BASH:如何使用脚本复制文件名并将其插入到文本中?

c++ - 为什么在不返回值的情况下流出非 void 函数的末尾不会产生编译器错误?

arrays - 向量化二维数组访问 (GCC)

c++ - 静态库链接失败,共享库链接成功

mysql - 如何记录特定数据库的 mysql 查询 - Linux

visual-c++ - 是否可以告诉编译器(msvc、gcc)单独保留特定寄存器?

linux - 执行glibc的ld-2.6.1.so时收到 "Illegal Instruction"

c++ - 实例化同一类中的多个对象时,代码不会运行,但是实例化具有相同代码的重复类中的对象时,代码会起作用