为什么在构建共享库时会删除--rpath?

时间:2018-05-31 15:35:33

标签: gcc ld

我正在使用CentOS机器。我有一个文件(test.c),我正在编译成共享库。

test.c

#include <stdio.h>
#include <stdlib.h>
#include <quadmath.h>
int my_func(void){
    __float128 r;
    r = strtoflt128 ("1.2345678", NULL);
    int * b = malloc(sizeof(int) * 5);
    double a = 10*M_PI_2q;
    printf("Hello world  %f\n",a);
    return 0;
}

编译它:

$ gcc -c -fPIC test.c -o test.o
$ gcc -shared -Wl,--verbose -Wl,-soname,poo.so -Wl,-rpath,/opt/gcc/5.5.0/lib/ -o poo.so test.o -lquadmath
$ echo $LD_LIBRARY_PATH   ### This shouldn't matter?
    /opt/gcc/5.5.0/lib

ld的详细输出中,看起来找到/opt/gcc/5.5.0/lib64/libquadmath.so.0(这就是我想要的)。即。

.
.
.
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.5.0/libquadmath.so failed
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.5.0/libquadmath.a failed
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/libquadmath.so failed
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/libquadmath.a failed
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.5.0/../../../../lib64/libquadmath.so succeeded 
-lquadmath (/opt/gcc/5.5.0/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.5.0/../../../../lib64/libquadmath.so)
 .
 .
 .

但是,当我查看ldd poo.so时, 没有正确的库。即。

$ ldd poo.so 
    linux-vdso.so.1 =>  (0x00007fffc0e8e000)
    libquadmath.so.0 => /act/gcc-4.7.2/lib64/libquadmath.so.0 (0x00002aea8fd39000)
    libc.so.6 => /lib64/libc.so.6 (0x00002aea8ff6f000)
    libm.so.6 => /lib64/libm.so.6 (0x00002aea90303000)
    /lib64/ld-linux-x86-64.so.2 (0x00002aea8f8f2000)

我正在使用gcc版本5.5.0,并希望poo.so链接到/opt/gcc/5.5.0/lib/libquadmath.so.0而不是4.7.2版本。

我认为这与/etc/ld.so.conf中存在指定旧库位置的文件有关。即。

$ cat /etc/ld.so.conf.d/gcc-4.7.2.conf 
/act/gcc-4.7.2/lib64
/act/gcc-4.7.2/lib

ld的手册页(我查询here)不太有用。

问题:我在链接和构建共享库时指定了-rpath,但我不明白为什么它会找到旧的gcc-4.7.2版本的quadmath图书馆。为什么链接器似乎优先考虑/etc/ld.so.conf中的路径并忽略-rpath选项?如何在编译时指定库位置以及如何解决此问题?

2 个答案:

答案 0 :(得分:0)

要理解解决方案,首先我们必须理解错误的想法。

  1. 我没有意识到两个实用程序正在进行链接。有ld(在编译时使用)和ld.so(在运行时使用)。 ld.so的手册页描述了如何在运行时找到库。总结一下搜索:

    a)DT_RPATH

    中指定的目录

    b)LD_LIBRARY_PATH

    中指定的目录

    c)DT_RUNPATH二进制动态部分(如果存在)

    中的目录

    d)缓存文件/etc/ld.so.cache

    e)默认路径/ lib,然后是/ usr / lib

  2. ld的手册主页让我很困惑。它在-rpath选项下说:

      

    将目录添加到运行时库搜索路径。将ELF可执行文件与共享对象链接

    时使用此方法

    我认为在构建共享库时传递-rpath会 保证它无需设置即可找到库 LD_LIBRARY_PATH。的错误的即可。此功能似乎只是有用 当构建可执行文件时,而不是共享库。有一个-rpath-link选项,但我无法弄清楚如何让它发挥作用。

  3. 您可以通过执行以下操作来查看此内容:

    $ cat test2.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <quadmath.h>
    int main(void){
        __float128 r;
        r = strtoflt128 ("1.2345678", NULL);
        int * b = malloc(sizeof(int) * 5); 
        double a = 10*M_PI_2q;
        printf("Hello world  %f\n",a);
        return 0;
    }
    $ export LD_LIBRARY_PATH=
    $ which gcc 
    /opt/gcc/5.5.0/bin/gcc
    $ gcc -Wl,-rpath,/opt/gcc/5.5.0/lib64 test2.c -lquadmath
    $ ldd a.out 
    linux-vdso.so.1 =>  (0x00007fffff34f000)
    libquadmath.so.0 => /opt/gcc/5.5.0/lib64/libquadmath.so.0 (0x00002b9c35e07000)
    libc.so.6 => /lib64/libc.so.6 (0x00002b9c36069000)
    libm.so.6 => /lib64/libm.so.6 (0x00002b9c363fd000)
    /lib64/ld-linux-x86-64.so.2 (0x00002b9c35be5000)
    $ readelf -a a.out  | grep -i rpath
    0x000000000000000f (RPATH)              Library rpath: [/opt/gcc/5.5.0/lib64]
    
    1. 链接器找到正确库的方式是利用/opt/gcc/5.5.0/bin/gcc的路径并查看相对于它的相对路径。我通过设置export LD_LIBRARY_PATH=并排除rpath参数(即gcc -shared -Wl,--verbose -Wl,-soname,poo.so -o poo.so test.o -lquadmath)进行了检查。即使这样,它也能够链接到正确的libquadmath.so.0库。

    2. ldd poo.so无法找到正确库的原因是因为它希望libquadmath.so.0库的 64位版本不是 { {1}} 即可。这是该库的 32位版本。一旦你检查了两个版本的库并且看到它们分别是ELF64和ELF32(例如/opt/gcc/5.5.0/lib/libquadmath.so.0),这是显而易见的。

    3. 由于我从未指定正在寻找的正确库的路径,因此默认情况下readelf -a /opt/gcc/5.5.0/lib64/libquadmath.so.0 | grep Class查看ld.so(构建于`/etc/ld.conf.d/) &#39;)决定要查看哪些目录。这就是为什么它找到了4.7.2版本的quadmath。

    4. 要在运行时获取正确的库,我需要设置/etc/ld.conf.cache

    5. 摘要,它是在编译时使用export LD_LIBRARY_PATH=/opt/gcc/5.5.0/lib64找到正确的库(b / c它查看了gcc的相对路径)但是在运行时找不到正确的库(b / c LD_LIBRARY_PATH设置不正确)。解决方案是: ld

答案 1 :(得分:0)

--rpath选项指定的路径将硬编码为您创建的二进制文件。在运行时,ld将优先从这些路径中搜索依赖库。这由ld.so确定。

但是当您编译程序时,链接器将从LD_LIBRARY_PATH和您通过-L选项指定的文件夹中搜索依赖库。在编译时,--rpath指定的路径不会生效。这由ld, the GNU linker确定。