静态库与动态库
- 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库,使用静态库编译后的程序其实是比使用动态库编译的程序体积要大得多,优点是不依赖第三方库
- 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享 使用库的代码,比如当我们执行一个printf函数,当程序运行时会去c语言的动态库中找到这个对应的printf函数(其实依赖的动态链接),并在动态库中完成处理,最后将返回值结果返回了, 动态库的有点就是代码体积比较小,并不会将库中的代码拷贝进来,
//其实libc . so . 6是c语言的库中的一个软链接,他链接的是libc-2.17.so这个动态库
[mzt@VM-16-4-centos test]$ ls /lib64/libc.so.6 -al
lrwxrwxrwx 1 root root 12 Nov 23 17:52 /lib64/libc.so.6 -> libc-2.17.so
- 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
- 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
- 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间
打包静态库
过程:
1、将源文件编译成 .o 文件
2、使用打包工具将. o 文件打包成 以.a为后缀的静态库文件
3、新建lib目录,将头文件和目标文件拷贝到include和mylib目录中,
编写makefile
mytest_static: test.c
gcc -o mytest_static test.c -I./lib/include -L./lib/mylib -l mymath
//-I: 后面接的是头文件的搜索路径
//-L:后面接的是库文件的搜索路径
//-l:必须接库文件的名字
.PHONY:clean
clean:
rm -rf mytest_static
也可以使用绝对路径
path=$(shell pwd)
mytest_static: test.c
gcc -o mytest_static test.c -I $(path)/lib/include -L $(path)/lib/mylib -l mymath
.PHONY:clean
clean:
rm -rf mytest_static
库搜索路径
最后将打包后的静态库lib(库文件 + 头文件)和test.c放在同一目录下,使用make编译
程序运行成功
打包动态库
1、在当前目录下(libso)创建源文件 add.c 、sub.c 和他们对应的头文件 add.h、 sub.h
2、在当前目录下(libso)编写makefile
输入make编译后我们的目录中会多出以下的几个文件
编写makefile
创建测试文件test.c 和编写对应的makefile。
运行动态库
当执行程序的时候会报以下的错误信息。
./mytest: error while loading shared libraries: libmymath.so:
cannot open shared object file: No such file or directory
注意:
使用动态库,必须设置全局的静态变量,告诉操作系统动态库的运行时位置在哪,如果只在编译器上面写入库的位置,那么OS是不确定运行时动态链接库的位置的
解决办法:更改 LD_LIBRARY_PATH,让操作系统把动态库加载到内存中来,建立页表,再让共享区和物理形成映射关系,最终我们的程序就可以去共享区中找到对应的动态库文件,
注意:环境变量只需要设置成绝对路径就行!!
程序运行结果: