库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。 例如:libtest.so libtest.a。为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,但由于程序连接默认以.so为文件后缀名。所以为了使用这些库,通常使用建立符号连接的方式。如:
ln -s libtest.so.1.0 hello.so.1
ln -s libtest.so.1 hello.so 下面对比一下两者:
静态链接库:当要使用时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。
动态库而言:某个程序在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。在程序运行的时候,被调用的动态链接库函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须使用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器,这些对象文件是用来做动态链接库的,所以要用地址不无关代码(Position Independent Code (PIC))。注意:linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。
下面就通过实际的例子来向大家演示一下,该怎样编译和使用静态和动态链接库,这里有一个头文件:lib_test.h,一个.c文件:lib_test.c:
1.编写库文件lib_test.c 2.编写一个头文件用于声明我们使用的函数lib_test.h 3.用gcc编绎该文件,可以使用任何合法的编绎参数
#include #ifndef _LIBTEST_H gcc -c lib_test.c -o lib_test.o
void a() #define _LIBTEST_H
{ void a();
printf("zyx\n"); #endif
}
下面就用上面的文件生成和使用静态和动态链接库:
(一)静态链接库
1)用gcc编绎该文件,可以使用任何合法的编绎参数
gcc -c lib_test.c -o lib_test.o
2) $ar crv libtest.a lib_test.o //生成静态库生成libtest.a
3) 在某些系统中还要为静态库生成一个内容表 $ranlib libtest.a
4) 使用静态链接库
$nm libtest.a //nm工具可以打印出库中的涉及到的所有符号,库既可以是静态的也可以是动态的。nm列出的符号有很多, 常见的有三种,一种是在库中被
调用,但并没有在库中定义(表明需要其他库支持),用U表示;一种是库中定义的函数,用T表示,这是最常见的;另外一种是所谓的"弱态”
符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示。
$gcc -c -I/home/xxxxxxxx main.c //假设main.c要使用对应的静态库
$gcc -o main -L/home/xxxxxxxx main.o libtest.a
说明:这里的-I/home/xxxxxxxx和-L/home/xxxxxxxx 是通过-I和-L指定对应的头文件和库文件的路径,libtest.a就是要用的静态库。在main.c中要包含静态库
的头文件。
5)然后执行程序就可以看到成功了。#./main
(二)动态链接库 可以依次使用下面的命令
1)$gcc -fPIC -o libtest.o -c lib_test.c
2)$gcc -shared -o libtest.so libtest.o
也可以直接使用一条命令gcc -fPIC -shared -o libtest.so lib_test.c
3)有两种方法使用动态链接库。
a)#gcc -o main main.c ./libtest.so
b)先#cp ./libtest /usr/lib 然后gcc -o test test.c libtest.so这时要保证这个库所在目录包括再PATH 环境变量中。
4)然后执行程序就可以看到成功了。#./main
最后说一下库的路径问题,算是结个尾吧:
动态库的搜索路径搜索的先后顺序是:
1.编译目标代码时指定的动态库搜索路径;
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;//只需在在该文件中追加一行库所在的完整路径如"/root/test/conf/lib"即可,然后ldconfig是修改生效。
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib。