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

时间:2019-01-14 12:21:22

标签: linux gcc ld ldd

假设我们有一个库libutils.so:

ldd libutils.so
...
libdependency.so
...

让我们进一步假设我们需要构建一个应用程序:

g++ appliation.cpp -lutils -o application

可以在上面的命令中省略-ldependency还是必须写:

g++ appliation.cpp -lutils -ldependency -o application

1 个答案:

答案 0 :(得分:1)

  

我们可以在上面的命令中省略-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 = dir

     

将目录添加到运行时库搜索路径。在将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的{​​{1}}部分中有一个NEEDED条目,内容为 该库对.dynamic具有运行时依赖性。同样,它有 那里的一个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的链接中也通过了-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 的链接中通过-rpath=$(pwd)。但是,如果我没有:

prog

加载程序不知道在哪里找到$ 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)

稍后

  

在ldd libutils.so的输出中是否存在libdependency.so是否足以在链接期间省略-ldependencny仍然有点不清楚

您需要问至少一个和最多两个关于$ 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 输出的问题:-

  1. ldd utils.so的输出是否全部报告ldd libutils.so的名称?
  2. 如果对 1 为“是”,还会将该名称解析为实际文件吗?

如果对 1 否,则libdependency.so不包含有关其对libdutils.so的依赖性的信息 并且您必须在任何进一步的链接中指定libdependency.so

如果对 1 为是,对 2 为否(即-lutils -ldependency报告ldd libutils.so),则libdependency.so => not found具有 libutils.so条目的NEEDED条目,但不是一个libdependency.so条目,链接器或 加载程序可以将该名称解析为任何实际文件。再次在这种情况下,如果链接RUNPATH,则必须链接-lutils -ldependency,以便链接器然后搜索可解析-lutils的文件。至少,执行链接时,只要-ldependency still 报告ldd libutils.so,您就必须这样做。继续阅读...

如果对 1 是,对 2 是是,那么您可以在进一步的链接中放置libdependency.so => not found,前提是 在您运行的相同环境中运行 -ldependency

需要进行警告,因为如果ldd libutils.so解决了ldd libutils.so,那么您所知道的一切 是libdependency.so能够使用加载程序的搜索算法解析ldd:-

  • libdependency.so环境变量(在活动外壳中)列出目录 找到LD_LIBRARY_PATH的地方,或者
  • libdependency.so提供了一个libutils.so,其中找到了RUNPATH,或者
  • libdependency.so中列出的目录之一(或其递归libdependency.so扩展名)中找到
  • /etc/ld.so.conf,或者
  • 在加载程序的 trusted 搜索目录之一includelibdependency.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而不是 without 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,我将无法链接prog

-lbar

但如果我这样做:

$ 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

回到失败。