当前位置: 首页 > ai >正文

动/静态库的原理及制作

 一.基本概念

动态库:动态库就像一个仓库其中包含为可执行文件,如果有文件需要调用,就进行提取,使用动态库编译的文件因为保存的地址所以文件大小相对较小,依赖系统环境。

静态库:相当于2进制的.c文件,用来编译在文件内部,并且有相对较强的可移植性,若文件采用静态库进行编译,不依赖系统环境,但是文件体积相对较大。

二.动态库的制作

(1)将.c源文件编译为.o文件

制作动态库所需要的为有段落行的二进制文件编译时需要加特定的命令

gcc main.c -o main.o -c -fPIC

 -c :GCC 会将指定的源代码文件(如 .c 或 .cpp 文件)编译成目标文件(通常为 .o 或 .obj 文件),但不会尝试将它们链接成可执行文件。这意味着编译器不会处理外部引用,只关注于源代码内部的编译。

-fPIC:GCC 会生成位置无关代码,这意味着代码中的所有地址都是相对于某个基址

(2)动态库可以当作共享的.so文件

gcc main.o -shared -o libmain.so 

 -shared:用于生成共享库(Shared Library,也称为动态链接库,以便可以被多个程序共享使用。

其中有一些潜规则在进行连接"-l"的时候其中库的名称时掐头去尾    例如libmain.so其实时main

(3)运行

<1>最简单直接的方法:将生成的.so文件移送到系统的lib文件夹下   编译命令如下

gcc main.c -o main -L <系统lib的路径一般时/lib> -l <库的名称>

 <2>给链接库知名路径

gcc main.c -o main -L. -lmain -Wl,-rpath=/home/gec/lib

 -Wl :在参数后的逗号分隔的参数会被直接传递给底层链接器

-rpath:用来给编译器指明所连接库的位置

<3>修改环境变量(只有在当前终端生效)

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/gec/lib

<4>修改系统的环境变量

gec@ubuntu:~$ sudo vi /etc/ld.so.conf.d/libc.conf
gec@ubuntu:~$ sudo ldconfig

 三.静态库的制作

假设功能文件 a.c、b.c 包含了一些通用的程序模块,可以被其他程序复用,那么可以将它们制作成静态库,具体的步骤是:

(1)制作 *.o 原材料

gec@ubuntu:~$ gcc a.c -o a.o -c
gec@ubuntu:~$ gcc b.c -o b.o -c

(2)将 *.o 合并成一个静态库

gec@ubuntu:~$ ar crs libab.a a.o b.o

(3)静态库的常见操作

ar -<参数>  静态库名称

-t:意即table,以列表方式列出*.o文件

-d:d意即delte,删除掉指定的*.o文件

-r:r意即replace,添加或替换(重名时)指定的*.o文件

-x:x意即extract,将库中所有的*.o文件释放出来

(4)使用

gcc main.c -L /path/to/libmain.a -l main -o main

其中路径一定为绝对路径

 四.动态加载库

1.接口代码实现

// a.c
void detection()
{printf("正在检测颜色是否均匀...\n");
}// b.c
void detection()
{printf("正在检测外观是否破损...\n");
}

2.将不同的模块制作成动态库 

    gec@ubuntu:~$ gcc a.c -o a.o -c -fPIC
    gec@ubuntu:~$ gcc -shared -fPIC -o libcolor.so a.o
    gec@ubuntu:~$ 
    gec@ubuntu:~$ gcc b.c -o b.o -c -fPIC
    gec@ubuntu:~$ gcc -shared -fPIC -o libshape.so b.o
    gec@ubuntu:~$ 
    gec@ubuntu:~$ ls
    libcolor.so  libshape.so

    3.编写一个配置文件,指定程序需要加载的动态库:

    gec@ubuntu:~$ cat config
    libcolor.so

    示例代码 

    #include <stdio.h>
    #include <dlfcn.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdbool.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <errno.h>int main(int argc, char **argv)
    {// 读取配置文件FILE *fp = fopen("config", "r");char *lib = calloc(1, 30);fgets(lib, 30, fp);fclose(fp);// 根据配置文件打开指定的库void *handle = dlopen(strtok(lib, "\n"), RTLD_NOW);if(handle == NULL){printf("加载动态库[%s]失败:%s\n", lib, strerror(errno));exit(0);}// 在库中查找事先约定好的接口void (*detect)(void);detect = dlsym(handle, "detection");if(detect == NULL){printf("查找符号[%s]失败:%s\n", "detect", strerror(errno));exit(0);}// 潇洒地调用该接口detect();
    }

    五.函数解析 

    打开和关闭动态库,获取动态库的操作句柄:

    关键点:

    • RTLD_LAZY意味着打开动态库时,并不立即解析库中的函数符号的内存位置,而是等待程序实际调用时才临时去解析。
    • RTLD_NOW与上述含义相反,它意味着打开动态库时就立即解析库中的函数符号的内存位置。
    • 不管是LAZY还是NOW,库中的静态数据符号都将被立即解析。

    关键点:

    • 该函数用于在动态库中获取指定的函数入口地址。
    http://www.xdnf.cn/news/16370.html

    相关文章:

  1. 鸿蒙打包签名
  2. Linux:线程同步与线程互斥
  3. Vue 工程化
  4. 重构vite.config.json
  5. Linux Shell 命令
  6. 设计模式(九)结构型:组合模式详解
  7. 卷积神经网络研讨
  8. 设计模式(三)创建型:抽象工厂模式详解
  9. 3D芯片香港集成:技术突破与产业机遇全景分析
  10. Cursor下利用Stagewise实现 “所见即改” 的前端开发体验~
  11. Linux kill正在执行的后台任务 kill进程组
  12. Cline与Cursor深度实战指南:AI编程助手的革命性应用
  13. github上传本地项目过程记录
  14. 【Datawhale AI夏令营】科大讯飞AI大赛(大模型技术)/夏令营:让AI理解列车排期表
  15. 【计算机网络架构】网状型架构简介
  16. 栈----4.每日温度
  17. 226. 翻转二叉树
  18. C语言(长期更新)第6讲:函数
  19. (LeetCode 每日一题) 2210. 统计数组中峰和谷的数量 (数组)
  20. 【RAG技术权威指南】从原理到企业级应用实践
  21. Spring Boot音乐服务器项目-查询音乐模块
  22. 【自动化运维神器Ansible】Ansible常用模块之archive模块详解
  23. QT---概览
  24. Spring AI 学习笔记
  25. Datawhale 科大讯飞AI大赛(模型蒸馏)
  26. 电科金仓 KingbaseES 深度解码:技术突破・行业实践・沙龙邀约 -- 融合数据库的变革之力
  27. i节点学习
  28. 7月27日星期日今日早报简报微语报早读
  29. 从0开始学linux韦东山教程Linux驱动入门实验班(6)
  30. Flink2.0学习笔记:Stream API 常用转换算子