【问题标题】:Why is --rpath being superseded when building shared library?为什么在构建共享库时 --rpath 被取代?
【发布时间】:2018-11-10 16:25:36
【问题描述】:

我正在使用 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 选项?如何在编译时指定库位置以及如何解决此问题?

【问题讨论】:

    标签: gcc ld


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      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 选项,但我不知道如何使它工作。

      您可以通过执行以下操作来查看:

      $ 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 找不到正确库的原因是因为它想要 64 位 版本的 libquadmath.so.0 库不是 /opt/gcc/5.5.0/lib/libquadmath.so.0强>。那是库的 32 位 版本。一旦您检查了库的两个版本并看到它们分别是 ELF64 和 ELF32(例如readelf -a /opt/gcc/5.5.0/lib64/libquadmath.so.0 | grep Class),这一点就很明显了。

      3. 1234563要查找的目录。这就是它找到 4.7.2 版本的 quadmath 的原因。
      4. 要在运行时获取正确的库,我需要设置export LD_LIBRARY_PATH=/opt/gcc/5.5.0/lib64

      总结,它在编译时使用 ld 找到了正确的库(b/c 它查看了 gcc 的相对路径)但在运行时找不到正确的库(b /c LD_LIBRARY_PATH 设置不正确)。解决方案是: export LD_LIBRARY_PATH=/opt/gcc/5.5.0/lib64-rpath 不是构建共享库时的有效选项。

      【讨论】:

        猜你喜欢
        • 2015-10-07
        • 2014-11-11
        • 2014-05-25
        • 2010-11-08
        • 2015-10-03
        • 2012-09-20
        • 1970-01-01
        • 1970-01-01
        • 2019-01-27
        相关资源
        最近更新 更多