本文将通过实验的方法找到三种方式的区别。
-L
1.1 deps.cc
#include <stdio.h>
void deps() {
printf("deps.\n");
}
parent.cc
#include <stdio.h>
void deps();
void parent() {
printf("parent.\n");
deps();
}
test.cc
#include <stdio.h>
void parent();
int main(void) {
parent();
return 0;
}
a.首先编译汇编代码,得到deps.o 和 parent.o
gcc -c deps.cc parent.cc
查看编译得到的object file
nm -C parent.o
输出
U _GLOBAL_OFFSET_TABLE_
U deps()
0000000000000000 T parent()
U puts
b. 其次生成共享库
gcc -shared -o libparent.so parent.o
gcc -shared -o libdeps.so deps.o
为了达到使libparent.so依赖于libdeps.so的目的,在生成libparent.so时要链接到libdeps.so:
gcc -shared -o libmain.so parent.o -ldeps -L .
ldd libmain.so
输出:
linux-vdso.so.1 (0x00007ffd4855c000)
libdeps.so (0x00007fa99459f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa9941ae000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa9949a3000)
此时libmain.so已经依赖于libdeps.so。
- 编译test.cc
由于test.c直接依赖于libmain.so,因此使用-lmain -L
gcc test.cc -lmain -L.
或者
gcc test.cc -lparent -ldeps -L.
得到可执行程序 a.out
ldd a.out
linux-vdso.so.1 (0x00007ffeb632a000)
libmain.so (0x00007f0d9c701000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0d9c310000)
libdeps.so (0x00007f0d9c10e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0d9cb05000)
由上可见,libmain.so,并且libdeps.so也出现在a.out的依赖中!
-rpath 或者 -rpath-link
1.移动libmain.so 和 libdeps.so 到当前目录的子目录./lib
如果执行gcc test.cc -lmain -L./lib
,则会报错:
/usr/bin/ld: warning: libdeps.so, needed by ./lib/libmain.so, not found (try using -rpath or -rpath-link)
./lib/libmain.so: undefined reference to `deps()'
collect2: error: ld returned 1 exit status
可以看出 libmain.so 找不到 libdeps.so,所以需要通过 -rpath 执行 libdeps.so 的路径。
gcc test.cc -lmain -L ./lib -Wl,-rpath=./lib
编译成功!
执行:
export LD_LIBRARY_PATH=./lib
./a.out
-rpath和-rpath-link都可以在链接时指定库的路径;但是运行可执行文件时,-rpath-link指定的路径就不再有效(链接器没有将库的路径包含进可执行文件中),而-rpath指定的路径还有效(因为链接器已经将库的路径包含在可执行文件中了。)
-rpath=dir
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects.
All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at
runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly
included in the link; see the description of the -rpath-link option. If -rpath is not used when linking an ELF
executable, the contents of the environment variable "LD_RUN_PATH" will be used if it is defined.
The -rpath option may also be used on SunOS. By default, on SunOS, the linker will form a runtime search path out of
all the -L options it is given. If a -rpath option is used, the runtime search path will be formed exclusively using
the -rpath options, ignoring the -L options. This can be useful when using gcc, which adds many -L options which may
be on NFS mounted file systems.
For compatibility with other ELF linkers, if the -R option is followed by a directory name, rather than a file name, it
is treated as the -rpath option.
-rpath-link=dir
When using ELF or SunOS, one shared library may require another. This happens when an "ld -shared" link includes a
shared library as one of the input files.
When the linker encounters such a dependency when doing a non-shared, non-relocatable link, it will automatically try
to locate the required shared library and include it in the link, if it is not included explicitly. In such a case,
the -rpath-link option specifies the first set of directories to search. The -rpath-link option may specify a sequence
of directory names either by specifying a list of names separated by colons, or by appearing multiple times.
This option should be used with caution as it overrides the search path that may have been hard compiled into a shared
library. In such a case it is possible to use unintentionally a different search path than the runtime linker would do.