WD1X.COM - 问答一下,轻松解决,电脑应用解决专家
主板显卡CPU内存显示器
硬盘维修显卡维修显示器维修
注册表系统命令DOS命令Win8
存储光存储鼠标键盘
内存维修打印机维修
WinXPWin7Win11Linux
硬件综合机箱电源散热器手机数码
主板维修CPU维修键盘鼠标维修
Word教程Excel教程PowerPointWPS
网络工具系统工具图像工具
数据库javascript服务器
PHP教程CSS教程XML教程

linux动态链接库的加载顺序

更新时间:2021-03-18 14:08 作者:佚名点击:
一、 Linux 动态库选择顺序指:
1.  编译程序时用到动态库,该从那些地方查找,按照怎么样的顺序查找?
 
2.  运行程序时需要动态库,该从那些地方查找,按照怎么样的顺序查找?
 
二、gcc 编译程序时查找SO顺序如下:
1.  gcc 编译时参数-L指定的路径
 
2.  环境变量 LIBRARY_PATH
 
3.  系统默认库位置 /lib    /usr/lib
 
三、Linux 程序运行时查找SO顺序如下:
1.  gcc 编译时指定的运行时库路径 -Wl,-rpath
 
2.  环境变量 LD_LIBRARY_PATH
 
3.  ldconfig 缓存 /etc/ld.so.cache
 
4  系统默认库位置 /lib    /usr/lib
 
四、LIBRARY_PATH和LD_LIBRARY_PATH环境变量的区别
LIBRARY_PATH和LD_LIBRARY_PATH是Linux下的两个环境变量,二者的含义和作用分别如下:
 
LIBRARY_PATH环境变量用于在程序编译期间查找动态链接库时指定查找共享库的路径,例如,指定gcc编译需要用到的动态链接库的目录。设置方法如下(其中,LIBDIR1和LIBDIR2为两个库目录):
 
export LIBRARY_PATH=LIBDIR1:LIBDIR2:$LIBRARY_PATH
LD_LIBRARY_PATH环境变量用于在程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径,注意,LD_LIBRARY_PATH中指定的路径会在系统默认路径之前进行查找。设置方法如下(其中,LIBDIR1和LIBDIR2为两个库目录):
 
export LD_LIBRARY_PATH=LIBDIR1:LIBDIR2:$LD_LIBRARY_PATH
举个例子,我们开发一个程序,经常会需要使用某个或某些动态链接库,为了保证程序的可移植性,可以先将这些编译好的动态链接库放在自己指定的目录下,然后按照上述方式将这些目录加入到LD_LIBRARY_PATH环境变量中,这样自己的程序就可以动态链接后加载库文件运行了。
 
区别与使用:
 
开发时,设置LIBRARY_PATH,以便gcc能够找到编译时需要的动态链接库。
 
发布时,设置LD_LIBRARY_PATH,以便程序加载运行时能够自动找到需要的动态链接库。
 
注意:新设置变量 LD_LIBRARY_PATH ,下次开机,一切设置将不复存在;如何把这个值持续写到 LD_LIBRARY_PATH 里呢?
 
我们就会想有不有什么一劳永逸地方法,使得设置之后就不用再去设置了?答案是肯定的。有两种:
 
1、在~/目录下打开.bash_profile文件,设置环境变量如下:
 
LD_LIBRARY_PATH=dir:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
LD_LIBRARY_PATH  这个环境变量是大家最为熟悉的,它告诉loader:在哪些目录中可以找到共享库。可以设置多个搜索目录,这些目录之间用冒号分隔开。
 
2、在linux下,还 提供了另外一种方式来完成同样的功能,你可以把这些目录加到/etc/ld.so.conf中,然后调用ldconfig。
 
五、链接选项-I,-l,-L,-Wl:rpath
-I,添加包含路径
 
-I 在编译时用,告诉编译器去哪个路径下找文件
 
如:-I /home/hello/include
 
表示将/home/hello/include目录作为第一个寻找头文件的目录。
 
编译器的寻找顺序是:/home/hello/include-->/usr/include-->/usr/local/include。如果在/home/hello/include中有个文件hello.h,则在程序中用#include<hello.h>就能引用到这个文件。
 
可以加多个包含路径,编译器的寻找顺序为添加的顺序。
 
-l,添加引用链接库
 
-l 在链接时用到,它的作用是告诉链接器,要用到哪个库。
如:-l pthread
 
告诉链接器(linker),程序需要链接pthread这个库,这里的pthread是库名不是文件名,具体来说文件句是libpthread.so。
 
-L,添加链接库路径
-L 后跟路径,告诉链接器从哪找库(.so文件),只有在链接时会用到。
 
如:-L /home/hello/lib
 
表示将/home/hello/lib目录作为第一个寻找库文件的目录,寻找顺序是:/home/hello/lib-->/usr/lib-->/usr/local/lib。
 
可以加多个包含路径,链接器的寻找顺序为添加的顺序。
 
 
 
-Wl:rpath,添加运行时库路径
 
-Wl:rpath 后面也是路径,运行的时候用。这条编译指令会在编译时记录到target文件中,所以编译之后的target文件在执行时会按这里给出的路径去找库文件。
 
如:-Wl:rpath=/home/hello/lib
 
表示将/home/hello/lib目录作为程序运行时第一个寻找库文件的目录,程序寻找顺序是:/home/hello/lib-->/usr/lib-->/usr/local/lib。
 
可以加多个包含路径,程序在运行时的寻找顺序为添加的顺序。
 

参考文献二:
 

inux动态链接库的加载顺序:
它有5个地方会查找,
1. 编译时指定的run path
2. LD_LIBRARY_PATH 指定的地方
3. ldconfig 指定的地方
4. /lib
5. /usr/lib
 
下面是测试实例,验证上面5句话。 (注: 用strace 会更好的看到加载顺序!!! --hjjdebug)
 
------------------------------------------------------------
1. 编写5个so源文件和1个测试文件
------------------------------------------------------------
 
hjj@hjj-Inspiron:~/MyTest/temp$ cat pos1.c
#include <stdio.h>
 
void tellpos()
{
    printf("I am pos1 ");
}
hjj@hjj-Inspiron:~/MyTest/temp$ cat pos2.c
#include <stdio.h>
 
void tellpos()
{
    printf("I am pos2 ");
}
hjj@hjj-Inspiron:~/MyTest/temp$ cat pos3.c
#include <stdio.h>
 
void tellpos()
{
    printf("I am pos3 ");
}
hjj@hjj-Inspiron:~/MyTest/temp$ cat pos4.c
#include <stdio.h>
 
void tellpos()
{
    printf("I am pos4 ");
}
hjj@hjj-Inspiron:~/MyTest/temp$ cat pos5.c
#include <stdio.h>
 
void tellpos()
{
    printf("I am pos5 ");
}
hjj@hjj-Inspiron:~/MyTest/temp$ cat main.c
#include <stdio.h>
void tellpos();
int main(int argc, char *argv)
{
tellpos();
return 0;
}
2. 生成5个so文件并放到5个地方,生成test 测试文件
 
$ cat Makefile
CC=gcc
CFLAG=-fPIC -c
LDFLAG=-shared
all: fivepos test
fivepos
-mkdir pos1 pos2 pos3
$(CC) $(CFLAG) -o pos.o pos1.c
$(CC) $(LDFLAG) pos.o -o libpos.so
mv libpos.so pos1
$(CC) $(CFLAG) -o pos.o pos2.c
$(CC) $(LDFLAG) pos.o -o libpos.so
mv libpos.so pos2
$(CC) $(CFLAG) -o pos.o pos3.c
$(CC) $(LDFLAG) pos.o -o libpos.so
mv libpos.so pos3
$(CC) $(CFLAG) -o pos.o pos4.c
$(CC) $(LDFLAG) pos.o -o libpos.so
sudo mv libpos.so /lib
$(CC) $(CFLAG) -o pos.o pos5.c
$(CC) $(LDFLAG) pos.o -o libpos.so
sudo mv libpos.so /usr/lib
test: main.c
gcc -o test main.c -L pos1 -lpos -Wl,-rpath,pos1
# -L pos1 是说连接时到 pos1 目录去找
# -Wl,-rpath,pos1 是说运行时到pos1目录去找 
 
3. 其它说明:
    pos1 通过readelf -d test 可以看到(RPATH) Library rpath: [pos1]
    pos2 需要用LD_LIBRARY_PATH 说明。此例为: export LD_LIBRARY_PATH=./pos2
    pos3 需要在/etc/ld.so.conf 中指明,此例为:/home/hjj/MyTest/temp/pos3
         然后ldconfig 生成缓存使设置生效。
    pos4 系统目录/lib
    pos5 系统目录/usr/lib
 
------------------------------------------------------------
4. 用ldd 检查 和用 ./test 直接测试及结果
------------------------------------------------------------
那个64为地址是动态地址,每次ldd 都会变的。
ldd test
    libpos.so => pos1/libpos.so (0x00007f93f4204000)
./test
I am pos1
rm pos1/libpos.so  // 第一个地方删除掉该so, 它会从剩下的4个地方继续选择
 
ldd test
    libpos.so => ./pos2/libpos.so (0x00007f580053d000)
./test
I am pos2
rm pos2/libpos.so //它会从剩下的3个地方继续选择
 
$ ldd test
    libpos.so => /home/hjj/MyTest/temp/pos3/libpos.so (0x00007efef7dbf000)
$ ./test
I am pos3
rm pos3/libpos.so //它会从剩下的2个地方继续选择
 
ldd test
    libpos.so => /lib/libpos.so (0x00007f70d60ce000)
./test
I am pos4
sudo rm /lib/libpos.so //它会从剩下的1个地方继续选择
 
ldd test
    libpos.so => /usr/lib/libpos.so (0x00007f3849e1e000)
./test
I am pos5
sudo rm /usr/lib/libpos.so
 
ldd test
libpos.so => not found
./test
error while loading shared libraries: libpos.so: cannot open shared object file: No such file or directory
 
我们用strace ./test 来跟踪系统调用,非常清晰的看到了动态库的加载过程。(这就不贴文字了). 看到链接器经过了很多的努力后,
最后给出找不到动态库的结论。
本贴演示了如何生成动态库so文件及如何使用动态库。 给出了一种比较笨的直接了当的方法,也给出了聪明的strace方法。

顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
你可能感兴趣的内容