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

动/静态库的原理及制作

 一.基本概念

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

静态库:相当于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.lryc.cn/news/602048.html

    相关文章:

  1. 开源B端生态掘金:从Odoo二次开发到行业专属模块的技术变现
  2. Qwen 系列模型实现文本改写工具
  3. Java 大视界 -- 基于 Java 的大数据实时流处理在智能电网分布式能源接入与电网稳定性保障中的应用(368)
  4. Java从入门到精通!第十八天(JDK17安装以及网络编程) 完结篇!!!
  5. WPF,窗口拖动事件与窗口内控件点击事件
  6. Visual Studio Code使用
  7. MCP资源管理深度实践:动态数据源集成方案
  8. Jenkins vs GitLab CI/CD vs GitHub Actions在容器化部署流水线中的对比分析与实践指南
  9. Spring Boot 2整合Druid的两种方式
  10. Spring Boot日志开发实战手册:集成/输出/级别控制/持久化精要
  11. docker排查OOM
  12. c++ 中的字符串相关的操作
  13. 「源力觉醒 创作者计划」_文心大模型4.5系列开源模型,意味着什么?对开发者、对行业生态有何影响?
  14. 重复文件清理工具,附免费链接
  15. 聊聊工业相机中的硬触发、软触发和视频流模式
  16. MFC UI对话框
  17. puppeteer 系列模块的系统性、详细讲解
  18. 使用JavaScript实现一个代办事项的小案例
  19. 八大神经网络的区别
  20. 【RH134 问答题】第 6 章 管理 SELinux 安全性
  21. 计算机网络(基础篇)
  22. 《零基础入门AI: 从轮廓查找到形态学变换(OpenCV图像预处理)》
  23. 【深度学习新浪潮】基于文字生成3D城市景观的算法有哪些?
  24. Leaflet 综合案例-聚类图层控制
  25. Python快速入门(2025版):输入
  26. 婚纱摄影管理系统(发送邮箱、腾讯地图API、物流API、webSocket实时聊天、协同过滤算法、Echarts图形化分析)
  27. C++ list 容器全解析:从构造到模拟实现的深度探索----《Hello C++ Wrold!》(16)--(C/C++)
  28. 数值计算 | 图解基于龙格库塔法的微分方程计算与连续系统离散化(附Python实现)
  29. C primer plus (第六版)第九章 编程练习第6题
  30. 【Rust异步】async和await异步编程实战:高并发任务处理全解析