经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Linux/Shell » 查看文章
-L -Wl,-rpath-link -Wl,-rpath区别精讲
来源:cnblogs  作者:TianKnight  时间:2019/4/3 16:17:05  对本文有异议

转载请注明出处,谢谢 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

  1. #include <stdio.h>
  2. void world(void);
  3. void hello(void)
  4. {
  5. printf("hello ");
  6. world();
  7. }

hello.c

  1. #include<stdio.h>
  2. void hello(void);
  3. void main(void)
  4. {
  5. hello();
  6. }

world.c

  1. #include<stdio.h>
  2. void world(void)
  3. {
  4. printf("world.\n");
  5. }

尝试编译,保证源码没有问题

  1. # -o 指定输出文件
  2. [root@localhost testc]# ls
  3. hello.c test.c world.c
  4. [root@localhost testc]# gcc -o hehe *.c
  5. [root@localhost testc]# ls
  6. hehe hello.c test.c world.c
  7. [root@localhost testc]# ./hehe
  8. hello world.

编译

首先编译world.c

  1. # -shared 编译链接库
  2. # -fPIC 我的理解是编译链接库时给代码动态分配内存
  3. [root@localhost testc]# gcc -shared -fPIC -o libworld.so world.c
  4. [root@localhost testc]# ls
  5. hello.c libworld.so test.c world.c
  6. [root@localhost testc]# ldd libworld.so
  7. linux-vdso.so.1 => (0x00007ffd7498f000)
  8. libc.so.6 => /lib64/libc.so.6 (0x00007fcb49815000)
  9. /lib64/ld-linux-x86-64.so.2 (0x00007fcb49dea000)
  10. #上述命令和下面的等价,建议选取单条命令即可:gcc -shared -fPIC -o libworld.so world.c
  11. # -c 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
  12. [root@localhost testc]# gcc -c -fPIC world.c
  13. [root@localhost testc]# ls
  14. hello.c test.c world.c world.o
  15. [root@localhost testc]# gcc -shared -fPIC -o libworld.so world.o
  16. [root@localhost testc]# ls
  17. hello.c libworld.so test.c world.c world.o
  18. [root@localhost testc]# ldd libworld.so
  19. linux-vdso.so.1 => (0x00007ffd0dfa9000)
  20. libc.so.6 => /lib64/libc.so.6 (0x00007f4357dcb000)
  21. /lib64/ld-linux-x86-64.so.2 (0x00007f43583a0000)

编译并链接hello.c

  1. # -lxxx 指定需要动态链接的库文件
  2. # -L 指定动态连接库文件的位置(编译时)
  3. # . 指当前路径
  4. # 下面编译出的libhello.so文件已经显式依赖libworld.so文件,但是没有找到libworld.so的位置
  5. [root@localhost testc]# gcc -shared -fPIC -o libhello.so hello.c -lworld -L.
  6. [root@localhost testc]# ls
  7. hello.c libhello.so libworld.so test.c world.c
  8. [root@localhost testc]# ldd libhello.so
  9. linux-vdso.so.1 => (0x00007ffe61b89000)
  10. libworld.so => not found
  11. libc.so.6 => /lib64/libc.so.6 (0x00007ff73cc1e000)
  12. /lib64/ld-linux-x86-64.so.2 (0x00007ff73d1f4000)

调试编译test.c

  1. [root@localhost testc]# ls
  2. hello.c libhello.so libworld.so test.c world.c
  3. # 编译出错,提示找不到hello
  4. [root@localhost testc]# gcc -o haha test.c
  5. /tmp/ccQCWcSW.o: In function 'main':
  6. test.c:(.text+0x5): undefined reference to 'hello'
  7. collect2: error: ld returned 1 exit status
  8. # 添加libhello.so的链接索引,并指定库的搜索路径为'.'(当前路径)
  9. # 依然编译失败,提示找不到libworld.so,该库被libhello.so依赖,并提示建议使用-rpath 或 -rpath-link解决
  10. [root@localhost testc]# gcc -o haha test.c -lhello -L.
  11. /usr/bin/ld: warning: libworld.so, needed by ./libhello.so, not found (try using -rpath or -rpath-link)
  12. ./libhello.so: undefined reference to 'world'
  13. collect2: error: ld returned 1 exit status
  14. # 手动添加libworld.so的依赖,编译通过,查看haha的链接库,已经显式指出依赖,但是没有找到其位置
  15. [root@localhost testc]# gcc -o haha test.c -lhello -L. -lworld
  16. [root@localhost testc]# ldd haha
  17. linux-vdso.so.1 => (0x00007fff556ea000)
  18. libhello.so => not found
  19. libworld.so => not found
  20. libc.so.6 => /lib64/libc.so.6 (0x00007f1ff0c97000)
  21. /lib64/ld-linux-x86-64.so.2 (0x00007f1ff106b000)
  22. # 执行编译出的haha,执行报错,提示找不到依赖库
  23. [root@localhost testc]# ./haha
  24. ./haha: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
  25. #修改系统环境变量'LD_LIBRARY_PATH',增加索引库的位置,查看依赖OK,执行haha, 结果OK, 清空'LD_LIBRARY_PATH'
  26. [root@localhost testc]# export LD_LIBRARY_PATH=/home/testc/ && echo $LD_LIBRARY_PATH
  27. /home/testc/
  28. [root@localhost testc]# ldd haha
  29. linux-vdso.so.1 => (0x00007ffd647d2000)
  30. libhello.so => /home/testc/libhello.so (0x00007fb7aa063000)
  31. libworld.so => /home/testc/libworld.so (0x00007fb7a9e60000)
  32. libc.so.6 => /lib64/libc.so.6 (0x00007fb7a9a8e000)
  33. /lib64/ld-linux-x86-64.so.2 (0x00007fb7aa266000)
  34. [root@localhost testc]# ./haha
  35. hello world.
  36. [root@localhost testc]# export LD_LIBRARY_PATH= && echo $LD_LIBRARY_PATH
  37. # 将-lworld 替换为 -Wl,-rpath-link=. ,编译OK,依然找不到索引库,添加LD_LIBRARY_PATH后,执行OK
  38. [root@localhost testc]# gcc -o haha test.c -lhello -L. -Wl,-rpath-link=.
  39. [root@localhost testc]# ldd haha
  40. linux-vdso.so.1 => (0x00007ffdf67c0000)
  41. libhello.so => not found
  42. libc.so.6 => /lib64/libc.so.6 (0x00007fbdbb94b000)
  43. /lib64/ld-linux-x86-64.so.2 (0x00007fbdbbd1f000)
  44. [root@localhost testc]# ./haha
  45. ./haha: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
  46. [root@localhost testc]# export LD_LIBRARY_PATH=/home/testc && echo $LD_LIBRARY_PATH
  47. /home/testc
  48. [root@localhost testc]# ldd haha
  49. linux-vdso.so.1 => (0x00007fff89504000)
  50. libhello.so => /home/testc/libhello.so (0x00007fc9e75c6000)
  51. libc.so.6 => /lib64/libc.so.6 (0x00007fc9e71f3000)
  52. libworld.so => /home/testc/libworld.so (0x00007fc9e6ff1000)
  53. /lib64/ld-linux-x86-64.so.2 (0x00007fc9e77c9000)
  54. [root@localhost testc]# ./haha
  55. hello world.
  56. [root@localhost testc]# export LD_LIBRARY_PATH= && echo $LD_LIBRARY_PATH
  57. # 将-Wl,-rpath-link=. 换成 -Wl,-rpath=. 编译OK, 查看链接库OK,执行OK
  58. # 修改LD_LIBRARY_PATH后,链接库的位置没有变化
  59. [root@localhost testc]# gcc -o haha test.c -lhello -L. -Wl,-rpath=.
  60. [root@localhost testc]# ls
  61. haha hello.c libhello.so libworld.so test.c world.c
  62. [root@localhost testc]# ldd haha
  63. linux-vdso.so.1 => (0x00007fff86195000)
  64. libhello.so => ./libhello.so (0x00007f4c11254000)
  65. libc.so.6 => /lib64/libc.so.6 (0x00007f4c10e81000)
  66. libworld.so => ./libworld.so (0x00007f4c10c7f000)
  67. /lib64/ld-linux-x86-64.so.2 (0x00007f4c11457000)
  68. [root@localhost testc]# ./haha
  69. hello world.
  70. [root@localhost testc]# export LD_LIBRARY_PATH=/home/testc/ && echo $LD_LIBRARY_PATH
  71. /home/testc/
  72. [root@localhost testc]# ldd haha
  73. linux-vdso.so.1 => (0x00007ffc9f36c000)
  74. libhello.so => ./libhello.so (0x00007f35cf07c000)
  75. libc.so.6 => /lib64/libc.so.6 (0x00007f35ceca9000)
  76. libworld.so => ./libworld.so (0x00007f35ceaa7000)
  77. /lib64/ld-linux-x86-64.so.2 (0x00007f35cf27f000)
  78. [root@localhost testc]# export LD_LIBRARY_PATH= && echo $LD_LIBRARY_PATH

结论

  • 编译时链接库需要分为两类: 直接引用 间接引用
  • 直接引用 被源码中直接调用的库
  • 间接引用 被调用库的依赖库
  • -lxxx 指定具体的库名称,编译时需要显式指定直接引用的库名称
  • -L 指定链接库的位置,编译时需要显式指定直接引用的库位置
  • -Wl,-rpath-link ,用于编译时指定间接引用的库位置
    如果知道所有间接引用的库文件名称,并且不嫌麻烦,也可以用-lxxx显式指定每一个库(不推荐-lxxx)
  • -Wl,-rpath ,有两个作用:
    1. 用于编译时指定间接引用的库位置,作用同-Wl,-rpath-link
    2. 用于运行时指定所有引用库的位置,作用同修改环境变量(LD_LIBRARY_PATH),并且库路径引用优先级高于LD_LIBRARY_PATH
  • 使用建议
    1. 编译命令中使用-Wl,-rpath-link 指定间接引用库位置(编译时),使用-Wl,-rpath 指定引用库位置(运行时)
    2. -Wl,-rpath-link 在 -Wl,-rpath 前

原文链接:http://www.cnblogs.com/tianknight/p/10648021.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号