为什么 --rpath 在构建共享库时被取代?
Why is --rpath being superseded when building shared library?
我在 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
到 link 到 /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)用处不大。
问题 : 我在 link 构建共享库时指定 -rpath
,但我不明白为什么它会找到较旧的 gcc -4.7.2 版本的 quadmath 库。为什么 linker 似乎优先考虑 /etc/ld.so.conf
中的路径而忽略 -rpath
选项?我如何在编译时指定库位置以及如何解决这个问题?
要理解解决方案,首先要理解错误的思路。
我没有意识到 两个 实用程序正在执行 linking。有ld
(在编译时使用)和ld.so
(在运行时使用)。 ld.so
的手册页描述了在 运行 时如何找到库。总结一下搜索:
a) DT_RPATH
中指定的目录
b) LD_LIBRARY_PATH
中指定的目录
c) DT_RUNPATH 二进制动态部分中的目录(如果存在)
d) 缓存文件 /etc/ld.so.cache
e)默认路径/lib然后/usr/lib
ld
的手册页主要让我感到困惑。它在 -rpath 选项下说:
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects
我认为在构建共享库时传递 -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]
linker 找到正确库的方法是利用 /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
)来检查这一点。即使那样,它也能够 link 到正确的 libquadmath.so.0
库。
ldd poo.so
找不到正确库的原因是因为它想要 libquadmath.so.0
的 64 位 版本图书馆不是 /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
),这一点就很明显了。
因为我从来没有指定它正在寻找的正确库的路径,所以 ld.so
默认查看 /etc/ld.conf.cache
(它建立在 `/etc/ld .conf.d/') 来决定要查看的目录。这就是它找到 quadmath 4.7.2 版本的原因。
要在运行时获取正确的库,我需要设置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
在构建共享库时不是有效选项。
--rpath 选项指定的路径将被硬编码到您创建的二进制文件中。 运行时,ld
会优先从那些路径中搜索依赖库。这是由 ld.so.
决定的
但是当你编译程序时,链接器会从LD_LIBRARY_PATH和你用-L选项指定的文件夹中搜索依赖库。编译时,--rpath 指定的路径不生效。这是由 ld, the GNU linker.
决定的
我在 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
到 link 到 /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)用处不大。
问题 : 我在 link 构建共享库时指定 -rpath
,但我不明白为什么它会找到较旧的 gcc -4.7.2 版本的 quadmath 库。为什么 linker 似乎优先考虑 /etc/ld.so.conf
中的路径而忽略 -rpath
选项?我如何在编译时指定库位置以及如何解决这个问题?
要理解解决方案,首先要理解错误的思路。
我没有意识到 两个 实用程序正在执行 linking。有
ld
(在编译时使用)和ld.so
(在运行时使用)。ld.so
的手册页描述了在 运行 时如何找到库。总结一下搜索:a)
中指定的目录DT_RPATH
b)
中指定的目录LD_LIBRARY_PATH
c) DT_RUNPATH 二进制动态部分中的目录(如果存在)
d) 缓存文件
/etc/ld.so.cache
e)默认路径/lib然后/usr/lib
ld
的手册页主要让我感到困惑。它在 -rpath 选项下说:Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects
我认为在构建共享库时传递
-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]
linker 找到正确库的方法是利用
/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
)来检查这一点。即使那样,它也能够 link 到正确的libquadmath.so.0
库。ldd poo.so
找不到正确库的原因是因为它想要libquadmath.so.0
的 64 位 版本图书馆不是/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
),这一点就很明显了。因为我从来没有指定它正在寻找的正确库的路径,所以
ld.so
默认查看/etc/ld.conf.cache
(它建立在 `/etc/ld .conf.d/') 来决定要查看的目录。这就是它找到 quadmath 4.7.2 版本的原因。要在运行时获取正确的库,我需要设置
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
在构建共享库时不是有效选项。
--rpath 选项指定的路径将被硬编码到您创建的二进制文件中。 运行时,ld
会优先从那些路径中搜索依赖库。这是由 ld.so.
但是当你编译程序时,链接器会从LD_LIBRARY_PATH和你用-L选项指定的文件夹中搜索依赖库。编译时,--rpath 指定的路径不生效。这是由 ld, the GNU linker.
决定的