静态库
静态库的本质时将多个目标文件打包成一个文件,而链接静态库就是将库中被调用的代码复制到调用模块中,拓展名为.a
举例:
calc.h
//计算模块头文件
#ifndef _CALC_H_
#define _CALC_H_
int add(int a,int b);
int sub(int a,int b);
#endif //_CALC_H_
calc.c
#include "calc.h"
int add(int a,int b){
return a+b;
}
int sub(int a,int b){
return a-b;
}
编译.c文件:
gcc -c calc.c // 仅编译不链接,为了生成.o
制成静态库
ar -r libtest.a calc.o
按照上述命令就可以制作成libtest.a静态库。接下来如果要使用该库中的方法,可参考如下:
main.c
#include "show.h"
#include "calc.h"
int main(){
int a=145,b=897;
show(a,'+',b,add(a,b));
return 0;
}
然后在终端
gcc main.c libtest.a
如果库和main文件不在同一目录
gcc main.c -ltest -L/yourPath
优缺点
优点
执行速度块
可执行文件不依赖库存在
缺点
文件体积较大
更新困难,维护成本高
动态库
与静态库相比,链接动态库不需要将被调用的函数代码复制到包含调用代码的可执行文件中,相反链接器会在调用语句处嵌入一段指令,在该程序执行到这段指令时,会加载该动态库并寻找被调用函数的入口地址并执行
如果动态库中的代码同时被多个进程所用,动态库在内存中的实例仅需一份,为所有使用该库的进程共享,也叫共享库。
编译
gcc -c -fpic calc.c show.c(pic:位置无关量,每个函数在文件里面都有一个固定的偏移量,不管它映射到哪一个进程中虽然地址不一样,但是在映射后的地址上加上偏移量就能准确找到函数位置)
gcc -shared calc.o show.o -o libtest.so
链接动态库
gcc main.c -ltest -L/myPath
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:path
gcc main.c -ltest
动态加载
在程序执行的过程中,开发人员可以动态加载共享库(需要用的时候就加载)
动态加载库需要的函数:
dlopen() 函数详解
头文件:#include <dlfcn.h> 链接 -ldl
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
dlopen()
函数是 Linux 和 Unix-like 系统中用于动态加载共享库的核心接口。它接受两个参数:
-
const char *filename
:指定了待加载库文件的路径。可以是绝对路径或相对路径。若使用相对路径,其相对于当前工作目录或环境变量LD_LIBRARY_PATH
中列出的目录。 -
int flag
:加载模式标志,用于控制库的加载行为和符号可见性。常见的标志有:RTLD_LAZY
:延迟绑定(默认)。仅解析库中符号的引用,直到它们首次被调用时才解析和解决。RTLD_NOW
:立即绑定。在dlopen()
调用时立即解析并解决所有符号引用。RTLD_LOCAL
(默认):加载的库中的符号对其他已加载库不可见。RTLD_GLOBAL
:加载的库中的符号对其他已加载库可见,允许跨库间的符号引用。
成功加载库后,dlopen()
返回一个非空的句柄(handle),该句柄是后续使用 dlsym()
等函数访问库内资源的关键。如果加载失败,dlopen()
返回 NULL
。可通过 dlerror()
函数获取详细的错误信息。
char *dlerror(void);
dlopen() 的搭档:dlsym() 与 dlclose()
dlsym():查找并获取库中符号
dlsym():查找并获取库中符号
dlsym()
用于从已加载库中查找并获取指定符号(函数或全局变量)的地址。参数:
void *handle
:由dlopen()
返回的库句柄。const char *symbol
:要查找的符号名称(函数名或变量名)。
成功找到符号时,dlsym()
返回指向该符号的指针。若找不到或发生错误,返回 NULL
。同样,使用 dlerror()
获取错误信息
dlclose():卸载已加载库
int dlclose(void *handle);
dlclose()
用于释放由 dlopen()
加载的库资源,使其从进程中卸载。参数:
void *handle
:待卸载库的句柄。
返回值:
0
表示成功卸载。- 非零值表示卸载失败,可通过
dlerror()
获取原因。