linux指定动态库路径包括:
1.指定编译时动态库路径;
2.指定运行时动态库路径。后文提到的动态库路径都是指的是这两种路径。
众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib(不管是编译还是运行都会默认搜索这两个路径)。动态库被创建后,一般都复制到这两个目录中。当程序执行时需要某动态库,并且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中,这样程序就可以使用该动态库中的函数,以及该动态库的其它资源了。
在Linux 中,动态库的搜索路径除了默认的搜索路径外,还可以通过以下三种方法来指定。
1.在配置文件/etc/ld.so.conf中指定动态库搜索路径。
可以通过编辑配置文件/etc/ld.so.conf来指定动态库的搜索路径,该文件中每行是一个动态库搜索路径。每次编辑完该文件后,都必须运行命令ldconfig使修改后的配置生效。
以动态库的创建与使用为例:
//so_test.h
#include "stdio.h"
void test_a();
void test_b();
void test_c();
//test_a.c
#include "so_test.h"
void test_a()
{
printf("this is in test_a...\n");
}
//test_b.c
#include "so_test.h"
void test_b()
{
printf("this is in test_b...\n");
}
//test_c.c
#include "so_test.h"
void test_c()
{
printf("this is in test_c...\n");
}
测试程序
//test.c
#include “so_test.h”
int main()
{
test_a();
test_b();
test_c();
return 0;
}
操作过程:
我们通过以下命令用源程序test_a.c、test_b.c、test_c.c来创建动态库 libtest.so。
# gcc -c test_a.c test_b.c test_c.c
# gcc -shared -fPIC -o libtest.so *.o
或者直接一条指令:
#gcc -shared -fPIC -o libtest.so test_a.c test_b.c test_c.c
这样在当前目录下就生成了动态库libtest.so。对于头文件位置的存放请参考博文《linux头文件》。
注意:
-fPIC参数声明链接库的代码段是可以共享的;
-shared参数声明编译为共享库。
请注意这次我们编译的共享库的名字叫做libtest.so,这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式。
接着通过以下命令编译test.c,生成目标程序main。
# gcc -o main -L. –ltest test.c
当应用程序调用动态库的时候,要用-l选项,指定所调用的库名。用-L选项指定库所在的路径(如果没有使用后文所述的三种方法处理的情况下,用这种方式指定库所在路径)。
(注意:此时,头文件以及库文件都在当前目录下)
在当前目录下生成可执行文件main
运行程序main
#./main
./main: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
出错了,系统未找到动态链接库libtest.so。原因是系统会默认的到/lib或/usr/lib中寻找需要的库,但是我们需要的库放在了当前的目录下,也就说虽然编译的时候指定了所需要的动态库,但是执行的时候并不会到之前编译时指定的动态库的位置去寻找动态库,这也就是为什么在文章开头讲清楚,什么是指定编译时动态库路径,什么是指定运行时动态库路径。解决的方法就是找到动态库。怎样找到动态库呢?最简单的解决的方法是将动态库拷贝到/lib或/usr/lib目录下,这样在编译时不需要指定动态库的路径,运行时也不会找不到动态库(不管编译还是执行都会到/lib或/usr/lib目录下寻找动态库)。对于编译阶段找到动态库的方法还有上面的通过-L选项指定动态库的路径。对于执行阶段是否可以通过选项指定动态库,下面的方法3会有介绍。除了上面提到的方法外,我们更需要这样一种解决思路:我们可以灵活的指定动态库的存放的位置,然后由操作系统负责动态库的查找。当然强大的linux提供了这样的功能,并且这种功能的实现不止一种,详细内容可以参考博文《/etc/ld.so.conf文件》。现在简单介绍/etc/ld.so.conf的使用,我们打算将制作好的动态库放在/root/lib目录下,因此执行如下命令:
# mkdir /root/lib
# mv libtest.so /root/lib/libtest.so
最后编辑配置文件/etc/ld.so.conf,在该文件中追加一行/root/lib。
运行程序main
# ./main
./main: error while loading shared libraries: lib_test.so: cannot open shared object file: No such file or directory
仍然出错,系统未找到动态库libtest.so。找找原因,原来在编辑完配置文件/etc/ld.so.conf后,没有运行命令ldconfig,所以刚才的修改还未生效。我们运行ldconfig后再试试。
# ldconfig
# ./main
this is in test_a...
this is in test_b...
this is in test_c...
#
程序main运行成功,并且打印出正确结果。
2.通过环境变量LD_LIBRARY_PATH指定动态库搜索路径。
通过设定环境变量LD_LIBRARY_PATH也可以指定动态库搜索路径。当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号”:”分隔。下面通过例2来说明本方法。
举一个例子:
这次我们把上面得到的文件lib_test.so移动到另一个地方去,如/root下面,然后设置环境变量LD_LIBRARY_PATH找到libtest.so。设置环境变量方法如下:
# export LD_LIBRARY_PATH=/root
#
然后运行:
#./main.out
this is in test_a...
this is in test_b...
this is in test_c...
#
注意:设置环境变量LD_LIBRARY_PATH=/root是不行的,非得export才行。这种设置LD_LIBRARY_PATH环境变量只是临时性的,下次开启LD_LIBRARY_PATH的值会失效,因此可以将环境变量写入到/etc/bash.bashrc文件中。
3.在编译目标代码时指定该程序运行时的动态库搜索路径。
还可以在编译目标代码时指定程序的动态库搜索路径。-Wl,表示后面的参数将传给link程序ld(因为gcc可能会自动调用ld)。这里通过gcc 的参数”-Wl,-rpath,”指定
举一个例子:
这次我们还把上面得到的文件libtest.so移动到另一个地方去,如/root/test/lib下面,
因为我们需要在编译目标代码时指定可执行文件的动态库搜索路径,所以需要用gcc命令重新编译源程序test.c来生成可执行文件main。
# gcc -o main -L. –ltest -Wl,-rpath=/root/test/lib test.c
#
运行结果:
# ./main.out
this is in test_a...
this is in test_b...
this is in test_c...
#
程序./main运行成功。因此程序main搜索到的动态库是/root/test/lib/lib_test.so。
关于-Wl,rpath的使用方法我再举一个例子,应该不难从中看出指定多个路径的方法:
gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c
以上介绍了三种指定动态库搜索路径的方法,加上默认的动态库搜索路径/lib和/usr/lib,共五种动态库的搜索路径,那么它们搜索的先后顺序是什么呢?读者可以用下面的方法来试验一下:
(1) 用前面介绍的方法生成5个libtest.so放在5个不同的文件夹下面,要求每一个libtest.so都唯一对应一个搜索路径,并注意main程序输出的不同。
(2) 运行main,即可看出他是那个搜索路径下的,然后删除这个路径下的libtest.so,然后再运行。依此类推操作,即可推出搜索顺序。
可以得出动态库的搜索路径搜索的先后顺序是:
1.编译目标代码时指定的动态库搜索路径;
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib。
在上述1、2、3指定动态库搜索路径时,都可指定多个动态库搜索路径,其搜索的先后顺序是按指定路径的先后顺序搜索的。有兴趣的读者自己验证。