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

动静态库的制作和原理

目录

动静态库的原理

静态库 

动静态库的区别 

静态库

动态库 

静态库的生成与使用 

静态库的生成 

 静态库的使用

动态库的生成与使用

动态库的生成

动态库的使用


动静态库的原理

假如我有个朋友叫张三,他总是请我吃饭,有一次老师要我们交作业,张三平时并不听课,他说他让我把方法的定义.h文件和方法的使用.c文件发给他,然后他自己去用这些方法写一个usercode文件交上去,这样就可以蒙混过关了。后来我们一直这样干,但有一天,老师发现了,我被张三连累了,扣了平时分,但是他总是请我吃饭,不好意思不给他作业抄,所以我想了个办法。老师讲过:源文件和头文件变成可执行程序有四个过程

  1. 预处理: 完成头文件展开、去注释、宏替换、条件编译等,最终形成xxx.i文件。
  2. 编译: 完成词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,最终形成xxx.s文件。
  3. 汇编: 将汇编指令转换成二进制指令,最终形成xxx.o文件。
  4. 链接: 将生成的各个xxx.o文件进行链接,最终形成可执行程序..

我就把写好的.c文件经过汇编形成.o文件,和.h文件打包发给张三,然后他可以将,o文件链接起来,形成一个可执行程序,这样就能躲过老师的眼睛,既能还张三的人情,也能不被老师发现,两全其美,而我们刚刚用的打包.o文件的方法就是制作一个库。库里面不包含主函数,是要用到的方法的实现,所以库的本质其实就是一个“半可执行程序”。 

静态库 

我们在Linux下写一份很简单的代码,

#include <stdio.h>int main()
{printf("hello world!\n);return 0;
}  

我们运行这份代码 

 

但是今天我们并不讨论这份代码,而是要讨论我们为什么可以用printf函数,这是为什么呢?因为这个程序链接的时候把C标准库也链接了,在Linux中,我们可以通过 ldd  这个命令来查看这个可执行程序依赖的库。我们可以看到我们这个程序依赖的其实是 libm.so.6  ,我们再用ls来看看这个到底是什么。这是我们上一节所学的软链接。我们再通过 file 查看 libm-2.17.so 的文件类型,看到了shared就知道这是一个共享目标库文件,就是动态库

  •   在Linux中,以 .so 为后缀的是动态库,以 .a 为后缀的是静态库。
  •   在windows中,以 .dll 为后缀的是动态库, 以 .lib 为后缀的是静态库。

 我们上面所查看的 libm.so.6 就是C动态库,我们将lib去掉,将后缀和版本号去掉就是这个库的名字。而在g++或者gcc中,都是动态链接的,如果想要静态链接,只需后面加个-static就可以了。这个静态生成的文件比原来那个要大得多,而且静态生成的可执行程序并不依赖别的库文件,我们也可以查看一下。

动静态库的区别 

静态库

  • 程序在编译链接的时候把库的代码链接到可执⾏⽂件中,程序运⾏的时候将不再 需要静态库。 

 就像我们上面执行的一样,可执行程序依赖的如果是静态库的话,以后就不需要别的库了,这就是静态库的特征。但因为平时都是将静态库直接全部复制在可执行程序中,所以特别大,占用大量空间,这也是静态库的缺点。

动态库 

  • 程序在运⾏的时候才去链接动态库的代码,多个程序共享使⽤库的代码。

优点就是节省磁盘空间,且多个可执行程序所共享,但是缺点就是必须依赖动态库。

静态库的生成与使用 

静态库的生成 

我们使用最为简单的代码来创建一个静态库吧。用最简单的数的加减,定义了两个源文件和两个头文件。内容很简单就不过多阐述了。

第一步:编译源文件,让其生成对应的目标文件(.o文件)

 

第二步:使用ar将其打包为静态库 

 ar是gnu的归档工具,rc表示(replace 和 create)。

 ar -rc libcal.a add.o sub.o

既然我们打包了文件,那是不是也可以查看库里面的文件有啥,可以,用-tv选项。

ar -tv libcal.a

第三步:将生成的库和头文件组织起来 

当我们将自己的库给张三用的时候,其实要给他两个文件夹,第一个是.h为后缀的头文件,第二个就是刚刚生成的库,有点麻烦,我们将他组织起来。 这样我们也算是组织起来了。

使用Makefile

其实还挺麻烦的,使用Makefile的话能帮我们省掉很多事情,我们把需要写的命令,写到里面去,执行的时候就不用我们手敲了。我们使用make就能形成静态库,使用make output就能将头文件和库组织起来。

 静态库的使用

我们使用静态库呢,就需要一个main函数:

#include <stdio.h>
#include <add.h>int main()
{int x = 20;int y = 10;int z = my_add(x, y);printf("%d + %d = %d\n", x, y, z);return 0;
}

而gcc编译main.c的话,就要用到三个选项:

  • -I:指定头文件搜索路径。
  • -L:指定库文件搜索路径。
  • -l:指明需要链接库文件路径下的哪一个库。
gcc main.c -I./mathlib/include -L./mathlib/lib -lcal

 至此,我们就完成了静态库的生成与使用。

动态库的生成与使用

动态库的生成

基本步骤其实和静态库差不多,但有些些差别,我们还是像静态库一样。

第一步:将它编译成目标文件,但是这里和静态库的区别就体现出来了,此时用源文件生成目标文件时需要携带-fPIC选项:

  • -fPIC(position independent code):产生位置无关码。

 

第二步:使用-shared选项将所有目标文件打包为动态库 

 

第三步:将头文件和生成的动态库组织起来 

 

使用Makefile 

就像静态库那样写一个Makefile,就能一步到位了。 我们就能轻松得到库,然后将库和头文件组织起来

动态库的使用

我们还是用之前用的mian.c来演示一下。

#include <stdio.h>
#include <add.h>int main()
{int x = 20;int y = 10;int z = my_add(x, y);printf("%d + %d = %d\n", x, y, z);return 0;
}

继续使用-I.-L.-l的命令,来生成可执行文件, 但是,与静态库不同的是,这里生成的可执行文件并不能执行。

我们先看看可执行程序所依赖的库,

所依赖的动态库并没有被找到,我们怎么解决呢?

.这里有一种解决办法:拷贝.so文件到系统共享库路径下

 既然系统找不到我们的库文件,那么我们直接将库文件拷贝到系统共享的库路径下,这样一来系统就能够找到对应的库文件了。

sudo cp mlib/lib/libcal.so /lib64

至此,我们动态库的生成与使用也就完成了! 

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

相关文章:

  • 【unitrix】 6.10 类型转换(from.rs)
  • [BUG]关于UE5.6编译时出现“Microsoft.MakeFile.Targets(44,5): Error MSB3073”问题的解决
  • 【软件测试】从软件测试到Bug评审:生命周期与管理技巧
  • VUE2 学习笔记2 数据绑定、数据代理、MVVM
  • 【数据结构】第一讲 —— 概论
  • 基于Arduino的智能寻迹小车设计
  • 剑指offer——链表:旋转数组的最小数字
  • 【OD机试】池化资源共享
  • 「Java案例」利用方法求反素数
  • Ubuntu挂载和取消挂载
  • LP-MSPM0G3507学习--07定时器之二定时节拍
  • ZYNQ平台深度剖析:EMMC/FLASH/SD卡性能测试与创新实践
  • 从磁记录到数据中心:磁盘原理与服务器架构的完整技术链路
  • 两个数据表的故事:第 1 部分
  • Spring之事务使用指南
  • Java行为型模式---解释器模式
  • Openlayers 面试题及答案180道(121-140)
  • Node.js Express keep-alive 超时时间设置
  • @import导入css样式、scss变量用法、static目录
  • Java中List<int[]>()和List<int[]>[]的区别
  • PAT 1049 Counting Ones
  • 医学图像超分辨率重建深度学习模型开发报告
  • 如何用immich将苹果手机中的照片备份到指定文件夹
  • Word for mac使用宏
  • UniApp 常用UI库
  • 机器视觉---深度图像存储格式
  • 闲庭信步使用图像验证平台加速FPGA的开发:第二十五课——正弦波图像的FPGA实现
  • 数据存储方案h5py
  • 【C++基础】面试高频考点解析:extern “C“ 的链接陷阱与真题实战
  • MySQL详解三