1. 库?
库是写好的,现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库。例如最常见的printf()
库函数。
2. 静态库与动态库?
2.1. 静态库(.a)
程序在链接的时候把静态库文件链接到我们的程序的目标文件(.o)中,最终形成可执行文件。也就是相当于直接将写好的代码加到了我们的程序中。
静态库的特点:
- 静态库文件的链接是放在编译时期完成的
- 程序在运行时与函数库再无瓜葛,移植方便
- 浪费空间和资源,因为同时运行100个程序可能要把那些常用的静态库链接100遍,费时费力
2.2. 动态库/共享库(.so)
程序在链接的时候,仅仅把动态库中所用到的函数的入口地址做成一张表,而不是把整个库函数链接到程序中。等到程序运行的时候,动态库会被加载到内存中,而程序通过页表的映射就可以访问到这些库函数本体。这也说明了动态库的另一个名字共享库的由来,如果有多个用到同一共享库的程序,操作系统可以只在内存中存储一份共享库,而让这些程序的页表都映射到同一份共享库代码,这样就实现了代码的共享,比较节省空间。
动态库的特点:
- 动态库把对一些库函数的链接载入推迟到程序运行的时期
- 可以实现进程之间的资源共享。(因此动态库也称为共享库)
- 将一些程序升级变得简单
3. 静态库的生成与使用
先写两个功能函数供之后打包成静态库。
// add.c
int add(int a, int b) {
return a + b;
}
// sub.c
int sub(int a, int b) {
return a - b;
}
现在将这两个函数先分别生成对应的目标文件,再打包成一个静态库。
syndi@ubuntu:~/workspace/sys_code/lib$ gcc -c add.c -o add.o
syndi@ubuntu:~/workspace/sys_code/lib$ gcc -c sub.c -o sub.o
syndi@ubuntu:~/workspace/sys_code/lib$ ls
add.c add.o sub.c sub.o
syndi@ubuntu:~/workspace/sys_code/lib$ ar -rc libmymath.a add.o sub.o
syndi@ubuntu:~/workspace/sys_code/lib$ ls
add.c add.o libmymath.a sub.c sub.o
静态库文件名必须以lib
开头,.a
结尾。
使用下面的命令可以查看静态库中包含了哪些目标代码:
syndi@ubuntu:~/workspace/sys_code/lib$ ar -tv libmymath.a
rw-r--r-- 0/0 1248 Jan 1 08:00 1970 add.o
rw-r--r-- 0/0 1240 Jan 1 08:00 1970 sub.o
下面,编写一个调用库函数的测试程序:
// main.c
#include <stdio.h>
extern int add(int, int);
extern int sub(int, int);
int main() {
int x = add(3, 4);
printf("3 + 4 = %d\n", x);
int s = sub(3, 1);
printf("3 - 1 = %d\n", s);
return 0;
}
之后,将测试程序和静态库一起编译:
syndi@ubuntu:~/workspace/sys_code/lib$ gcc main.c -L. -lmymath -o main
syndi@ubuntu:~/workspace/sys_code/lib$ ls
add.c add.o libmymath.a main main.c sub.c sub.o
syndi@ubuntu:~/workspace/sys_code/lib$ ./main
3 + 4 = 7
3 - 1 = 2
可以看到,程序运行良好。
Linux下使用静态库,只需要在用gcc编译的时候用-L
选项指定库的搜索路径(上面的例子中使用的是当前路径.),然后用-l
选项指定静态库名(不需要lib
前缀和.a
后缀)即可。
4. 动态库的生成与使用
首先是生成动态库:
syndi@ubuntu:~/workspace/sys_code/lib$ gcc -fPIC -c add.c -o add.o
syndi@ubuntu:~/workspace/sys_code/lib$ gcc -fPIC -c sub.c -o sub.o
syndi@ubuntu:~/workspace/sys_code/lib$ ls
add.c add.o sub.c sub.o
syndi@ubuntu:~/workspace/sys_code/lib$ gcc --share add.o sub.o -o libmymathd.so
syndi@ubuntu:~/workspace/sys_code/lib$ ls
add.c add.o libmymathd.so sub.c sub.o
选项-fPIC
表示生成位置无关代码。--share
表示要生成动态库,动态库文件名以lib
开头.so
结尾。
下来链接动态库:
syndi@ubuntu:~/workspace/sys_code/lib$ gcc -c main.c -o main.o
syndi@ubuntu:~/workspace/sys_code/lib$ gcc main.o -L. -lmymathd -o main
syndi@ubuntu:~/workspace/sys_code/lib$ ls
add.c add.o libmymathd.so main main.c main.o sub.c sub.o
但此时如果直接运行main程序会报错:
syndi@ubuntu:~/workspace/sys_code/lib$ ./main
./main: error while loading shared libraries: libmymathd.so: cannot open shared object file: No such file or directory
提示找不到共享库,所以此时还要再加一步,告诉操作系统我依赖的共享库在哪:
- 添加系统变量
LD_LIBRARY_PATH
指定共享库文件的位置 - 或者将共享库放到
/usr/lib
中
上面两种方法任选其一
syndi@ubuntu:~/workspace/sys_code/lib$ export LD_LIBRARY_PATH=.
syndi@ubuntu:~/workspace/sys_code/lib$ ls
add.c add.o libmymathd.so main main.c main.o sub.c sub.o
syndi@ubuntu:~/workspace/sys_code/lib$ ./main
3 + 4 = 7
3 - 1 = 2
此时就可以了。