一、什么是库
库是早已写好的代码,现实中每个程序的代码不可能都是从零开始,都要依赖很多基础的底层库 ,因此库的存在意义非同寻常
二、静态库
程序在编译期间直接把静态库的代码链接到可执行文件中,如此程序运行时将不再依赖静态库
静态库的生成和使用
$ cat add.h
#ifndef __ADD_H__
#define __ADD_H__
int add(int a, int b);
#endif /* __ADD_H__ */
$ cat add.c
#include "add.h"
int add(int a, int b)
{
return a + b;
}
$ cat sub.h
#ifndef __SUB_H__
#define __SUB_H__
int sub(int a, int b);
#endif /* __SUB_H__ */
$ cat sub.c
#include "add.h"
int sub(int a, int b)
{
return a - b;
}
$ gcc -c add.c -o add.o
$ gcc -c sub.c -o sub.o
生成静态库
$ ar -rc libmymath.a add.o sub.o
ar:gnu 归档工具
rc:replace and create
查看静态库
$ ar -tv libmymath.a
rw-r--r-- 1005/1001 1240 Oct 2 11:36 2025 add.o
rw-r--r-- 1005/1001 1240 Oct 2 11:37 2025 sub.o
$ ll
total 28
-rw-r--r-- 1 mam mam 80 Oct 2 11:34 add.c
-rw-r--r-- 1 mam mam 97 Oct 2 11:32 add.h
-rw-r--r-- 1 mam mam 1240 Oct 2 11:36 add.o
-rw-r--r-- 1 mam mam 2688 Oct 2 11:37 libmymath.a
-rw-r--r-- 1 mam mam 80 Oct 2 11:34 sub.c
-rw-r--r-- 1 mam mam 95 Oct 2 11:33 sub.h
-rw-r--r-- 1 mam mam 1240 Oct 2 11:37 sub.o
drwxr-xr-x 2 mam mam 20 Oct 2 11:40 test_liba
drwxr-xr-x 2 mam mam 20 Oct 2 11:40 test_libso
$ pwd
/mam/mylib
$ cd test_liba
$ cat main.c
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main()
{
int a = 10;
int b = 20;
printf("add(%d, %d)=%d\n", a, b, add(a, b));
printf("sub(%d,%d)=%d\n", a, b, sub(a, b));
return 0;
}
编译
$ gcc main.c -I../ -L../ -lmymath
-I:指定头文件路径
-L:指定库路径
-l:指定库名
$ ll
total 16
-rwxr-xr-x 1 mam mam 8600 Oct 2 11:55 a.out
-rw-r--r-- 1 mam mam 264 Oct 2 11:36 main.c
或者
$ export LIBRARY_PATH=/mam/mylib
$ gcc main.c -I../ -lmymath
$ ll
total 16
-rwxr-xr-x 1 mam mam 8600 Oct 2 12:01 a.out
-rw-r--r-- 1 mam mam 264 Oct 2 11:36 main.c
运行
$ ./a.out
三、动态库
1、编译链接
- 符号解析
链接器(ld)会扫描你的目标文件(.o 文件),找出其中所有未定义的符号(比如你调用了 add() 和 sub(),但二者的实现并不在你的代码里),然后在你通过 -l 选项指定的动态库(.so 文件)中查找这些符号是否存在,如果找不到,链接就会失败并报如下错误$ gcc main.c -I../ /tmp/cceii5lL.o: In function `main': main.c:(.text+0x21): undefined reference to `add' main.c:(.text+0x49): undefined reference to `sub' collect2: error: ld returned 1 exit status - 创建符号表和重定位表
链接器不会把 add() 和 sub() 所在目标文件(.o 文件)的整个机器码复制到你的可执行文件里,相反,它会在生成的可执行文件中创建两张很重要的表- 符号表:记录了程序需要哪些外部函数(add() 和 sub()),以及这些函数来自哪个动态库(libmymath.so)
- 重定位表:记录了代码中哪些地址是 “空的”,需要在运行时替换成动态库函数的真实地址
2、运行
动态链接器加载动态库并完成重定位后,交出控制权
3、注意
由于 Linux 的虚拟内存机制,使得物理内存中的一份动态库可以被所有需要用到该库的进程共享,因此动态库也被称为共享库
4、动态库的生成和使用
$ cat add.h
#ifndef __ADD_H__
#define __ADD_H__
int add(int a, int b);
#endif /* __ADD_H__ */
$ cat add.c
#include "add.h"
int add(int a, int b)
{
return a + b;
}
$ cat sub.h
#ifndef __SUB_H__
#define __SUB_H__
int sub(int a, int b);
#endif /* __SUB_H__ */
$ cat sub.c
#include "add.h"
int sub(int a, int b)
{
return a - b;
}
生成动态库
$ gcc -fPIC -c sub.c add.c
$ gcc -shared -o libmymath.so *.o
$ ll
total 36
-rw-r--r-- 1 mam mam 80 Oct 2 11:34 add.c
-rw-r--r-- 1 mam mam 97 Oct 2 11:32 add.h
-rw-r--r-- 1 mam mam 1240 Oct 2 12:14 add.o
-rw-r--r-- 1 mam mam 2688 Oct 2 11:37 libmymath.a
-rwxr-xr-x 1 mam mam 7920 Oct 2 12:14 libmymath.so
-rw-r--r-- 1 mam mam 80 Oct 2 11:34 sub.c
-rw-r--r-- 1 mam mam 95 Oct 2 11:33 sub.h
-rw-r--r-- 1 mam mam 1240 Oct 2 12:14 sub.o
drwxr-xr-x 2 mam mam 33 Oct 2 12:10 test_liba
drwxr-xr-x 2 mam mam 20 Oct 2 12:05 test_libso
$ pwd
/mam/mylib
$ cd test_libso
$ cat main.c
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main()
{
int a = 10;
int b = 20;
printf("add(%d, %d)=%d\n", a, b, add(a, b));
printf("sub(%d,%d)=%d\n", a, b, sub(a, b));
return 0;
}
编译
$ gcc main.o –I.. -L../ -lmymath
或者
$ export LIBRARY_PATH=/mam/mylib
$ gcc main.c -I../ -lmymath
$ ll
total 16
-rwxr-xr-x 1 mam mam 8552 Oct 2 12:18 a.out
-rw-r--r-- 1 mam mam 264 Oct 2 12:05 main.c
运行前需指定动态库路径
$ export LD_LIBRARY_PATH=/mam/mylib
$ ./a.out
277

被折叠的 条评论
为什么被折叠?



