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

news2024/11/26 17:35:29

一、静态库的封装

我们在学习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,这个环境变量就是用来存储我们需要加载的动态库的绝对路径。

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

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

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

项目访问量激增该如何应对

✨✨ 欢迎大家来到喔的嘛呀的博客✨✨ 🎈🎈希望这篇博客对大家能有帮助🎈🎈 目录 引言 一. 优化数据库 1.1 索引优化 1.2 查询优化 1.3 数据库设计优化 1.4 事务优化 1.5 硬件优化 1.6 数据库配置优化 二. 增加服务器资源…

监督学习:从数据中挖掘模式的引导

目录 前言1 定义2 举例说明3 回归问题4 分类问题结论 前言 监督学习是机器学习领域中的一种重要方法,通过给模型提供带有标签的训练数据,使其能够学习输入与输出之间的关系。这种学习方式在各个领域都有广泛的应用,从垃圾邮件过滤到医学诊断…

ClickHouse--08--SQL DDL 操作

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 SQL DDL 操作1 创建库2 查看数据库3 删除库4 创建表5 查看表6 查看表的定义7 查看表的字段8 删除表9 修改表9.1 添加列9.2 删除列9.3 清空列9.4 给列修改注释9.5 修…

【AI视野·今日CV 计算机视觉论文速览 第298期】Fri, 26 Jan 2024

AI视野今日CS.CV 计算机视觉论文速览 Fri, 26 Jan 2024 Totally 71 papers 👉上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Multimodal Pathway: Improve Transformers with Irrelevant Data from Other Modalities Authors Yiyuan Zhang, Xiaohan …

ARP请求的构造过程

ARP请求的构造过程: ARP请求的构造: 当设备A(发起者)想要与设备B(目标)通信,但它只知道设备B的IP地址(例如,192.168.1.2),而不知道其MAC地址。设备…

OpenGL-ES 学习(4)---- OpenGL-ES 坐标体系

坐标体系 我们知道 OpenGL -ES 坐标系中每个顶点的 x,y,z 坐标都应该在 -1.0 到 1.0 之间,超出这个坐标范围的顶点都将不可见。 将一个物体(图像)渲染到屏幕上,通常经过将物体坐标转换为标准化设备坐标&am…

顺序表(上)

1.顺序表的概念 顺序表(Sequential List)是一种基本的数据结构,它是一种线性表的存储结构。线性表是一种数据元素的有限序列,元素之间存在顺序关系。 线性表:线性表( linearlist )是n个具有相…

PHP毕业设计图片分享网站76t17

图片分享网站主要是为了提高工作人员的工作效率和更方便快捷的满足用户,更好存储所有数据信息及快速方便的检索功能,对系统的各个模块是通过许多今天的发达系统做出合理的分析来确定考虑用户的可操作性,遵循开发的系统优化的原则,…

【树莓派系统的位数】

要区分 ARM 架构下载的版本是 32 位还是 64 位,可以执行以下步骤: 执行以下命令来检查 Raspberry Pi 的 CPU 类型: uname -m如果返回的结果是 aarch64,则表示您的 Raspberry Pi 是 64 位的 ARM 架构。如果返回的结果是 armv7l&a…

代码随想录 Leetcode134. 加油站

题目&#xff1a; 代码(首刷看解析 2024年2月15日&#xff09;&#xff1a; class Solution { public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int curSum 0;int sum 0;int startIndex 0;for (int i 0; i < gas.size(); i)…

18 19 SPI接口的74HC595驱动数码管实验

1. 串行移位寄存器原理&#xff08;以四个移位寄存器为例&#xff09; 1. 通过移位寄存器实现串转并&#xff1a;一个数据输入端口可得到四位并行数据。 通过给data输送0101数据&#xff0c;那么在经过四个时钟周期后&#xff0c;与data相连的四个寄存器的输出端口得到了0101…

高德地图上绘制热力图的方法

百度地图和高德地图的JavaScript API都提供了热力图的绘制方法&#xff0c;都是将热力图作为新的图层&#xff0c;叠加到地图上。但是百度地图的经纬度体系与我们的经纬度存在偏差&#xff0c;高德的与我们相符&#xff0c;应当使用高德地图JavaScript API。 因为是JavaScript…

一个人被锁死在公司底层的根本原因

一、现代社会对员工角色的认知 随着经济全球化和科技进步,现代社会对员工的认知发生了深刻的变化。传统上,员工被视为公司的执行者和生产者,承担着重复性、机械性的工作。然而,随着知识经济和服务型经济的兴起,员工角色逐渐从“执行者”转变为“创造者”和“合作者”。员…

python-分享篇-五子棋

文章目录 代码效果 代码 """五子棋之人机对战"""import sys import random import pygame from pygame.locals import * import pygame.gfxdraw from checkerboard import Checkerboard, BLACK_CHESSMAN, WHITE_CHESSMAN, offset, PointSIZE 3…

CSRNET图像修复,DNN

CSRNET图像修复 CSRNET图像修复&#xff0c;只需要OPENCV的DNN

Momentum2

攻击机 192.168.223.128 目标机 192.168.223.147 主机发现 nmap -sP 192.168.223.0/24 端口扫描 nmap -sV -A -p- 192.168.223.147 开启了22 80 端口 看一下web界面 源码&#xff0c;robots.txt ,url都观察了一下好像没什么有用信息 扫一下目录 gobuster dir -u http:…

H5 树叶飘动二次元引导页源码

H5 树叶飘动二次元引导页源码 源码介绍&#xff1a;一款H5 树叶飘动二次元引导页源码&#xff0c;带有很多可选跳转按钮。 下载地址&#xff1a; https://www.changyouzuhao.cn/10386.html

【C语言】指针的入门篇2,深入理解指针和数组的关系

欢迎来CILMY23的博客喔&#xff0c;本期系列为【C语言】指针的入门篇2&#xff0c;深入理解指针和数组的关系&#xff0c;图文讲解指针和数组关系的知识&#xff0c;带大家理解指针和数组的关系&#xff0c;以及指针数组的用法&#xff0c;感谢观看&#xff0c;支持的可以给个赞…

投资理财的正确方式,实现个人的财富积累

一、教程描述 本套理财教程&#xff0c;大小18.98G&#xff0c;共有16个文件。 二、教程目录 第01课&#xff1a;记账为什么能帮月薪3000的你&#xff0c;省20%&#xff1f;.mp4 第02课&#xff1a;玩转信用卡&#xff0c;银行帮你越刷越有钱.mp4 第03课&#xff1a;巧用公…

代码+视频基于R语言进行K折交叉验证

我们在建立数据模型后通常希望在外部数据验证模型的检验能力。然而当没有外部数据可以验证的时候&#xff0c;交叉验证也不失为一种方法。交叉验验证&#xff08;交叉验证&#xff0c;&#xff23;&#xff36;&#xff09;则是一种评估模型泛化能力的方法&#xff0c;广泛应用…