linux 搜索so文件,Linux动态库文件搜索路径

首先回答前面的问题,一共有多少种方法来指定告诉linux共享库链接器ld.so已经编译好的库libbase.so的位置呢?

答案是一共有五种,它们都可以通知ld.so去哪些地方找下已经编译好的c语言函数动态库,它们是:

1)ELF可执行文件中动态段中DT_RPATH所指定的路径。即在编译目标代码时, 对gcc加入链接参数“-Wl,-rpath”指定动态库搜索路径,eg:gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c

2)环境变量LD_LIBRARY_PATH 指定的动态库搜索路径

3)/etc/ld.so.cache中所缓存的动态库路径,这个可以通过先修改配置文件/etc/ld.so.conf中指定的动态库搜索路径,然后执行ldconfig命令来改变。

4)默认的动态库搜索路径/lib

5)默认的动态库搜索路径/usr/lib

另外:在嵌入式Linux系统的实际应用中,1和2被经常使用,也有一些相对简单的的嵌入式系统会采用4或5的路径来规范动态库,3在嵌入式系统中使用的比较少, 因为有很多系统根本就不支持ld.so.cache。

那么,动态链接器ld.so在这五种路径中,是按照什么样的顺序来搜索需要的动态共享库呢?答案这里先告知就是按照上面的顺序来得,即优先级是:1-->2-->3-->4-->5。我们可以写简单的程序来证明这个结论。

首先,写成5个函数,这5个函数名称都叫pt,但是里面的内容不一样:

pt1.c

#include void pt(){

printf("1 path on the gcc give \n");

}

pt2.c

#include void pt(){

printf("2 path on the LD_LIBRARY_PATH \n");

}

pt3.c

#include void pt(){

printf("3 path on the /etc/ld.so.conf \n");

}

pt4.c

#include void pt(){

printf("4 path on the /lib \n");

}

pt5.c

#include void pt(){

printf("5 path on the /usr/lib \n");

}

然后,分别编译这5个函数,然后将它们分别移到上面5种情况对应的5个不同目录下:

gcc -fPIC -c pt1.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /tmp/st/1/

gcc -fPIC -c pt2.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /tmp/st/2/

gcc -fPIC -c pt3.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /tmp/st/3/

gcc -fPIC -c pt4.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /lib/

gcc -fPIC -c pt5.c -o pt.o

gcc -shared pt.o -o libpt.so

mv libpt.so /usr/lib/

再次,编写一个main函数m,让它来调用函数pt:

m.c

#include /*void pt();*/

int main(){

printf("start....\n");

pt();

printf("......end\n");

return 0;

}

最后,准备环境,让ld都知道这5个路径:

(a) 往/etc/ld.so.conf总增加一行,内容:/tmp/st/3,然后执行 ldconfig 命令

(b) export LD_LIBRARY_PATH=/tmp/st/2

另外3中路径,ld都可以得到,请接着看下面。

之后测试:

gcc m.c -o m1 -L/tmp/st/1 -lpt -Wl,-rpath,/tmp/st/1

./m1

start....

1 path on the gcc give

......end

这里在可执行文件中动态段中DT_RPATH所指定的路径,因此需要在编译m.c的时候就指定路径,由于其他路径都也告诉了ld,很明显,此种方法优先级最高了。

gcc m.c -o m -L/tmp/st/1 -lpt

./m

start....

2 path on the LD_LIBRARY_PATH

......end

这里很显然调用了LD_LIBRARY_PATH指定了路径中的共享库,因此此种情况优先级第二。

mv /tmp/st/2/libpt.so /tmp/st/2/libpt2.so

/m

start....

3 path on the /etc/ld.so.conf

......end

这里是调用了/etc/ld.so.cache中所缓存的动态库路径中的共享库,因此此种情况优先级第三。

mv /tmp/st/3/libpt.so /tmp/st/3/libpt3.so

./m

start....

4 path on the /lib

......end

这里是调用/lib中的共享库,优先级第四。

rm /lib/libpt.so

./m

start....

5 path on the /usr/lib

......end

这里是调用/usr/lib中的共享库,优先级第五。

故证明这五种路径指定方法的优先级是1-->2-->3-->4-->5!

# ldconfig -p 发现有两个libevent, 应用程序会使用其中哪一个呢?

综合多个人给出的答案, 如果两个libevent的soname相同, 那么将会调用ldconfig -p 先打印出来的那个:

# ldconfig -p | grep libevent

libevent-1.4.so.2 (libc6,x86-64) => /usr/local/lib/libevent-1.4.so.2

libevent-1.4.so.2 (libc6,x86-64) => /usr/lib64/libevent-1.4.so.2

# ldd /usr/local/bin/memcached

linux-vdso.so.1 =>  (0x00007fff51d7b000)

libevent-1.4.so.2 => /usr/local/lib/libevent-1.4.so.2 (0x00002ac681ea6000)

libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003672200000)

libc.so.6 => /lib64/libc.so.6 (0x0000003671600000)

libnsl.so.1 => /lib64/libnsl.so.1 (0x0000003675200000)

librt.so.1 => /lib64/librt.so.1 (0x0000003672600000)

libresolv.so.2 => /lib64/libresolv.so.2 (0x0000003677600000)

/lib64/ld-linux-x86-64.so.2 (0x0000003671200000)

# cd /usr/local/lib

# rename libevent bak_libevent libevent*

# ldconfig

# ldd /usr/local/bin/memcached

linux-vdso.so.1 =>  (0x00007fff9316f000)

libevent-1.4.so.2 => /usr/lib64/libevent-1.4.so.2 (0x00002b1fafb0b000)

libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003672200000)

libc.so.6 => /lib64/libc.so.6 (0x0000003671600000)

libnsl.so.1 => /lib64/libnsl.so.1 (0x0000003675200000)

librt.so.1 => /lib64/librt.so.1 (0x0000003672600000)

libresolv.so.2 => /lib64/libresolv.so.2 (0x00000036

命名约定

在开始探讨共享对象之前,简要地看一下库的命名规则。静态库一般由字母 lib开头,并有 .a 的扩展名。共享对象有两个不同的名称: soname和 real name。 soname 包含前缀 "lib",然后紧跟库名,其次是 ".so"(后面紧跟另一个圆点),以及表明主版本号的数字。soname 可以由前缀的路径信息来限定。real name 是包含库的已编译代码的真正文件名。real name 在 soname 后添加一个圆点、小的数字、另外一个圆点和发布号。(发布号和其相应的圆点是可选的。)

我们会看到由 Program-Library How-To 定义的名称,称作 linker name ,它指的是不带版本号的 soname。客户所使用的库名是指 linker name。通常,这是与 linket name 的链接。而 soname 是到 real name 的链接。

这里拿 soname /usr/lib/libhello.so.1来作为示例。这是一个全限定 soname,它链接到 /usr/lib/libhello.so.1.5 。其相应的 linker name 是 /usr/lib/libhello.so 。这里似乎要管理许多名称,但有工具可以帮助您管理他们。(请参阅本文后面将要讲述的 实用程序和工具 中的 ldconfig 。)

现在我们来看实质性内容,并编写一个样本共享对象。库的 soname 是 libprint.so.1 ,real name 是 libprint.so.1.0 。库有一个 printstring(char*) 的函数,它将打印字 "String: ",后面紧跟着以参数形式传递给它的任何字符串。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值