【Linux笔记】动静态库的封装和加载

一、静态库的封装

我们在学习C语言阶段其实就已经知道一个可执行程序的形成过程分为预处理、编译、汇编、链接这四个阶段,而且也知道我们程序中使用的各种库其实是在链接的阶段加载的。

可我们那时候并不知道库是怎么被加载的,或者库是怎么形成的,所以今天我们就要好好的来聊一下,库的形成。

1.1、库封装的本质

我们知道链接阶段其实是将形成可执行程序的各种.o目标文件连接起来形成可执行程序,但是对于一个库来说,可是如果一个可执行程序使用的很多函数分散在不同的.o文件中,那么这样一个一个的链接就显得很麻烦。

就例如我们现在有这样的一个场景:

如上图,我们有这样一堆头文件和对应的方法实现,我们想要模拟编译器的行为先形成.o文件,再将它们连接形成可执行程序。我们当然可以一个一个的将它们编译形成.o文件,然后再连接:

但这样实在太麻烦,特别是后面链接形成可执行的操作,如果今天我们的可执行程序依赖了100或200个.o文件,那这样不累死人?

所以为了方便,我们可以将一些有关联的.o文件再次打包,形成一个库文件,那这样我们在连接的时候就只需要找到这个库文件就行了。

所以库的封装其实就是将一批.o文件打包。

1.2、静态库的封装方法

我们打包静态库使用的指令是ar -rc指令,例如我们想要将上面的这些方法打包成一个名为mymath的静态库,对应的指令是这样的:

注意:上面所写的库名称为libmymath.a,但是该库的真实名称并不是libmymath,而是mymath,这是因为库文件必须要一个前缀lib,而.a是静态库文件的后缀名。

但是这样使用起来会有点麻烦,这是因为gcc在编译形成可执行程序的时候默认值知道系统默认的库的名称和路径,我们现在这个是我们自己新建的库,所以gcc不认识。所以我们在编译的时候还需要特别指定库名称和库路径。

指定库名称使用的是-l选项,执行库路径使用的是-L选项:

这样我们才能成功的生成可执行程序:

但我们今天还是想要做得更规范一些,一般我们的库文件和头文件是被放到一个目录结构中的,这样就更像一个整体。

我们编写一个makefile来完成再次打包的工作:

这样执行了makefile之后,我们就得到了一个更规范的库文件了:

然后使用的时候就需要注意了,因为我们上面的演示中头文件是和test.c处在同一个路径下的,所以编译的时候不需要指定头文件的路径编译器也能直接找到,而我们今天已经形成了一个库文件,也就是所我们以后其他的源代码想要用这个库中的方法,就只需要有这个库文件即可,而其他的源代码的路径下就不会有对应的头文件了,所以我们在使用的时候还需要多加一个-I的选项表示指定头文件的路径:

二、动态库的封装

2.1、动态库的封装方法

动态库的封装就和静态库有点不一样了,首先动态库的封装是直接使用gcc的,这说明gcc是可以直接形成动态库的。这个后面我也会聊一些,这是因为动态库比起静态库来说更重要,优先级也更高。

第二个不同的地方也比较特殊了,我们在形成对应的.o文件的时候还需要额外的加上一个“与位置无关码”fPIC的选项,这个后面我们简单的聊一些,其实我也不是很懂,记住就行了。

此外还需要加上一个-shared的指令,表示生成的是“共享库”,这个也是到后面聊:

其他的地方就没什么不同了,因为库的本质动态库和静态库是一样的。

所以我们就只需要修改一下makefile即可,也就是像上面生成静态库一样,将二次打包也做好:

执行makfile之后我们就形成了动态库了:

然后使用动态库生成可执行程序的时候也是个静态库一样:

但当我们直接运行的时候就会出现问题了:

如果直接运行的话,会提示找不到动态库,这时候大家可能就会有疑问了,我在形成可执行程序的时候不是已经告诉了编译器库的路径了吗?怎么还会找不到呢?

这是因为静态库和动态库的加载是不一样的。

严格来说,静态库是不需要加载的,因为静态库是在链接的时候将对应的方法一代码的形式“拷贝”到我们可执行程序的代码部分,所以自然的,运行的时候就不要再找静态库了。

而动态库不同,动态库并不是以代码的形式将拷贝到可执行程序的代码部分,它是在运行的时候才加载到“内存”,并不是加载到可执行程序中,然后由可执行程序在内存中去寻找。

所以我们也就知道了,我们编译形成可执行程序的时候只是将库的路径告诉了编译器,但运行是操作系统的事,操作系统当然不知道我们的库在哪里了。

如果想要解决动态库运行时候找不到库的问题,可以有一下四种解决方案。

2.2、解决动态库运行时找不到的三种方法

方法1:直接将动态库安装到系统中默认路径下

我们以前在编译可执行程序的时候,之所以不需要指定库路径和头文件的路径,是因为我们以前使用的都是系统默认支持的库,而这些库的头文件都会存在于系统中的两个默认的路径:/lib64/usr/include中。

所以我们今天就可以直接将我们的头文件和库拷贝到这两个路径中:

这样我们再次运行就可以正常运行了:

并且如果我们今天将可执行程序删掉在重新编译形成,也不再需要指定头文件路径和库路径了,只需要指定库名称即可:

因为我们的头文件和库已经存在于系统的默认路径下了,所以在编译的时候就像我们以前使用系统库一样再默认路径下寻找了,而之所以还需要指定库名称是因为我们实现的mymath本质上还是属于第三方库,而第三方库gcc是不认识的。

而且我们在使用ldd指令来查询可执行程序所依赖的库的时候也是可以查到的,并且显示的路径就是/lib64:

而如果我们将刚才加入的头文件和库都删掉,在用ldd查询的时候就会显示找不到对应的库了:

同时将库直接安装到系统的默认路径下也是我们以后使用第三方库最推荐的一种做法,没有之一。

方法2:在当前路径下创建连接到库的软连接:

其实这也是软连接的一个应用场景,当然啦我们也可以将软连接创建到/lib64目录下,我当前就不做了。

方法3:更改环境变量

在我们的系统中有许许多多的环境变量,而其中有一个是和我们今天动态库加载有关的环境变量——LD_LIBRARY_PATH,这个环境变量就是用来存储我们需要加载的动态库的绝对路径。

但是有的朋友可能这个环境变量是空的或者不存在,这也是很正常的,因为有可能你的系统比较新或者你从来没有设置过这个环境变量。

设置了之后我们就可以,正常的运行我们的可执行程序了:

那我们最后再来做一个实验,就是如果同一套方法,我们机提供了静态库也提供了动态库,编译器会选择哪种库呢?

我们可以先将两个库拷贝到同一个目录下:

然后我们在重新生成可执行程序,再来查看一下它所依赖的库:

从结果中我们可以看到,默认依赖的是动态库,虽然这里找不到,但是也能显示出来我们所依赖的是哪一个库(找不到是因为我们现在库的路径变了,而且我们也把原来的动态库给删除了)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/380970.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

高防服务器出租的优势及特点

高防服务器出租是指租用具备高防御能力的服务器,用于应对网络攻击、保护网站和数据安全。那么为什么会选择高防服务器出租,小编为您整理发布高防服务器出租的优势及特点。 高防服务器通常具备以下特点: 1. 高性能硬件配置:高防服务…

前端工程化面试题 | 01.精选前端工程化高频面试题

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【软考】系统集成项目管理工程师(十五)文档和配置管理【2分】

一、 文档管理 二、配置管理 1、配置项 基线类型基线包括管理原则基线配置项所有设计文档和源程序向开发人员开放读取的权限非基线配置项项目的各类计划额报告向PM、CCB及相关人员开放所有配置项的操作权限应由CMO(配置管理员)严格管理 2、基线 3、配置…

[office] excel求乘积的公式和方法 #媒体#笔记#经验分享

excel求乘积的公式和方法 本文首先给出两个常规的excel求乘积的链接,然后再例举了一个文字和数字在同一单元格里面的excel求乘积的公式写法。 excel求乘积的方法分为两种,第一种是直接用四则运算的*来求乘积,另外一种就是使用PRODUCT乘积函数…

攻防世界 CTF Web方向 引导模式-难度1 —— 11-20题 wp精讲

PHP2 题目描述: 暂无 根据dirsearch的结果,只有index.php存在,里面也什么都没有 index.phps存在源码泄露,访问index.phps 由获取的代码可知,需要url解码(urldecode )后验证id为admin则通过 网页工具不能直接对字母进行url编码 …

LeetCode Python - 6.Z字形变换

文章目录 题目答案运行结果 题目 将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下: P A H N A P L S I I G Y I R 之后,你的输…

部署monggodb单节点分片集群

分片技术,可以满足MongoDB数据量大量增长的需求。当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。…

用Python动态展示排序算法

文章目录 选择冒泡插入排序归并排序希尔排序 经常看到这种算法可视化的图片,但往往做不到和画图的人心灵相通,所以想自己画一下,本文主要实现归并排序和希尔排序,如果想实现其他算法可参考这篇 C语言实现各种排序算法[选择&#x…

v-if 和v-show 的区别

第074个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下,本专栏提供行之有效的源代码示例和信息点介绍,做到灵活运用。 提供vue2的一些基本操作:安装、引用,模板使用,computed&a…

Ps:直接从图层生成文件(图像资源)

通过Ps菜单:文件/导出/将图层导出到文件 Layers to Files命令,我们可以快速地将当前文档中的每个图层导出为同一类型、相同大小和选项的独立文件。 Photoshop 还提供了一个功能,可以基于文档中的图层或图层组的名称,自动生成指定大…

无人机飞控算法原理基础研究,多旋翼无人机的飞行控制算法理论详解,无人机飞控软件架构设计

多旋翼无人机的飞行控制算法主要涉及到自动控制器、捷联式惯性导航系统、卡尔曼滤波算法和飞行控制PID算法等部分。 自动控制器是无人机飞行控制的核心部分,它负责接收来自无人机传感器和其他系统的信息,并根据预设的算法和逻辑,对无人机的姿…

材料非线性Matlab有限元编程:切线刚度法

导读:本文主要围绕材料非线性问题的有限元Matlab编程求解进行介绍,重点围绕牛顿-拉普森法(切线刚度法)、初应力法、初应变法等三种非线性迭代方法的算法原理展开讲解,最后利用Matlab对材料非线性问题有限元迭代求解算法进行实现,展示了实现求解的核心代码。这些内容都将收…

利用Python画布之乌龟的爬行

一.基础操作 1.引入turtle库 首先,在你的Python代码中引入turtle库,代码如下: import turtle 2.创建画布 要创建一个画布,你可以使用turtle库中的Screen类。Screen类提供了一个窗口,你可以在其中创建一个画布。下…

Github 2024-02-08 开源项目日报 Top9

根据Github Trendings的统计,今日(2024-02-08统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Ruby项目1HTML项目1Python项目1Scala项目1PLpgSQL项目1Rust项目1NASL项目1C项目1TypeScript项目1非开发语言项目…

结构体的大小以及内存对齐问题

结构体的大小怎么计算?什么是结构体的对齐? 首先想要直到结构体的大小需要先了解结构体的内存对齐。那么,什么是结构体的内存对齐: 什么是结构体内存对齐 结构体的对齐 就是 结构体类型数据在内存中按照一定的对齐规律储存。结…

中科大计网学习记录笔记(七):Web and HTTP

前言: 学习视频:中科大郑烇、杨坚全套《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》课程 该视频是B站非常著名的计网学习视频,但相信很多朋友和我一样在听完前面的部分发现信…

免费软件推荐-开源免费批量离线图文识别(OCR)

近期要批量处理图片转电子化,为了解决这个世纪难题,试了很多软件(华为手机自带OCR识别、 PandaOCR、天若OCR、Free OCR)等软件,还是选择了这一款,方便简单 一、什么是OCR? 光学字符识别(Opt…

【Java EE初阶十一】文件操作(IO)

1. 认识文件 所谓的文件是一个广义的概念,可以代表很多东西;在操作系统里面,会把很多的硬件设备和软件设备都抽象成“文件”,统一进行管理;但是大部分情况下,我们读到的文件,都是指硬盘的文件&a…

泽攸科技ZEM系列台扫助力环境科研创新:可见光催化抗生素降解的探索

环境污染和能源短缺是当今人类社会面临的最严重威胁之一。为了克服这些问题,特别是在污水处理过程中,寻找新的技术来实现清洁、高效、经济的发展显得尤为重要。在各种工业废水中,抗生素的过量排放引起了广泛关注。抗生素的残留会污染土壤、水…

【机器学习】数据清洗之处理缺失点

🎈个人主页:甜美的江 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:机器学习 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步…