- 库是预编译的目标文件(
.o
)的集合,它们可以被链接进程序。
printf
等C标准库在/usr/lib/libc.a
,它包含ANS1/ISO
标准指定的函数。对每一个C程序,libc.a
默认被链接。
- 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。编译之后程序文件大,但加载快,隔离性也好。
- 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。多个应用程序可以使用同一个动态库,启动多个应用程序的时候,只需要将动态库加载到内存一次即可。
一、静态库 archive file
生成步骤:
1、由源文件编译生成一堆.o
,每个.o
里都包含这个编译单元的符号表。
2、ar
命令将很多.o
转换成.a
,成为静态库
gcc -c hello.c //生成hello.o
ar -cvr libhello.a hello.o //生成libhello.a
使用:
gcc -o app main.c -L. -lhello //生成可执行文件
-r
将objfile文件插入静态库尾或者替换静态库中同名文件
-x
从静态库文件中抽取文件objfile
-t
打印静态库的成员文件列表
-d
从静态库中删除文件objfile
-s
重置静态库文件索引
-v
创建文件冗余信息
-c
创建静态库文件
二、动态库
gcc -o libhello.so -shared -fPIC hello.c //生成libhello.so
sudo cp libhello.so /usr/lib/ //要把.so文件拷贝到系统动态库路径里
gcc -o app main.c -L. -lhello //生成可执行文件
-shared
该选项指定生成动态连接库(让连接器生成T
类型的导出符号表,有时候也生成弱连接W
类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件。
-fPIC
作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code
)。那么在产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
-L.
表示要连接的库在当前目录中。
三、说明
编译命令一致时,动态库和静态库同时存在时,优先使用动态库。
除非gcc -o hello main.c libhello.a
四、例子
文件:main.c
、include.h
、add.c
、hello.c
//include.h 声明作用,使用时只需包含该文件,
//具体实现在哪个文件不关心,链接时把实现的库链接上即可
#ifndef __INCLUDE__
#define __INCLUDE__
int add(int a, int b);
void hello(const char *str);
#endif
//add.c
#include <stdio.h>
int add(int a, int b){
return a + b;
}
//hello.c
#include <stdio.h>
void hello(const char *str){
printf("Hello %s!\n",str);
}
//main.c 只需把声明文件包含进去
#include <stdio.h>
#include "include.h"
int main(){
hello("World");
printf("2 + 3 = %d\n", add(2, 3));
return 0;
}
1.静态库使用:
gcc -c add.c hello.c //生成add.o hello.o
ar -cvr liball.a *o //把所有.o文件打包成一个静态库liball.a,也可以一个.o生成一个.a
gcc -o app main.c -L. -lall //生成可执行文件app
相当于:
gcc -c *.c
gcc -o app *.o
2.动态库使用:
gcc -o liball.so -shared -fPIC add.c hello.c //生成动态库liball.so
gcc -o app main.c -L. -lall //生成可执行二进制文件
若要执行的话需要通过修改环境变量,指定动态库的搜索路径,或者把liball.so拷贝到/usr/lib/