Linux系统编程——静态库和动态库
函数库分为静态库和动态库
动态库(格式为libname.so[.主版本号.次版本号.发行号])。在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入。
静态库是目标文件.a的归档文件(格式为libname.a)。如果在编译某个程序时链接静态库,则链接器将会搜索静态库并直接拷贝到该程序的可执行二进制文件到当前文件中;
看定义不太好理解,下面举例说明上述概念:
动态库
动态库(格式为libname.so[.主版本号.次版本号.发行号])。在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入。
$ gcc -fPIC -Wall -c add.c
$ gcc -shared -o libadd.so add.o
$ gcc -o main main.c –ladd
在运行main前,需要注册动态库的路径。将库文件拷贝到/lib或者/usr/lib下(系统默认搜索库路径)。
$ cp libadd.so /lib //通常采用的方法, cp lib*.so /lib
$ ./main
实例测试:
add.c
int add(int a, int b){
return a + b;
}
main.c
#include <stdio.h>
int add(int a, int b);
int main()
{
int res = add(3, 4);
printf("res = %d\n", res);
return 0;
}
这里我们要将add.c生成动态库使得main.c能编译运行。
gcc -fPIC -Wall -c add.c
gcc -shared add.o -o libadd.so
sudo cp libadd.so /usr/lib
gcc main.c -ladd
执行时将动态库(libadd.so)与a.out同时加载到代码段才能运行。当多个代码段需要用到一个libXXX时,并不会生成多个libXXX放入代码段,而是通过共享库。
当动态库升级时,以格式为libname.so[.主版本号.次版本号.发行号]命名,如现在将原来的libadd.so修改为libadd.so.1,那怎么让原来main.c文件中的add函数还能实现呢?——软链接
先穿插一个概念:
软链接
命令: $ ln -s filename1 filename2
功能: filename2 -> filename1
可以看到当链接建立时,file1 -> file,file1的大小为4B,file的大小为739B。可以用过 ls -lh查看链接。
软链接存储是路径,相当于file1是file的一个快捷方式,所以在查看file1的时候也是显示file的内容。
回到原来的问题,现在将原来的libadd.so修改为libadd.so.1,只要将libadd.so.1与libadd.so软链接即可。
sudo ln -s libadd.so.1 libadd.so
静态库
gcc -c add.c //编译add.c生成add.o
ar crsv libadd.a add.o //对目标文件*.o进行归档,生成lib*.a,将库文件libadd.a拷贝到/lib或者/usr/lib下(系统默认搜索库路径)
gcc -o main main.c -ladd //-ladd表示链接库文件libadd.a/.so
./main
还是用上面同一个例子做测试:
main.c
#include <stdio.h>
int add(int, int);
int main()
{
int j = add(3, 4);
printf("%d\n", j);
return 0;
}
静态库是目标文件.a的归档文件(格式为libname.a)。如果在编译某个程序时链接静态库,则链接器将会搜索静态库并直接拷贝到该程序的可执行二进制文件到当前文件中;
所以当我们在删除库文件中libadd.a后还是可以编译执行main.c!
静态库与动态库的比较:
动态库只在执行时才被链接使用,不是直接编译为可执行文件,并且一个动态库可以被多个程序使用故
可称为共享库。
静态库将会整合到程序中,在程序执行时不用加载静态库。 因此,静态库会使你的程序臃肿并且难以升
级,但比较容易部署。而动态库会使你的程序轻便易于升级但难以部署。
二者的不同点在于代码被载入的时刻不同。
- 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。
- 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小。