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

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系统默认的库路径

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

相关文章:

  • Java并发容器和原子类
  • caliper中的测试文件写法及其注意事项
  • 谷歌云代理商 | 游戏行业专属方案:谷歌云实时多人游戏服务器架构
  • 在Windows下利用LoongArch-toolchain交叉编译Qt
  • C++编程——关于比较器的使用
  • 五子棋网络对战游戏的设计与实现设计与实现【源码+文档】
  • 常见工具导出DDL语句
  • 图片切割工具:智能分割长图并控制文件大小
  • 三维GIS开发cesium智慧地铁教程(4)城市白模加载与样式控制
  • 数据任务调度解决离不开离线开发BatchWorks
  • 单周期cpu和多周期cpu、单周期数据通路和多周期数据通路与总线结构数据通路和专用数据通路的关系
  • AOP实现Restful接口操作日志入表方案
  • CC7利用链深度解析
  • 基于3D对象体积与直径特征的筛选
  • 【Linux】find 命令详解及使用示例:递归查找文件和目录
  • EtherNet/IP转DeviceNet协议网关详解
  • C++.OpenGL (9/64)摄像机(Camera)
  • mysql的分页场景下,页数越大查询速度越慢的解决方法
  • 3D Web轻量化引擎HOOPS Communicator的定制化能力全面解析
  • java 局域网 rtsp 取流 WebSocket 推送到前端显示 低延迟
  • dw做网站一般需要多大尺寸/巨量关键词搜索查询
  • 如何对网站做镜像/360推广联盟
  • php网站留言板漏洞/专业关键词排名优化软件
  • 网站建设需求计划书/百度首页清爽版
  • 邢台手机网站建设费用/百度网盘app
  • 做网站使用什么软件的/最新地址