一.库
链接静态库是将库中的被调用代码复制到调用模块中。
链接共享库则只是在调用模块中,嵌入被调用代码在库中的(相对)地址。
静态库占用空间非常大,不易修改但执行效率高。
共享库占用空间小,易于修改但执行效率略低。
二.函数的定义
add.h
#ifndef _ADD_H__
#define _ADD_H__
int add(int,int);
#endif //_ADD_H__
add.c
#include "add.h"
int add(int a,int b){
return a+b;
}
minus.h
#ifndef _MINUS_H__
#define _MINUS_H__
int minus(int,int);
#endif //_MINUS_H__
minus.c
#include "minus.h"
int minus(int a,int b){
return a-b;
}
div.h
#ifndef _DIV_H__
#define _DIV_H__
int div(int,int);
#endif //_DIV_H__
div.c
#include "div.h"
int div(int a,int b){
return a/b;
}
main.c
#include <stdio.h>
#include "add.h"
#include "minus.h"
#include "plus.h"
#include "div.h"
int main(){
int a = 20, b = 10;
printf("%d\n",add(a,b));
printf("%d\n",minus(a,b));
printf("%d\n",div(a,b));
return 0;
}
三.静态库
1.创建静态库
(1) 编辑源程序:.c/.h gcc -c xxx.c 检查语法错误
把所有的.c文件进行编译不链接处理 生成.o文件
(2) 编译成目标文件:ar -r liboper.a *.o
(3) 打包成静态库文件:ar -r lib+静态库名字
ar指令:ar [选项] 静态库文件名 目标文件列表
-r - 将目标文件插入到静态库中,已存在则更新
-q - 将目标文件追加到静态库尾
-d - 从静态库中删除目标文件
-t - 列表显示静态库中的目标文件
-x - 将静态库展开为目标文件
2.使用静态库 在.c文件中使用静态库中的函数 需要包含头文件
gcc -I 头文件的路径 main.c -l+静态库名 -L.静态库存储的路径
在相同目录时直接调用 gcc main.c liboper.a
-I 查找头文件的路径
-l 链接静态库/动态库
-L 查找静态库/动态库的路径
VirtualBox:~/unix/staticlib$ gcc -c add.c div.c minus.c
VirtualBox:~/unix/staticlib$ ar -r liboper.a *.o
ar: creating liboper.a
VirtualBox:~/unix/staticlib$ gcc main.c liboper.a
VirtualBox:~/unix/staticlib$ ./a.out
30
10
2
四.动态库
1.创建动态库
(1).c .h编译
(2)gcc -c -fpic xxx.c 编译所有的.c文件
(3)gcc -shared *.o -o liboper.so
gcc -shared -fpic *.c -o lib动态库名.so
2.使用动态库
(1)编写代码 包含头文件 使用动态库中的函数
(2)gcc -I 头文件路径 main.c -l动态库名 -L动态库路径
(3)链接动态库即使生成了可执行文件 该文件依然不能运行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./unix/staticlib
除了和静态库的使用方法一样以外 多了LD_LIBRARY_PATH
VirtualBox:~/unix/staticlib$ gcc -c -fpic *.c
VirtualBox:~/unix/staticlib$ gcc -shared *.o -o liboper1.so
//VirtualBox:~/unix/staticlib$ gcc -shared -fpic *.c -o liboper.so
VirtualBox:~/unix/staticlib$ gcc -I main.c liboper.so -L.
VirtualBox:~/unix/staticlib$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./unix/staticlib
加载动态库
#include <stdio.h>
#include <dlfcn.h>
typedef int (*FUNC)(int,int);
int main(){
void *handle = dlopen("liboper1.so",RTLD_NOW);
if(handle == NULL){
printf("%s\n",dlerror());//获取错误信息
return -1;
}
FUNC f1,f2,f3,f4;
f1 = dlsym(handle,"add");//根据标识符获取该标识符在动态库中的相对地址
if(f1 == NULL){
printf("%s\n",dlerror());
return -1;
}
int ret = f1(888,999);
printf("ret = %d\n",ret);
f2 = dlsym(handle,"minus");
ret = f2(888,999);
printf("ret = %d\n",ret);
f3 = dlsym(handle,"div");
ret = f3(888,999);
printf("ret = %d\n",ret);
dlclose(handle);
return 0;
}
VirtualBox:~/unix/staticlib$ gcc loadsharedlib -ldl
五.静态库和动态库的区别
1.生成静态库和动态库的步骤不一样
静态库 ar -r lib静态库名.a *.o
动态库 gcc -shared *.o -o lib动态库名.so
2.静态库文件没有 ‘x’权限 动态库有 -x 指定源代码的语言
3.链接静态库时 是把调用函数的指令用静态库中的二进制代码替换
链接动态库时 是直接在函数调用处嵌入函数在动态库中的相对地址
使用静态库生成的可执行程序比较大 把静态库的数据拷贝到可执行文件
使用动态库生成的可执行程序比较小
4.链接静态库 编译时 比较慢 执行效率高
链接动态库 编译时 比较快 执行效率低
5.链接静态库 生成的执行文件在运行过程中不依赖于静态库文件
链接动态库 生成的执行文件依赖于动态库
LD_LIBRARY_PATH 链接动态库生成的可执行程序在运行时查找动态库的路径
6.静态库本质上是对目标文件进行打包
动态库其实是对目标文件进行进一步的编译,是可以执行的二进制指令
如果xxx.a 和 xxx.so都有
gcc -I . main.c -loper -L . 链接的是动态库
gcc -I -static main.c -loper -L .
如果在开发过程中 有一个.c文件被修改 需要编译哪些动态库
1.c文件所在的动态库
2.连接了该动态库的所有动态库和可执行程序都需要重新编译 -ldd