建行网站会员是什么,福州网站模板建站,软件定制开发网站建设,小程序备用金文章目录 动静态库基础认知动静态库基本概念静态库的制作库的概念包的概念 静态库的使用第三方库小结 动态库的制作动态库的使用动态库如何找到内容#xff1f;小结 本篇要谈论的内容是关于动静态库的问题#xff0c;具体的逻辑框架是建立在库的制作#xff0c;库的使用小结 本篇要谈论的内容是关于动静态库的问题具体的逻辑框架是建立在库的制作库的使用和库的原理来展开基于上述的三个模块来对动静态库有一个较为清楚的认知
动静态库基础认知
在前面的学习中知道在用户写完代码后想要将写完的代码转换成可以执行的可执行程序过程是一个相当复杂的过程那么在这段过程中要处理的过程基本有例如预处理编译汇编链接可执行程序而在学习编译工具gcc的时候又提到过在代码进行链接的过程中系统必须要提供对应的动静态库因此就引入了动静态库的概念
所谓动态链接就是让程序和库产生这种地址性的关联而静态库就是把目标的库文件直接拷贝到对应的可执行程序当中
动静态库基本概念
对于静态库第一步要先引入的是静态库的原理静态库就是在进行编译链接的过程中把静态库中所包含的代码都拷贝到可执行程序中之后在可执行程序的运转就不需要静态库了
对于动态库原理是在程序运行的时候才会链接动态库的代码多个程序会共享使用库的代码而一个与动态库链接的可执行文件只有一个函数入口地址的表而不是整个文件的内容上述是关于动态库的基本原理关于这些内容后面就进行一个一个的解析
静态库的制作
首先创建出对应的文件这里假设要实现一个计算器那么实现对应的函数声明和实现过程 再创建一个对应的测试函数
#include Add.h
#include Sub.h
#include Mul.h
#include Div.hint main()
{int a 10;int b 20;printf(%d %d %d\n, a, b, Add(a, b));printf(%d - %d %d\n, a, b, Sub(a, b));printf(%d * %d %d\n, a, b, Mul(a, b));return 0;
}那么现在准备工作就完成了下面的问题是我想要编译生成一个可执行程序应该输入什么指令呢
gcc -o test.exe test.c Add.c Sub.c Mul.c Div.c这样就完成了编译生成了一个可以被运行的可执行文件那么下面对于上面的现象提出一些问题
1. 为什么在编译的时候不带头文件
因为头文件所属的位置就在当前路径下编译器是直接可以找到的如果头文件对应的查找路径是在当前目录或者是指定的目录是不需要写在编译选项中的
2. 上面的步骤是否每一步都需要
这个问题问法很奇怪怎么说是每一步都需要假设现在要生成的是一个可执行程序其实根本不太需要把源文件全部编译生成一个可执行文件因为这样的过程需要经过预处理编译汇编链接等等而实际上在编译这样的多文件项目的过程中只需要把源文件都编译为.o后缀的文件再将这些文件进行链接形成一个可执行文件这是被倡议的一种链接方式
库的概念
这也就是在任何项目中都会存在这样的文件的原因在进行编译生成可执行文件的过程中如果是直接将已经生成的这些.o后缀的文件进行一定的链接组合就能生成可执行程序
基于上面的原因我们重新进行一次编译这次按照上述的过程生成对应的.o文件即可为了方便后续进行其他的使用写一个Makefile来自动进行编译比较好
%.o:%.cgcc -c $Test:Add.o Sub.o Mul.o Div.o test.ogcc -o $ $^.PHONY:clean
clean:rm -rf *.o Test那么上面就是实现了Makefile但是和前面写的不太一样这个Makefile是直接将这些.o后缀的文件生成了一个可执行程序所以现在就要先生成这样的.o后缀的文件借助gcc编译工具就可以生成之后就可以运行出结果了
这里补充一点上面写的这个语句%.c的意义就是类似于一种通配符因为后续生成test可执行文件是依赖于.o文件的但是它们都不存在那么此时就需要根据依赖关系来进行推导而在推导的过程中当Makefile在进行被编译的时候就会把%.c全部展开之后就会进行不断的推导展开成四个gcc的编译方式语句而这里的$表示的是把文件依赖列表中的内容一个一个的传递到下面的命令中最后连起来就能解析成对应的内容了
那么现在的问题是如果源文件已经不需要了而是只需要这些.o为后缀的文件也就是说把这些文件进行打包作为一个库而把这个包交给使用者后使用者就只需要写出自己的.c文件再编译成.o文件就能和我刚才打包好的包直接进行链接就省去了前面的很多步骤像这样的过程就是前面所述的核心观点基于这样的原因现在当前的主要任务就是生成一个库
那么就对Makefile进行改造改造的核心思路就是基于上述的这一系列原理将文件编译成.o文件再将文件整合到一个固定的地方这就是库的概念
包的概念
上面的思路原理存在下面的一个问题是直接把.o文件存到一个固定的位置显然是不太合适的方式如果此时有几百个文件呢如果也是一个一个的进行转移那么可能会有所遗漏这都是不被建议和允许的基于这样的原因有了打包的概念
ar指令
ar -rc $ $^上述就是在Linux中打包的指令ar命令就是把所有的源文件进行打包形成对应库文件的过程其中这个rc表示的是replace和create的意思表示的是如果不存在就创建存在就替换总之这样就可以形成一个完整的.a文件
下面要做的就是生成一个库文件库文件的生成也能放到Makefile中来写具体的书写过程如下
# 库的名字是mymath是个静态库
static-liblibmymath.a# 生成库需要Add.o Sub.o Mul.o Div.o实现方式是ar指令
$(static-lib):Add.o Sub.o Mul.o Div.oar -rc $ $^# 生成.o文件需要把.c文件按照下面的gcc编译选项一个一个生成($)
%.o:%.cgcc -c $# 建库
.PHONY:output
output:mkdir -p mymath_lib/includemkdir -p mymath_lib/libcp -f *.h mymath_lib/includecp -f *.a mymath_lib/lib# 清空内容
.PHONY:clean
clean:rm -rf *.o *.a mymath_lib上述的完整Makefile进行推导解析第一行表示这是一个静态库静态库的名字叫做mymath前面的lib和后面的.a都是前缀和后缀静态库真正的名字叫做mymath而后面对于这个静态库的生成方式有了一个定义静态库的生成依赖的是后面的四个.o文件而具体的生成方式是ar指令那么此时Makefile就会进行推导Makefile现在需要.o文件但是现在没有所以在后面就提到了生成.o文件的过程是利用.c文件来生成的这样就完成了Makefile的过程后面的两个操作就是建库和清除的过程
执行结果如下 这样就完成了一个静态库那么接下来要进入的问题是库的使用问题
静态库的使用
进入这个话题就意味着现在我们已经有了静态库但是这个库怎么用呢
朴素做法
现在已经有了库别人给我提供了这些方法我该如何使用所以就用到了这些头文件提供的函数但是现在如果直接编译会发现根本编译不过去说明就现在而言还是不可行的 原因在于什么呢从报错信息来看找不到这里对应的头文件原因在于这些库文件都是被保护起来的现在在本地编写之后的代码是无法找到对应的内容说明现在还得想办法把这些库文件都让编译工具能够找见才可以那么就把头文件都放到代码所在的目录中再进行编译 此时报错信息是没有定义说明现在已经找到对应的头文件了但是没有找到定义头文件的地方这个就叫做链接报错那我写的这个库为什么用不了呢
第三方库
对于我们自己写的库函数都叫做第三方库而gcc不认识第三方库哪怕是就在当前路径下也依旧不认识这个第三方库因此就引出了要链接库的概念所以就要引出一个选项大I
-I 选项表示的意义是link也就是链接指定的一个库也就是说告诉编译器你在进行编译的时候要使用这个库所以执行下面的指令
gcc test.c -I mymath_lib/include/ -l mymath -L mymath_lib/lib上面这一串是很长的指令但是不急一点一点的分析
首先是要进行编译的对象是test.c后面的这个选项表示的是新增头文件的搜索路径后面紧跟着的就是头文件的搜索路径而后面的小l表示的是指明链接的库名称而大L表示的是新增库文件的搜索路径基于上面这么一长串的选项就能最终编译出来我们想要的结果事实上也确实生成了这说明我们的静态库已经使用成功了
之前我们使用的C标准库从来不需要指定而此时为什么这里就需要指定了呢因为这里我们自己实现的叫做第三方库而gcc是专门用来处理C语言的编译工具所以在进行编译的时候会直接到指定的路径下去寻找gcc已经认识了C语言提供的官方库而我们自己实现的第三方库它并不认识即使看见了也不认识需要我们主动的为gcc和自己写的库建立起合适的联系才能让他们之间认识编译器才能进行工作编译链接等等的后续操作最终生成一个可执行程序
因此得出的结论是未来我们把我们写的静态库提供给别人去使用只需要把对应的.h头文件和对应的.a文件交给别人就够了其中这个.a文件就是我们前面所说的.o文件的集合
那么下一个问题是当使用ldd指令去查看依赖关系的时候却发现一个问题 问题是我们生成的这个a.out并不依赖我们写的库文件这是因为在默认的情况下可执行程序都是动态链接因此ldd指令只能查询动态库而静态库在编译期间就已经被拷贝到可执行程序当中了因此也就查不到对应的信息静态库是无法检查的
这里引出一个结论gcc默认采取的是动态链接但是对于个别库来说如果你只提供.a的方式那编译器也无能为力只会把内容局部性的作为静态链接而其他库则采取的是正常的的动态链接如果带有 -static选项那就必须要采取静态链接的方式了
所以说在使用gcc进行编译的时候如果这个程序依赖10个库那么gcc就会尽量的把这10个库对应的.so文件都拿到但是如果没有动态库也没关系还可以去拿静态库
小结
加入现在需要某个库我们从网上去下载得到了库下一步应该安装库那如何安装库实际上就是把对应的头文件和库文件都安装到系统当中怎么安装到系统本质上就是把对应的文件安装到usr路径下的include路径和lib路径下所以说安装的本质就是把头文件和库文件分别拷贝到系统的指定路径下只要拷贝到gcc的默认路径下那么gcc在进行搜索的过程就不是问题
动态库的制作
关于动态库如何制作呢其实也和静态库类似从原理上将和静态库都相同都是在源文件编译成.o文件后给这些个文件进行打包就形成了动态库区别是在形成对应的.o文件时需要带上一个fPIC的选项这个选项的意思是与位置无关码至于这个是什么意思在后续会有讲解这里只需要知道是这样的原理即可具体原因主要是因为动态库本身没有把内容拷贝到可执行程序当中去因此动态库和可执行程序之间只是地址方面的关联因此使用了动态链接后只是告诉了可执行程序你所需要的内容在哪里在哪一个文件的什么位置你需要的时候自己去找就可以那么这个过程就叫做动态链接所以在使用的时候只需要带上一个fPIC就可以了之后再对生成的.o文件进行打包使用的命令还是gcc命令生成一个.so的文件但是要带上-shared选项表示的这个文件我想要生成的是一个共享库也叫做是动态库
不管是在Linux中还是Windows中也好动态库是比较重要的形成动态库不需要额外的工具只需要gcc就可以帮助我们完成这个过程从这个角度也能看出形成动态库的方法直接内置到了编辑中但是静态库没有做出对应的内置这也就说明动态库的重要性那么下面对于Makefile进行对应的改造生成我们所需要的动态库
# 库的名字是mymath并且是个动态库
dy-liblibmymath.so# 动态库的生成方式是用gcc带上编译选项直接编译就可以
$(dy-lib):Add.o Div.o Mul.o Sub.ogcc -shared -o $ $^# 生成动态库所需要的.o文件需要依赖于.c文件生成并且也需要带上特殊选项表示的是与位置无关码
%.o:%.cgcc -fPIC -c $# 整体将生成的内容进行打包
.PHONY:output
output:mkdir -p mymath_lib_so/includemkdir -p mymath_lib_so/libcp -f *.h mymath_lib_so/includecp -f *.so mymath_lib_so/lib# 对部分内容做出清理
.PHONY:clean
clean:rm -rf *.o *.so mymath_lib_so动态库的使用
如果想对于这个动态库把它安装到系统中那么就需要放到指定的路径下那么现在我们先不对于它做出任何操作只是和静态库一样来尝试编译它结果是 事实上用静态库的编译方式来对动态库进行编译也成功了说明到现在为止和静态库比起来没有任何区别那么接下来接续 在运行程序的过程中失败了不过这也是可以预见的因为静态库相当于直接把内容拷贝进去了而动态库只是告诉你该去哪找而在运行的时候程序并不知道去哪找所以找不见这样的结果也是意料之内的
动态库和你的可执行程序是分离的是两个文件当执行程序的时候程序需要被加载到内存而库中的文件也要能够被系统找到也是要加载到内存中所以说动态链接的程序程序和库文件是分开的在进程进行加载的过程中程序库也要被找到并且加载只有程序库被加载了才能跑的起来动态链接非常依赖动态库
那么如何能找到对应的内容呢下面讨论的就是这个问题
动态库如何找到内容
1. 直接安装到系统中
这个是简单粗暴的方法当然也是简单可行的看下面的操作
把头文件放到系统中 把库文件放到系统中
此时运行程序就可以运行起来了因为进程在运行的过程中可以在默认路径下找到我们所需要的内容就能把这些内容加载到内存中供进程使用调度等等
如果把对应的文件从对应的库中删除那么就不能再使用了 2. 软链接的方式 建立链接后再进行编译运行也能正常运行出结果 说明这也是可行的同时查看ldd情况发现确实是存在链接情况 现在解除链接链接断开也就无法运行了 3. 通过环境变量的方式
这个方式也很好理解默认的寻找方式是到lib64下去寻找然而在这里可以通过修改环境变量使得环境变量中新增一个配置变量这样就能继续寻找了具体操作过程如下 但是环境变量的修改是临时的这样的修改只在当次生效当下次重新登陆就不存在了这是因为环境变量在每次登陆时都会由配置文件对其进行修饰所以最根本的方法其实是修改配置文件这样就能每次都修改成功环境变量
4. 修改配置文件
在Linux中动态库的配置文件的位置在 /etc/ld.so.conf.d/
那么修改的原理就是在这里新增一个文件在文件中写入我们需要的地址就可以了
具体操作展示如下 所以往后你自己需要使用动态库不管是用别人的还是你自己写的库文件如果运行是找不到那么这里就有四种做法
小结
如果同时同一组方法动静态库同时被提供那么默认使用的是动态库并且同一组库会提供动静态两种方式gcc默认使用的是动态库如果想使用静态库就带上-static选项