基本原理
-L
编译选项是编译期间使用
LD_LIBRARY_PATH
环境变量是运行期间使用,可以用来指定so的加载路径,并且优先级高于系统默认的。
RPATH
和RUNPATH
是ELF格式里面的一个数据,rpath
编译选项实际上是在可执行文件中加入了RUNPATH
或者RPATH
。
小结一下一个ELF文件自身加载so的情况(不可信,仅供参考):
其实这三者的关系概括起来没有几点:
LD_LIBRARY_PATH
是个环境变量,优先级高于系统默认的。RPATH
是ELF格式里面的一个数据,他的优先级比LD_LIBRARY_PATH
还要高RUNPATH
很特殊,如果他出现了RPATH
就躲起来了,LD_LIBRARY_PATH
又成了首选??
ELF 中 RPATH | ELF 中 RUNPATH | LD_LIBRARY_PATH 变量 | 尝试加载目录的顺序 |
---|---|---|---|
未设置 | 未设置 | 未设置 | /lib => /usr/lib |
未设置 | 未设置 | 设置 | ${LD_LIBRARY_PATH} => /lib => /usr/lib |
设置 | 未设置 | 未设置 | ${RPATH} => /lib => /usr/lib |
设置 | 未设置 | 设置 | ${RPATH} => ${LD_LIBRARY_PATH} => /lib => /usr/lib |
设置 或 未设置 | 设置 | 设置 | ${LD_LIBRARY_PATH} => ${RUN_PATH} => /lib => /usr/lib |
设置 或 未设置 | 设置 | 未设置 | ${RUN_PATH} => /lib => /usr/lib |
LD_LIBRARY_PATH 例子
1// a.c
2#include <stdio.h>
3
4extern void test_b();
5void test_a()
6{
7 test_b();
8}
9
10int main()
11{
12 test_a();
13 return 0;
14}
15
16// b.c
17#include <stdio.h>
18
19void test_b()
20{
21}
1root@ubuntu:/usr1/tmp/2# gcc b.c -shared -fPIC -o lib/libmyb.so
2root@ubuntu:/usr1/tmp/2# gcc -o a a.c -Llib -lmyb
3root@ubuntu:/usr1/tmp/2#
4root@ubuntu:/usr1/tmp/2# ./a
5./a: error while loading shared libraries: libmyb.so: cannot open shared object file: No such file or directory
6root@ubuntu:/usr1/tmp/2#
7root@ubuntu:/usr1/tmp/2# export LD_LIBRARY_PATH=lib
8root@ubuntu:/usr1/tmp/2# ./a
9root@ubuntu:/usr1/tmp/2#
10root@ubuntu:/usr1/tmp/2# tree
RPATH和RUNPATH 例子
1// a.c
2#include <stdio.h>
3
4extern void test_b();
5void test_a()
6{
7 test_b();
8}
9
10int main()
11{
12 test_a();
13 return 0;
14}
15
16// b1.c, b2.c
17#include <stdio.h>
18
19void test_b()
20{
21 printf("test_b in: %s\n", __FILE__);
22}
1unset LD_LIBRARY_PATH
2gcc b1.c -shared -fPIC -o lib1/libmyb.so
3gcc b2.c -shared -fPIC -o lib2/libmyb.so
4gcc -o a a.c -Llib1 -lmyb -Wl,-rpath=lib2
5tree
6
7ldd ./a
8readelf -d ./a | grep PATH
9
10export LD_LIBRARY_PATH=lib1
11ldd ./a
12readelf -d ./a | grep PATH