一、静态库和动态库
Linux的库文件一般分为静态库和动态库:
静态库(.a): 库文件以.a为后缀,程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库 动态库(.so): 库文件以.so为后缀,程序运行的时候才会去链接动态库的代码,多个程序共享使用库的代码
二、理解库
如果不想给对方我们的源代码,我们可以选择给用户提供我们的.o可重定位目标二进制文件(gcc -c 文件)与.h头文件。让用户用我们提供的.o文件进行链接即可。在编译时,只要把源文件编译成.o文件在将其链接便可形成一个可执行的程序:

通过 gcc -o 链接目标文件,生成可执行程序:
我们可以把 .o
和 .h
文件提交给用户,可是如果有成百上千个,那一个个提供太过麻烦。因此为了让用户简单的使用库,我们就把所有 .o
文件打包成一个包,给对方提供一个库文件即可。把多个文件合并成一个文件,这个文件就是库,打包的方式就分为了静态库和动态库。
三、制作静态库
创建Makefile
c
libmymath.a: my_add.o my_sub.o
ar -rc $@ $^
my_add.o: my_add.c
gcc -c my_add.c -o my_add.o
my_sub.o: my_sub.c
gcc -c my_sub.c -o my_sub.o
.PHONY: output
output:
mkdir -p mylib/include
mkdir -p mylib/lib
cp -f *.a mylib/lib
cp -f *.h mylib/include
.PHONY: clean
clean:
rm -rf *.o libmymath.a
在Makefile中,$@
和$^
是自动变量,用于表示规则中的目标和依赖项。
$@
表示当前规则的目标(target),即规则左侧的文件名。$^
表示当前规则的所有依赖项(prerequisites),即规则右侧的文件名。
在Makefile中,libmymath.a: my_add.o my_sub.o
规则中的 $@
表示 libmymath.a
,即目标文件名。$^
表示 my_add.o my_sub.o
,即所有依赖项的列表。
当执行命令时,$@
和$^
会被替换为实际的目标和依赖项的文件名,以便进行相关操作。例如,ar -rc $@ $^
中的 $@
将被替换为 libmymath.a
,$^
将被替换为 my_add.o my_sub.o
。因此,该命令最终将执行 ar -rc libmymath.a my_add.o my_sub.o
,将 my_add.o
和 my_sub.o
打包成 libmymath.a
静态库。
output
是我们要生成的库
链接库:
c
gcc -o mytest my_test.c -I ./mylib/include -L ./mylib/lib -lmymath
-I:指明头文件的搜索路径
-L:指明库文件的搜索路径
-l:指明要链接哪个库,带上库的名称(去掉前缀和后缀)
四、制作动态库
首先我们需要把库文件全部编译成.o文件,这里与静态库不同,需要带上选项 -fPIC,形成与位置无关码:
c++
gcc -c -fPIC my_add.c
动态库打包:-shared
c++
gcc -shared -o libmymath.so my_add.o my_sub.o
目录结构:
c
➜ test tree
.
├── libmymath.so
├── Makefile
├── my_add.c
├── my_add.h
├── my_add.o
├── mylib
│ ├── include
│ │ ├── my_add.h
│ │ └── my_sub.h
│ └── lib
│ └── libmymath.so
├── my_sub.c
├── my_sub.h
├── my_sub.o
├── mytest
└── my_test.c
链接动态库:
c
gcc -o mytest my_test.c -I mylib/include -L mylib/lib -lmymath
报错了:
我们此时已经告诉了库文件,路径和库名称,选项已经给gcc带上了。但是我们当编译完之后,和gcc还有关系吗?答案是无关的,接下来运行是和OS有关的,动态库是运行时才加载的,所以程序运行起来,OS和shell也是需要知道库是在哪里的!而我们自己制作的库并没有在系统路径下,OS无法找到!如何找到动态库。
把库路径添加到环境变量LD_LIBRARY_PATH:
c
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/zmm/playground/test/mylib/lib