`-rpath-link` 和 `-L` 有什么区别?
What's the difference between `-rpath-link` and `-L`?
gold
的人说:
-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-link
用于递归包含的 sos。
ld.lld
甚至没有将其列为参数。
有人可以为我澄清一下这种情况吗?
bfd ld 使用 --rpath-link
选项添加到搜索路径,用于在执行 link-time 符号解析时查找 DT_NEEDED 共享库。它基本上是告诉 linker 在尝试模仿动态 linker 在解析符号(由 --rpath
选项或 LD_LIBRARY_PATH
环境变量).
解析共享库中的符号时,Gold 不遵循 DT_NEEDED 条目,因此忽略 --rpath-link
选项。这是一个深思熟虑的设计决定;在 link 过程中,间接依赖项不需要存在或位于它们的运行时位置。
这是 GNU ld
的演示,说明 -L
和 -rpath-link
之间的区别 -
为了更好地衡量,-rpath-link
和 -rpath
.
之间的差异
foo.c
#include <stdio.h>
void foo(void)
{
puts(__func__);
}
bar.c
#include <stdio.h>
void bar(void)
{
puts(__func__);
}
foobar.c
extern void foo(void);
extern void bar(void);
void foobar(void)
{
foo();
bar();
}
main.c
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
创建第三个共享库,libfoobar.so
依赖于前两个;
$ 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.so
的程序:
$ 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
请求的动态依赖项
但不能满足他们。让我们拒绝它的建议 - try using -rpath or -rpath-link
-
稍等片刻,看看我们可以用 -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-link
,我们可以:
$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath-link=$(pwd)
并且该链接也成功。 ($(pwd)
表示“Print Wworking Directory”,只是“复制”当前路径。)
-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
./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)
- 但加载器可能能够找到它们
通过其他方式:通过 ldconfig
缓存或设置
LD_LIBRARY_PATH
环境变量,例如:
$ export LD_LIBRARY_PATH=.; ./prog
foo
bar
rpath=dir
为链接器提供与 rpath-link=dir
相同的信息
and 指示链接器将该信息烘焙到
输出文件。让我们试试看:
$ 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_LIBRARY_PATH
中列出的目录之后尝试,如果已设置,并且在系统默认值之前 - ldconfig
-ed 目录,加上 /lib
和/usr/lib
.
gold
的人说:
-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-link
用于递归包含的 sos。
ld.lld
甚至没有将其列为参数。
有人可以为我澄清一下这种情况吗?
bfd ld 使用 --rpath-link
选项添加到搜索路径,用于在执行 link-time 符号解析时查找 DT_NEEDED 共享库。它基本上是告诉 linker 在尝试模仿动态 linker 在解析符号(由 --rpath
选项或 LD_LIBRARY_PATH
环境变量).
解析共享库中的符号时,Gold 不遵循 DT_NEEDED 条目,因此忽略 --rpath-link
选项。这是一个深思熟虑的设计决定;在 link 过程中,间接依赖项不需要存在或位于它们的运行时位置。
这是 GNU ld
的演示,说明 -L
和 -rpath-link
之间的区别 -
为了更好地衡量,-rpath-link
和 -rpath
.
foo.c
#include <stdio.h>
void foo(void)
{
puts(__func__);
}
bar.c
#include <stdio.h>
void bar(void)
{
puts(__func__);
}
foobar.c
extern void foo(void);
extern void bar(void);
void foobar(void)
{
foo();
bar();
}
main.c
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
创建第三个共享库,libfoobar.so
依赖于前两个;
$ 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.so
的程序:
$ 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
请求的动态依赖项
但不能满足他们。让我们拒绝它的建议 - try using -rpath or -rpath-link
-
稍等片刻,看看我们可以用 -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-link
,我们可以:
$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath-link=$(pwd)
并且该链接也成功。 ($(pwd)
表示“Print Wworking Directory”,只是“复制”当前路径。)
-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
./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)
- 但加载器可能能够找到它们
通过其他方式:通过 ldconfig
缓存或设置
LD_LIBRARY_PATH
环境变量,例如:
$ export LD_LIBRARY_PATH=.; ./prog
foo
bar
rpath=dir
为链接器提供与 rpath-link=dir
相同的信息
and 指示链接器将该信息烘焙到
输出文件。让我们试试看:
$ 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_LIBRARY_PATH
中列出的目录之后尝试,如果已设置,并且在系统默认值之前 - ldconfig
-ed 目录,加上 /lib
和/usr/lib
.