目录
概念
动态库与静态库
如何制作动静态库
静态库
动态库
总结
一般库分为两种:动态库和静态库,他们都是文件。
静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文 件的整个机器码。
在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个 过程称为动态链接。
动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间 。
ps:windows下静态库以.lib为后缀,动态库以.dll为后缀。
ldd :显示可执行程序依赖的库
查看C动态库:
库文件的命名:libxxxx.so 或 lib.xxxx.a
库的真实名字:去掉lib前缀,去掉后缀,剩下的就是库的名称
下面分别使用动态链接和静态链接,看看他们到底有什么不同点,他们的使用区别在于编译上,所以makfile的编写上有所不同
动态链接:
test:test.c gcc -o $@ $^
.PHONY:clean clean: rm -f test
静态链接:
test_static:test.c gcc -o $@ $^ -static
.PHONY:clean clean: rm -f test
如果系统上没有装静态库可以使用以下命令在root下安装:
yum install glibc-static
yum install glibc-static libstdc++-static
然后make编译生成后,来比较一下他们的可执行文件的区别:可以看到静态链接的可执行程序比动态链接的可执行程序大非常多
通过 file 可执行程序 命令可查看文件属性
静态链接:在编译时将需要的静态库拷贝到可执行程序中,形成之后不再依赖库。
动态链接:将要关联的函数关联起来(即将库文件地址映射到地址空间中),需要执行相关函数时,直接跳转到该函数。
库本身就是二进制的文件,如何知道库提供了什么方法?
一套完整的库包括:库文件本身、头文件(告诉使用者有哪些方法,怎样使用)、说明文档
制作过程:
所以的源代码,都需要先被编译称为.o文件(可重定向目标文件)
先把自己的所有源文件编译成为.o
制作动静态库的本质:就是将所有的.o文件打包,使用ar或者gcc进行打包
交付:include + .a or .so文件
首先声明和定义出需要使用的函数:
add.h
#pragma once #include
int add(int x, int y); add.c
#include"add.h" int add(int x, int y) { return x + y; }
sub.h
#pragma once #include
int sub(int x, int y); sub.c
#include"sub.h" int sub(int x, int y) { return x - y; }
有了定义和声明,知道他所在的路径也是可以直接使用的:
#include"./test_lib/add.h"
#include"./test_lib/sub.h"
int main()
{
int a = 10;
int b = 20;
int x1 = add(a, b);
int x2 = sub(a, b);
printf("%d\n", x1);
printf("%d\n", x2);
return 0;
}
但是编译时,需要指明名定义所在的路径,否则编译器会找不到函数的地址:
gcc myproc.c test_lib/add.c test_lib/sub.c
将自己写的函数给别人用,可以直接将头文件和源文件给别人,但这样会暴露自己的源代码。
所以可以制作静态库,将编译好的.o文件打包提供给使用方。打包好的.o文件就是库文件。
Makefile编写:
libmymath.a:add.o sub.o #将这两个.o文件打包形成libmymath.a文件 # lib 是前缀,.a是后缀 ar -rc $@ $^ %.o:%.c #通过编译形成.o文件 gcc -c $<
.PHONY:clean clean: rm -rf *.o libmymath.a output
.PHONY:output
output: #发布(将头文件和打包好的libmymath.a文件放在ouput目录下)
mkdir output
cp -rf *.h output cp libmymath.a output
静态库的使用:
gcc myproc.c -I./output -L./output -lmymath
#:-I 指明头文件搜素路径
#:-L 指明库文件搜索路径
#:-l 指明要链接哪一个库(需要去掉前缀和后缀)
我们之前写的代码也调用了库,但没有使用这些选项是因为之前的库在系统的默认路径下,编译器通过环境变量能够识别路径。
以后给别人使用时,直接给output给别人即可。
动态库的制作比静态库更简单:
Makefile编写:
#打包形成一个动态连接的共享库
libmymath.so:add.o sub.o
gcc -shared -o $@ $^
#产生.o目标文件,程序内部的地址方案是:
与位置无关,即库文件可以在内存的任何位置加载,而且不影响和其他程序的关联性
%.o:%.c gcc -fPIC -c $<
.PHONY:clean
clean:
rm -f libmymath.so *.o
.PHONY:lib
lib:
mkdir lib cp *.h lib cp libmymath.so lib
动态库的使用:
gcc myproc.c -I./lib -L./lib -lmymath,直接使用这种方法是不行的,这里只是告诉编译器头文件库路径在哪里,当程序编译好了,运行时还是会找不到库路径。
这里可以右两种方法解决:
将动态库拷贝到系统的库目录下(不推荐)
使用环境变量LD_LIBARAY_PATH (它是用来指明程序启动后,库的搜索路径的),将当前动态库所在路径导入环境变量中(export)
export LD_LIBRARY_PATH=$LD_LIBARAY_PATH:/home/wt/write_myblog/IO/lib
然后再来运行即可:
通过文件属性,就可以看到这里已经成功链接到了动态库。
如果只提供静态库,只能静态链接到程序。
如果只提供动态库,只能动态链接到程序。
若两种库都有,gcc、g++会优先链接动态库!
动静态库区别
静态库使用 ar -rc 命令生成,动态库使用 gcc 命令生成
静态库只能自己使用,动态库可以多个程序共享
使用静态库的程序运行速度较快,而使用动态库的程序相对较慢
使用静态库的程序占用磁盘和内存很大,而动态库较小
若静态库发生变化需将应用程序重新编译,而动态库变化只要头文件不变应用程序不需重新编译