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

1.4 编译库:静态库、动态库

一、静态库

1.1 编译静态库

静态库:是将多个.o文件打包成一个归档文件(.a)

源码下载地址:universe.zip

(1)编译源码

gcc -c -o zeus.o zeus.c
gcc -c -o sun.o sun.c
gcc -c -o moon.o moon.c
gcc -c -o earth.o earth.c

(2)将.o文件打成包静态库

ar -rcs libstar.a moon.o sun.o earth.o# ar是Linux归档工具
# -r 如果库中有同名的.o文件,则替换
# -c 如果静态库不存在,则创建。
# -s 为静态库生成或更新索引

(3)使用静态库

poseidon.c 内容如下:

#include "sun.h"
#include "moon.h"
#include "earth.h"
#include <stdio.h>
int main()
{printf("poseidon do something \r\n");sun_rotate();moon_rotate();earth_rotate();return 0;
}
# 1.编译
gcc -c poseidon.c# 2.链接静态库
gcc -o poseidon poseidon.o -static -L./ -lstar # 通过-L指定库路径gcc -o poseidon poseidon.o libstar.a # 通过库完整名称来指定

1.2 封装静态库

封装静态库:在静态库基础上,增加一些功能代码,再重新打包静态库。

封装静态库流程

  • 将新增的.c文件编译成.o文件
  • 将静态库解压:ar -x
  • 将所有的.o文件重新打包成静态库

项目代码:handes.zip

(1)编译新增代码

gcc -c -o dog.o dog.c
gcc -c -o pig.o pig.c

(2)解压原静态库

# libstar.a会解压出:earth.o、moon.o、sun.o
ar -x libstar.a

(3)重新打包

ar -rcs libpower.a earth.o moon.o sun.o dig.o pig.o

注意

  • 不能直接把libstar.a和新.o文件一起打包,否则会有问题。
  • 静态库不是纯ELF文件,而是多个ELF文件的合并,所以必须先解压再打包

二、动态库

2.1 编译动态库

动态库:多个程序共用,共享节省磁盘空间。

源码下载地址:universe.zip

(1)编译源码

gcc -c -o sun.o sun.c
gcc -c -o moon.o moon.c
gcc -c -o earth.o earth.c 

(2)编译动态库

# 编译动态库 -fPIC 生成位置无关的代码,-shared生成动态库
gcc -fPIC -shared -o libstar.so sun.o moon.o earth.o

(3)使用动态库

# 链接动态库
gcc -c zeus.c
gcc -o zeus zeus.o libstar.so  # 运行报错,找不到libstar.so,因为Linux默认不从当前目录加载动态库。
./zeus# 可以设置环境变量 再运行
export LB_LIBRARY_PATH=./:$LB_LIBRARY_PATH
./zeus

2.2 显式使用动态库

问题:当静态库和动态库存在同名符号时,会导致符号冲突。
如:

  • 静态库A(依赖C标准库libc.a)和 动态库B(依赖C标准库libc.so)
  • 现在程序program需要同时链接A和B库。
  • A和B存在相同的符号(函数)就会导致符号冲突

解决方法正常链接静态库,动态库在代码中显式调用。

zeus.c 的代码:

  #include <stdio.h>#include<dlfcn.h>int main(int argc, char **argv){// 动态库的句柄void *handle;// 动态库中函数的地址int (*sun_rotate)();// 打开动态库handle = dlopen("/home/oem/Desktop/dev/cpp/universe/libstar.so", RTLD_LAZY);if (!handle) {fprintf(stderr, "%s\n", dlerror());return 1;}// 获取函数的地址sun_rotate = dlsym(handle, "sun_rotate");if (!sun_rotate) {fprintf(stderr, "%s\n", dlerror());return 1;}// 调用函数printf("zeus2 do something\n");(*sun_rotate)();// 关闭动态库dlclose(handle);return 0;}

编译和链接

# 会提示一个警告,但不影响运行
gcc -c zeus.c
gcc -c zeus zeus.o -ld -static

2.3 封装静态库为动态库

封装静态库成动态库:在已有的静态库基础上,增加一些功能代码,并封装成新动态库。

封装动态库流程

  • 将新增的.c文件编译成.o文件
  • 将静态库解压:ar -x
  • 将所有.o文件重新链接成动态库。

项目代码:handes.zip

(1)编译新增代码

gcc -c -o dog.o dog.c
gcc -c -o pig.o pig.c

(2)解压原静态库

# libstar.a会解压出:earth.o、moon.o、sun.o
ar -x libstar.a

(3)重新打包

gcc -fPIC -shared -o libpower.so dog.o pig.o moon.o earth.o sun.o

2.4 混合使用静态库与动态库

编译器支持同时链接静态库和动态库:

  • -Wl,-Bstatic 指定后续库静态链接。
  • -Wl,-Bdynamic 指定后续库动态链接。

示例项目

  • 项目用到动态库libstar.so和静态库libcook.a
  • 动态库存储在:/usr/local/star/lib
  • 静态库存储在:/usr/lib
gcc -c theseus.c
gcc -o theseus theseus.o -Wl,-Bstatic -lcook -Wl,-Bdynamic -L/usr/local/star/lib -lstar
#  静态库不使用-L指定库路径的原因,是/usr/lib系统默认的库路径

注意:避免同一库同时静态和动态链接,防止冲突。

http://www.xdnf.cn/news/12610.html

相关文章:

  • Java并发包中的管程:Lock和Condition
  • 基于STM32语音识别柔光台灯
  • 基于深度学习的无人机轨迹预测
  • 《ERP原理与应用教程》第3版习题和答案
  • VSCode - VSCode 放大与缩小代码
  • 嵌入式开发之STM32学习笔记day22
  • 深入解析:为什么 Redis 比 MySQL 快
  • 如何轻松、安全地管理密码(新手指南)
  • 创客匠人:如何通过精准定位实现创始人IP打造与知识变现
  • [C语言实战]C语言操作MySQL数据库(八)
  • Ubuntu18.6 学习QT问题记录以及虚拟机安装Ubuntu后的设置
  • 下载和安装Visual Studio(开发ASP.NET MVC应用)
  • 华为仓颉语言初识:并发编程之同步机制(上)
  • TensorFlow安装全攻略:快速搭建AI开发环境
  • 图像识别预处理(配合pytesseract使用)
  • 基于最大相邻夹角的边缘点提取(matlab)
  • 华为大规模——重塑生产力
  • 软信天成:数据驱动型背后的人工智能,基于机器学习的数据管理
  • FPGA定点和浮点数学运算-实例对比
  • opencv2/opencv.hpp里面有哪些常用的函数
  • 从混乱到秩序:探索管理系统如何彻底改变工作流程
  • Spring 团队详解:AOT 缓存实践、JSpecify 空指针安全与支持策略升级
  • Python 构建法律DeepSeek RAG
  • 35.成功解决编写关于“江协科技”编写技巧第二期标志位积累的问题
  • PostgreSQL 的扩展pg_freespacemap
  • Webhook 配置备忘
  • Imprompter: Tricking LLM Agents into Improper Tool Use
  • VUE解决页面请求接口大规模并发的问题(请求队列)
  • 通过跳板机连接远程主机
  • 【佳易王个体诊所电子处方软件】助力智慧诊疗! #医疗数字化 #电子处方效率提升