-L -Wl,-rpath-link -Wl,-rpath区别精讲
程序员文章站
2022-04-02 14:19:01
-L -Wl,-rpath-link -Wl,-rpath区别精讲 ......
目录
转载请注明出处,谢谢 https://www.cnblogs.com/tianknight/p/10648021.html
前言
关于gcc这三个参数,参考了诸多文档后,仍然理解上有偏差,仿照下面博客中的方法,自己调试了一波,总算是理解了。还是建议大家动手实践一下。
参考资料如下:
- https://blog.csdn.net/q1302182594/article/details/42102961
- https://blog.csdn.net/openme_openwrt/article/details/7860580
源码准备
新建三个文件:test.c hello.c world.c ,其源码依赖关系为:test.c 依赖 hello.c;hello.c 依赖 world.c
源码内容
test.c
#include <stdio.h> void world(void); void hello(void) { printf("hello "); world(); }
hello.c
#include<stdio.h> void hello(void); void main(void) { hello(); }
world.c
#include<stdio.h> void world(void) { printf("world.\n"); }
尝试编译,保证源码没有问题
# -o 指定输出文件 [root@localhost testc]# ls hello.c test.c world.c [root@localhost testc]# gcc -o hehe *.c [root@localhost testc]# ls hehe hello.c test.c world.c [root@localhost testc]# ./hehe hello world.
编译
首先编译world.c
# -shared 编译链接库 # -fpic 我的理解是编译链接库时给代码动态分配内存 [root@localhost testc]# gcc -shared -fpic -o libworld.so world.c [root@localhost testc]# ls hello.c libworld.so test.c world.c [root@localhost testc]# ldd libworld.so linux-vdso.so.1 => (0x00007ffd7498f000) libc.so.6 => /lib64/libc.so.6 (0x00007fcb49815000) /lib64/ld-linux-x86-64.so.2 (0x00007fcb49dea000) #上述命令和下面的等价,建议选取单条命令即可:gcc -shared -fpic -o libworld.so world.c # -c 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件 [root@localhost testc]# gcc -c -fpic world.c [root@localhost testc]# ls hello.c test.c world.c world.o [root@localhost testc]# gcc -shared -fpic -o libworld.so world.o [root@localhost testc]# ls hello.c libworld.so test.c world.c world.o [root@localhost testc]# ldd libworld.so linux-vdso.so.1 => (0x00007ffd0dfa9000) libc.so.6 => /lib64/libc.so.6 (0x00007f4357dcb000) /lib64/ld-linux-x86-64.so.2 (0x00007f43583a0000)
编译并链接hello.c
# -lxxx 指定需要动态链接的库文件 # -l 指定动态连接库文件的位置(编译时) # . 指当前路径 # 下面编译出的libhello.so文件已经显式依赖libworld.so文件,但是没有找到libworld.so的位置 [root@localhost testc]# gcc -shared -fpic -o libhello.so hello.c -lworld -l. [root@localhost testc]# ls hello.c libhello.so libworld.so test.c world.c [root@localhost testc]# ldd libhello.so linux-vdso.so.1 => (0x00007ffe61b89000) libworld.so => not found libc.so.6 => /lib64/libc.so.6 (0x00007ff73cc1e000) /lib64/ld-linux-x86-64.so.2 (0x00007ff73d1f4000)
调试编译test.c
[root@localhost testc]# ls hello.c libhello.so libworld.so test.c world.c # 编译出错,提示找不到hello [root@localhost testc]# gcc -o haha test.c /tmp/ccqcwcsw.o: in function 'main': test.c:(.text+0x5): undefined reference to 'hello' collect2: error: ld returned 1 exit status # 添加libhello.so的链接索引,并指定库的搜索路径为'.'(当前路径) # 依然编译失败,提示找不到libworld.so,该库被libhello.so依赖,并提示建议使用-rpath 或 -rpath-link解决 [root@localhost testc]# gcc -o haha test.c -lhello -l. /usr/bin/ld: warning: libworld.so, needed by ./libhello.so, not found (try using -rpath or -rpath-link) ./libhello.so: undefined reference to 'world' collect2: error: ld returned 1 exit status # 手动添加libworld.so的依赖,编译通过,查看haha的链接库,已经显式指出依赖,但是没有找到其位置 [root@localhost testc]# gcc -o haha test.c -lhello -l. -lworld [root@localhost testc]# ldd haha linux-vdso.so.1 => (0x00007fff556ea000) libhello.so => not found libworld.so => not found libc.so.6 => /lib64/libc.so.6 (0x00007f1ff0c97000) /lib64/ld-linux-x86-64.so.2 (0x00007f1ff106b000) # 执行编译出的haha,执行报错,提示找不到依赖库 [root@localhost testc]# ./haha ./haha: error while loading shared libraries: libhello.so: cannot open shared object file: no such file or directory #修改系统环境变量'ld_library_path',增加索引库的位置,查看依赖ok,执行haha, 结果ok, 清空'ld_library_path' [root@localhost testc]# export ld_library_path=/home/testc/ && echo $ld_library_path /home/testc/ [root@localhost testc]# ldd haha linux-vdso.so.1 => (0x00007ffd647d2000) libhello.so => /home/testc/libhello.so (0x00007fb7aa063000) libworld.so => /home/testc/libworld.so (0x00007fb7a9e60000) libc.so.6 => /lib64/libc.so.6 (0x00007fb7a9a8e000) /lib64/ld-linux-x86-64.so.2 (0x00007fb7aa266000) [root@localhost testc]# ./haha hello world. [root@localhost testc]# export ld_library_path= && echo $ld_library_path # 将-lworld 替换为 -wl,-rpath-link=. ,编译ok,依然找不到索引库,添加ld_library_path后,执行ok [root@localhost testc]# gcc -o haha test.c -lhello -l. -wl,-rpath-link=. [root@localhost testc]# ldd haha linux-vdso.so.1 => (0x00007ffdf67c0000) libhello.so => not found libc.so.6 => /lib64/libc.so.6 (0x00007fbdbb94b000) /lib64/ld-linux-x86-64.so.2 (0x00007fbdbbd1f000) [root@localhost testc]# ./haha ./haha: error while loading shared libraries: libhello.so: cannot open shared object file: no such file or directory [root@localhost testc]# export ld_library_path=/home/testc && echo $ld_library_path /home/testc [root@localhost testc]# ldd haha linux-vdso.so.1 => (0x00007fff89504000) libhello.so => /home/testc/libhello.so (0x00007fc9e75c6000) libc.so.6 => /lib64/libc.so.6 (0x00007fc9e71f3000) libworld.so => /home/testc/libworld.so (0x00007fc9e6ff1000) /lib64/ld-linux-x86-64.so.2 (0x00007fc9e77c9000) [root@localhost testc]# ./haha hello world. [root@localhost testc]# export ld_library_path= && echo $ld_library_path # 将-wl,-rpath-link=. 换成 -wl,-rpath=. 编译ok, 查看链接库ok,执行ok # 修改ld_library_path后,链接库的位置没有变化 [root@localhost testc]# gcc -o haha test.c -lhello -l. -wl,-rpath=. [root@localhost testc]# ls haha hello.c libhello.so libworld.so test.c world.c [root@localhost testc]# ldd haha linux-vdso.so.1 => (0x00007fff86195000) libhello.so => ./libhello.so (0x00007f4c11254000) libc.so.6 => /lib64/libc.so.6 (0x00007f4c10e81000) libworld.so => ./libworld.so (0x00007f4c10c7f000) /lib64/ld-linux-x86-64.so.2 (0x00007f4c11457000) [root@localhost testc]# ./haha hello world. [root@localhost testc]# export ld_library_path=/home/testc/ && echo $ld_library_path /home/testc/ [root@localhost testc]# ldd haha linux-vdso.so.1 => (0x00007ffc9f36c000) libhello.so => ./libhello.so (0x00007f35cf07c000) libc.so.6 => /lib64/libc.so.6 (0x00007f35ceca9000) libworld.so => ./libworld.so (0x00007f35ceaa7000) /lib64/ld-linux-x86-64.so.2 (0x00007f35cf27f000) [root@localhost testc]# export ld_library_path= && echo $ld_library_path
结论
- 编译时链接库需要分为两类: 直接引用 间接引用
- 直接引用 被源码中直接调用的库
- 间接引用 被调用库的依赖库
- -lxxx 指定具体的库名称,编译时需要显式指定直接引用的库名称
- -l 指定链接库的位置,编译时需要显式指定直接引用的库位置
- -wl,-rpath-link ,用于编译时指定间接引用的库位置
如果知道所有间接引用的库文件名称,并且不嫌麻烦,也可以用-lxxx显式指定每一个库(不推荐-lxxx)- -wl,-rpath ,有两个作用:
- 用于编译时指定间接引用的库位置,作用同-wl,-rpath-link
- 用于运行时指定所有引用库的位置,作用同修改环境变量(ld_library_path),并且库路径引用优先级高于ld_library_path
- 使用建议
- 编译命令中使用-wl,-rpath-link 指定间接引用库位置(编译时),使用-wl,-rpath 指定引用库位置(运行时)
- -wl,-rpath-link 在 -wl,-rpath 前
上一篇: Linux常见系统故障