Linker 什么';“-rpath链接”和“-L”之间的区别是什么?

Linker 什么';“-rpath链接”和“-L”之间的区别是什么?,linker,ld,gold-linker,bfd,lld,Linker,Ld,Gold Linker,Bfd,Lld,黄金的男人说: -L DIR, --library-path DIR Add directory to search path --rpath-link DIR Add DIR to link time shared library search path bfdld的man使其听起来有点像-rpath链接用于递归包含的sos ld.lld甚至没有将其列为参数 有人能为我澄清一下这种情况吗?bfd ld使用--rpath link选项添加到搜索

黄金的男人说:

  -L DIR, --library-path DIR
          Add directory to search path

  --rpath-link DIR
          Add DIR to link time shared library search path
bfd
ld
的man使其听起来有点像
-rpath链接
用于递归包含的sos

ld.lld
甚至没有将其列为参数

有人能为我澄清一下这种情况吗?

bfd ld使用
--rpath link
选项添加到搜索路径,用于在执行链接时间符号解析时查找所需的共享库。它基本上是告诉链接器在尝试模拟动态链接器在解析符号时所做的操作时使用什么作为运行时搜索路径(由
--rpath
选项或
LD\u LIBRARY\u path
环境变量设置)


在解析共享库中的符号时,Gold不跟随dtu所需的条目,因此忽略
--rpath链接
选项。这是一个深思熟虑的设计决定;在链接过程中,间接依赖项不需要存在或位于它们的运行时位置。

这里是一个演示,用于GNU
ld
,演示
-L
-rpath-link
之间的区别- 为了更好地衡量,
-rpath-link
-rpath
之间的差异

foo.c

#include <stdio.h>

void foo(void)
{
    puts(__func__);
}
#include <stdio.h>

void bar(void)
{
    puts(__func__);
}
extern void foo(void);
extern void bar(void);

void foobar(void)
{
    foo();
    bar();
}
extern void foobar(void);

int main(void)
{
    foobar();
    return 0;
}
main.c

#include <stdio.h>

void foo(void)
{
    puts(__func__);
}
#include <stdio.h>

void bar(void)
{
    puts(__func__);
}
extern void foo(void);
extern void bar(void);

void foobar(void)
{
    foo();
    bar();
}
extern void foobar(void);

int main(void)
{
    foobar();
    return 0;
}
创建两个共享库,
libfoo.so
libbar.so

$ gcc -c -Wall -fPIC foo.c bar.c
$ gcc -shared -o libfoo.so foo.o
$ gcc -shared -o libbar.so bar.o
$ gcc -c -Wall main.c
$ gcc -o prog main.o -L. -lfoobar
/usr/bin/ld: warning: libfoo.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libbar.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
./libfoobar.so: undefined reference to `bar'
./libfoobar.so: undefined reference to `foo'
collect2: error: ld returned 1 exit status
创建第三个共享库,
libfoobar

$ gcc -c -Wall -fPIC foobar.c
$ gcc -shared -o libfoobar.so foobar.o -lfoo -lbar
/usr/bin/ld: cannot find -lfoo
/usr/bin/ld: cannot find -lbar
collect2: error: ld returned 1 exit status
哎呀。链接器不知道在哪里查找解析
-lfoo
-lbar

-L
选项修复了该问题

$ gcc -shared -o libfoobar.so foobar.o -L. -lfoo -lbar
-Ldir
选项告诉链接器
dir
是要访问的目录之一 搜索解析给定的
-lname
选项的库。它搜索
-L
目录首先按命令行顺序排列;然后它搜索它的 按配置的顺序配置默认目录

现在制作一个依赖于libfoobar的程序。因此

$ gcc -c -Wall -fPIC foo.c bar.c
$ gcc -shared -o libfoo.so foo.o
$ gcc -shared -o libbar.so bar.o
$ gcc -c -Wall main.c
$ gcc -o prog main.o -L. -lfoobar
/usr/bin/ld: warning: libfoo.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libbar.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
./libfoobar.so: undefined reference to `bar'
./libfoobar.so: undefined reference to `foo'
collect2: error: ld returned 1 exit status
哎呀。链接器检测由
libfoobar.so请求的动态依赖项
但不能满足他们。让我们抵制它的建议-
尝试使用-rpath或-rpath链接
- 看一看我们能用
-L
-L
做些什么:

$ gcc -o prog main.o -L. -lfoobar -lfoo -lbar
到目前为止还不错。但是:

$ ./prog
./prog: error while loading shared libraries: libfoobar.so: cannot open shared object file: No such file or directory
在运行时,加载程序无法找到
libfoobar.so

那么链接者的建议呢?使用
-rpath链接
,我们可以执行以下操作:

$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath-link=$(pwd)
这种联系也取得了成功。(
$(pwd)
表示“PrintWDdirectory”,只“复制”当前路径。)

-rpath link=dir
选项告诉链接器,当它遇到输入文件时 请求动态依赖项-如
libfoobar.so
-它应该搜索目录
dir
,以 解决它们。因此,我们不需要使用
-lfoo-lbar
指定这些依赖项,也不需要 甚至需要知道它们是什么。它们是已经写在文档中的信息
libfoobar.so的动态部分:-

$ readelf -d libfoobar.so

Dynamic section at offset 0xdf8 contains 26 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
 0x0000000000000001 (NEEDED)             Shared library: [libbar.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 ...
 ...
我们只需要知道一个可以找到它们的目录,不管它们是什么

但这会给我们一个可运行的
程序吗

$ ./prog
./prog: error while loading shared libraries: libfoobar.so: cannot open shared object file: No such file or directory
不,和以前一样。这是因为
-rpath link=dir
为链接器提供了信息 加载程序需要解决
prog
在运行时-假设它在运行时仍然为真-但它不会将该信息写入
prog
的动态部分。 它只是让链接成功,而不需要我们详细说明所有递归动态 链接与
-l
选项的依赖关系

在运行时,
libfoo.so
libbar.so
——实际上是
libfoobar.so
- 它们很可能不在现在的位置-
$(pwd)
-但是加载程序可能能够找到它们 通过其他方式:通过缓存或设置
LD\u LIBRARY\u PATH
环境变量,例如:

$ export LD_LIBRARY_PATH=.; ./prog
foo
bar
rpath=dir
为链接器提供与
rpath link=dir
并指示链接器将该信息烘焙到 输出文件。让我们试试:

$ export LD_LIBRARY_PATH=
$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath=$(pwd)
$ ./prog
foo
bar
一切都好。因为现在,
prog
包含了
$(pwd)
是运行时搜索的信息 它所依赖的共享库的路径,如我们所见:

$ readelf -d prog

Dynamic section at offset 0xe08 contains 26 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libfoobar.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000f (RPATH)              Library rpath: [/home/imk/develop/so/scrap]
 ...                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ...

如果设置了
LD\u LIBRARY\u path
中列出的目录,将在系统默认设置之前尝试该搜索路径-ldconfig
-ed目录,加上
/lib
/usr/lib
,谢谢!我们收到了链接器错误和大量“尝试使用-rpath或-rpath链接”,结果是我们意外地从gold切换到bfd。这是一个很好的答案,让我补充一下,在“现代”版本的GCC中将使用RUNPATH。默认情况下,只有较旧的编译器具有RPATH。运行路径不会使依赖项继承搜索路径,它只应用于当前二进制文件的搜索路径。在上面的示例中:
libfoobar.so
将在运行时找到,但
libfoo.so
libbar.so
不会找到。您必须为
libfoobar.so
指定
-Wl,-rpath=$(pwd)
,或者您必须执行
-Wl,-disable new dtags
来获取rpath,然后Mike的示例仍然有效。