这位关于黄金
的男士说:
-L DIR, --library-path DIR
Add directory to search path
--rpath-link DIR
Add DIR to link time shared library search path
这位关于 bfd 的男士说起 -rpath-link
声音有点像它是用于递归包含 sos 的。
ld.lld
甚至没有将其列为参数。
请问有人能为我澄清这种情况吗?
这位关于黄金
的男士说:
-L DIR, --library-path DIR
Add directory to search path
--rpath-link DIR
Add DIR to link time shared library search path
这位关于 bfd 的男士说起 -rpath-link
声音有点像它是用于递归包含 sos 的。
ld.lld
甚至没有将其列为参数。
请问有人能为我澄清这种情况吗?
#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
请求的动态依赖项,但无法满足它们。让我们暂时忽略它的建议- 尝试使用-rpath或-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 Working 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
相同的信息,并指示链接器将该信息嵌入到输出文件的动态部分中。让我们尝试一下:
$ 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
配置的目录以及/lib
和/usr/lib
)之前搜索。
--rpath-link
选项是bfd ld用于添加搜索路径的选项,以便在链接时解析符号时找到DT_NEEDED
共享库。当尝试模拟动态链接器解析符号时(由--rpath
选项或LD_LIBRARY_PATH
环境变量设置),它基本上告诉链接器要使用什么作为运行时搜索路径。
Gold在解析共享库中的符号时不遵循DT_NEEDED
条目,因此--rpath-link
选项会被忽略。这是一个有意设计的决定;在链接过程中,间接依赖项不需要出现或位于其运行时位置。
libfoobar.so
将在运行时找到,但libfoo.so
和libbar.so
将不会找到。您还需要为libfoobar.so
指定-Wl,-rpath=$(pwd)
:) 或者要获取RPATHS,则必须执行-Wl,--disable-new-dtags
,然后Mike的示例仍然有效。 - Harmen