zoukankan      html  css  js  c++  java
  • -L、-rpath和-rpath-link的区别

    以下结论及分析仅针对动态库。

    结论:

    (1)-rpath和-rpath-link都可以在链接时指定库的路径;

    (2)运行可执行文件时,-rpath-link指定的路径不再有效(链接器没有将库的路径包含进可执行文件中),

                而-rpath指定的路径还有效(因为链接器已经将库的路径包含在可执行文件中);

    (3)-L指定的是链接时的库路径,生成的可执行文件在运行时库的路径仍由LD_LIBRARY_PATH环境变量指定;

    (4)不管采用何种选项链接,当提示找不到动态库时均可通过设置LD_LIBRARY_PATH解决。

    【转http://blog.csdn.net/q1302182594/article/details/42102961】

    关于这3个参数的说明,有不少资料,但是看完了还是觉得模糊,分不清它们的区别。本文将用实验的方法去探讨这3个参数的区别。

    1、三个.c文件

    1.1 world.c

    [cpp] view plain copy
     
    1. #include<stdio.h>  
    2. void world(void) {  
    3.     printf("world. ");  
    4. }  

    1.2 hello.c

    [plain] view plain copy
     
    1. #include <stdio.h>  
    2. void world(void);  
    3. void hello(void) {  
    4.     printf("hello ");  
    5.     world();  
    6. }  

    1.3 test.c

    [plain] view plain copy
     
    1. void main(void) {  
    2.     hello();  
    3. }  

    2、生成动态库

        参照《Linux静态库与动态库制作》,将hello.c和world.c分别生成动态库

    [plain] view plain copy
     
    1. ubuntu $ gcc -c hello.c world.c  
    2. ubuntu $ gcc -shared -o libhello.so hello.o  
    3. ubuntu $ gcc -shared -o libworld.so world.o  

         这时,生成的文件及其依赖如下图:

        由上图可见,libhello.so和libworld都依赖于Linux-gate.so.1、libc.so.6以及/lib/ld-linux.so.2,并且这3个库的路径都以及硬编码进libhello.so和libworld.so中了(=>右边的部分)。

        然而,虽然libhello.so中调用了libworld.so的函数,但是在上图中并没有显示出此关系。为了达到使libhello.so依赖于libworld.so的目的,在生成libhello.so时要链接到libworld.so:

    [plain] view plain copy
     
    1. ubuntu $ gcc -shared -o libworld.so world.o -lhello -L .  

       此时,再使用ldd查看libhello.so的依赖:

     


        由上图可见,此时libhello.so已经依赖于libworld.so。

    3、编译test.c

    3.1 -L

        由于test.c直接依赖于libhello.so,因此使用-lhello -L

    [plain] view plain copy
     
    1. ubuntu $ gcc test.c -lhello -L .  

        结果如下图:



        由上图可见已经在-L指定的路径找打了libhello.so,只是libhello.so还需要libworld.so。虽然它都在同一目录下,但是还是没有办法自动找到libworld.so。

        那么,能不能使用-lworld将libworld.so也一并链接到test.c中呢?下面做一个尝试:

    [plain] view plain copy
     
    1. ubuntu $ gcc test.c -lhello -lworld -L .  

         没有报错,成功生成a.out。

        执行a.out并且使用ldd查看a.out的依赖:

       

        由上图可见,虽然使用-lworld参数将libworld.so链接到了a.out中,但是上面只显示a.out依赖于libhello.so。由于找不到libhello.so(=> not found)的路径,因此需要设置环境变量LD_LIBRARY_PATH

    [plain] view plain copy
     
    1. ubuntu export LD_LIBRARY_PATH=/home/liyihai/documents  

        再次执行a.out并使用ldd命令查看a.out的依赖库:

       

        由上图可见,libhello.so已经通过LD_LIBRARY_PATH环境变量找到,并且libworld.so也出现在a.out的依赖中!

        结论:-L指定的是链接时的库路径,生成的可执行文件在运行时库的路径由LD_LIBRARY_PATH环境变量指定。

    3.2 -rpath

        根据3.1第1张图的提示,由于libhello.so依赖于libworld.so,可以只用-rpath或者-rpath-link来指定。这里先使用-rpath。

        先清空LD_LIBRARY_PATH环境变量,然后重新编译test.c并且带上-rpath参数:

    [plain] view plain copy
     
    1. ubuntu $ export LD_LIBRARY_PATH=  
    2. ubuntu $ gcc test.c -lhello -L . -Wl,-rpath .  

        执行a.out,并且使用ldd命令查看a.out的依赖:

     

        由上图可见,虽然没有明确指出链接libworld.so,但是libworld.so还是出现在a.out的依赖中。

        另外,虽然LD_LIBRARY_PATH已经清空,但是a.out还是可以执行,这说明库的路径已经被编译进a.out中了。需要注意的是,libhello.so和libworld.so的路径都是通过-rpath指定的路径找到的。

    3.2.1 实验1

        这时候,如果libhello.so和libworld.so的路径改变了,将会发生什么情况呢?下面做一个实验。

        创建一个lib_tmp目录,然后将libhello.so和libworld.so移动进这个目录。

    [plain] view plain copy
     
    1. ubuntu $ mdir lib_tmp  
    2. ubuntu $ mv libhello.so lib_tmp/  
    3. ubuntu $ mv libworld.so lib_tmp/  

        这时再执行a.out时,提示找不动态库,使用ldd命令查看a.out的库路径:

     

        由上图红色圈部分可见,libhello.so的路径是not found的,并且libworld.so没有出现在其中。这和3.1的情况是相同的。

        究其原因,就是要先找到libhello.so再去找libworl.so,因为是libhello.so依赖于libworld.so,而不是a.out依赖于libworld.so。

        由此可见,使用了-rpath参数指定库的路径后,生成的可执行文件的依赖库路径并非就固定不变了。而是执行时先从-rpath指定的路径去找依赖库,如果找不到,还是会报not fund。

        那么,这时候,LD_LIBRARY_PATH对a.out是否还有影响呢?下面将LD_LIBRARY_PATH设为当前libhello.so和libworld.so所在的路径

    [plain] view plain copy
     
    1. ubuntu $ export LD_LIBRARY_PATH=./lib_tmp  

        再次执行a.out,并且使用ldd查看此时a.out的依赖库路径:

     

        由上图可见LD_LIBRARY_PATH还是起作用的!由上图可见,和使用-rpath指定路径的效果是一样的。

    3.2.2 实验2

        将LD_LIBRARY_PATH清空,然后将libhello.so移动到lib_tmp中,而libworld.so则留在documents目录中。

        执行a.out,并且使用ldd查看此时a.out的依赖库:

        由上图可见,找不到libhello.so。这时,再指定LD_LIBRARY_PATH的路径为libhello.so所在的路径:

    [plain] view plain copy
     
    1. ubuntu $ export LD_LIBRARY_PATH=./lib_tmp/  

        再次执行a.out,并且使用ldd查看其依赖库:


     

        由上图可见,一切又恢复了正常。此时,libhello.so是通过LD_LIBRARY_PATH找到的,而libworld.so则是通过-rpath指定的路径找到的。

    3.2.3 回顾

        其实,经过测试,在3.1小节中,如果先指定LD_LIBRARY_PATH的值为libhello.so和libworld.so所在的路径,然后再编译test.c(执行3.1节的第1条编译命令),是可以成功编译的,并不会报3.1小节第1张图的那种错误。也就是说,LD_LIBRARY_PATH不仅指定可执行文件的库路径,还指定了库所依赖于其它库的路径。

    3.2.4 结论   

        并非指定-rpath参数后,就抛弃LD_LIBRARY_PATH环境变量,只是多了个可选的依赖库路径而已。

    3.3 -rpath-link

        先将LD_LIBRARY_PATH的值清空,然后将libworld.so移动到lib_tmp目录中,而libhello.so则留在documents目录中,使用以下命令对test.c进行编译:

    [plain] view plain copy
     
    1. ubuntu $ gcc test.c -lhello  -L . -Wl,-rpath-link ./lib_tmp  

       执行a.out并且使用ldd查看a.out的依赖库:

       找不到 libhello.so,这在预料之中。下面指定LD_LIBRARY_PATH的值为libhello.so的路径,然后在执行a.out,并且查看a.out的依赖:

        由上图可见,libhello.so已经通过LD_LIBRARY_PATH找到,但是libworld.so由于没有在LD_LIBRARY_PATH指定的路径中,而且编译时a.out又没有包含库的路径,因此找不到。

        

  • 相关阅读:
    mycat安装
    docker注册&打包
    docker的使用场景和背景了解
    解析nohup java -jar xxx &
    透明度百分比和十六进制对应关系
    android get cpu rate
    Cordova插件开发
    VectorDrawable在Android中的配置
    APK反编译后添加日志
    apk重新签名
  • 原文地址:https://www.cnblogs.com/candl/p/7358384.html
Copyright © 2011-2022 走看看