你不知道的库:库的种类,作用和加载方式

你不知道的库:库的种类,作用和加载方式

📟作者主页:慢热的陕西人

🌴专栏链接:Linux

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

本博客主要内容讲解了库的概念和为什么要有库,以及静态库和动态库,最后还有最重要的库的加载的理解以及动态库的三种配置方法

文章目录

  • 你不知道的库:库的种类,作用和加载方式
    • 1.了解一下库
    • 2.为什么要有库
    • 3.写一写----从库的书写者的角度
      • 3.1库的命名规则:
    • 4.用一用----站在使用者的角度去使用我们写的库
      • 4.1静态库
      • 4.2动态库
    • 5.动态库配置问题
      • 5.1环境变量
      • 5.2软链接方案
      • 5.3配置文件方案
    • 6.动态库加载过程的理解
      • 6.1 动态库加载问题和周边问题:
      • 6.2库中地址的理解

1.了解一下库

虽然我们目前没有使用过第三方库,但是我们一直在使用一些C/C++内部的标准库,那么我们来在目录中查看一下这些库:

包括我们甚至可以找到我们经常使用的stdio.h标准库,并且可以使用vim编辑器进行查看的!

image-20231121142639688

所以我们可以理解到:

①系统已经预装了C/C++的头文件和库文件,头文件提供方法说明,库提供方法实现,头和库是有对应关系的,是要组合在一起使用的。

②头文件是在预处理阶段就引入的,链接的本质其实就是链接库!

另外我们也可以理解一些现象了:

① 所以我们在vs2019,2022下安装开发环境—安装编译器软件,其实就是安装要开发的语言配套的库和头文件

②我们在使用编译器的时候,都会有语法的自动提醒功能,需要先包含头文件。**语法提醒本质:**编译器或者编辑器,它会自动的将用户输入的内容,不断的在被包含的头文件中进行搜索,自动提醒功能依赖于头文件的。

③我们在写代码的时候,我们的环境怎么知道我们的代码中有那些地有语法报错,那些地方定义变量有问题?不要太小看编译器,编译器有命令行模式,也就是我们在Linux中使用gcc命令那样,也有其他的自动化模式帮我们不断在进行语法检查。

2.为什么要有库

库可以帮助我们提高开发效率,我们学习的时候提倡去造轮子,帮我们深入理解库的原理和实现方法。

到开发中,我们更提倡用轮子!

当然我们也可以选择将以提供源代码的方式,来提高开发效率,但是这对我们未来是由一些其他问题的比如我们不想让使用者看到我们的代码,比如我们的公司向另一个公司提供软件服务,我们只需要将打包好的库给他们使用即可,而不会把源码直接给他们!

3.写一写----从库的书写者的角度

库分为静态库(.a)动态库(.so)

另外一般云服务器,默认只会存在动态库,不会存在静态库,静态库需要独自安装!

3.1库的命名规则:

例如:libstdc++.so.6

去掉前面的lib和后面的第一个.后面包括.的内容结恶果就是库的名称了!

所以例子的这个库的名称使stdc++;

4.用一用----站在使用者的角度去使用我们写的库

4.1静态库

我们先简单实现一个加减函数的库:

我们先写四个文件:

//myadd.c  
#include"myadd.h"int myadd(int a, int b)
{return a + b;
}
//myadd.h
#pragma once
#include<stdio.h>int myadd(int a, int b);
//mysub.c
#include"mysub.h"
int mysub(int a, int b)
{return a - b;
}
//  mysub.h
#pragma once#include<stdio.h>int mysub(int a, int b);

首先我们之前的做法就是在写一个主函数的文件将他们一块编译:

但是这是我们只有这么两个源文件的时候看起来还可以,但是当我们的项目非常庞大的时候,并且我们需要分享给别人使用我们的库的时候,就非常的不方便了!

image-20231121165901487

我们将.c源文件都让其生成.o文件,也就是未链接前的文件:

利用ar命令生成静态库:ar -rc libmymath.a myadd.o mysub.o

image-20231121174308280

当我们把libmymath.a文件挪动到我们的ortherperson目录下的时,我们尝试编译的时候:

发现提示我们找不到头文件

image-20231121174153962

所以我们这样的方式是不对的!

我们先在ortherperson下创建两个文件夹libinclude分别存放生成的静态库和对应的头文件;

正确的是这样:gcc -o mytest main.c -I./include -L./lib -lmymath

我们来解释一下:

  • -I:其中I表示的inlcude的意思,也就是头文件的意思后面直接跟上我们头文件的路径
  • -L:其中L表示的Lib的意思,就是我们的库的意思,后面直接跟上我们静态库的路径
  • -l:这个参数后面紧跟我们的静态库的名字,就是我们前面命名规则说的那样,去掉前面的lib.后面的内容就是我们的静态库的名字!

image-20231121174529404

那么我们接下来尝试一下把我们的库放到语言库中直接去调尝试一下:

[root@lavm-5wklnbmaja ortherperson]# cp lib/libmymath.a /lib64
[root@lavm-5wklnbmaja ortherperson]# cp include/*.h /usr/include

尝试去编译:

我们发现编译成功,并且运行成功!

image-20231121180401518

所以我们这里就可以引入第三方库的使用:

①首先我们需要指定的头文件和库文件

②如果没有默认安装到系统gcc,g++默认的搜索路径下,用户必须指明对应的选项,告知编译器:

​ a.头文件在哪;

​ b.库文件在哪;

​ c.库文件具体是谁

③将我们下载下来的库和头文件,拷贝到系统默认路径下---- 在Linux下安装库!!那么卸载呢?对任何软件而言,安装和卸载的本质就是拷贝到系统特定的路径。

④如果我们安装的库是第三方的(语言,操作系统系统接口) 库,我们要正常使用,即便是已经全部安装到了系统中,gcc/g++必须要用-l指明具体库的名称!

理解现象:

​ 无论我们是从网络中未来直接下载好的库,或者是源代码(编译方法) — make install 安装的命令 --cp,安装到系统中,我们安装大部分指令,库等等都是需要sudo的或者超级用户操作!

4.2动态库

我们删除掉之前的只留下最开始的源文件和头文件:

我们重新生成.o文件:

[mi@lavm-5wklnbmaja mylib]$ gcc -c -fPIC -o myadd.o myadd.c
[mi@lavm-5wklnbmaja mylib]$ gcc -c -fPIC -o mysub.o mysub.c

其中:fPIC:产生位置无关码(position independent code)

image-20231121185348586

再生成动态库:

gcc -shared -o libmymath.so myadd.o mysub.o

image-20231121185748618

接下来我们尝试链接动态库:

gcc -o main main.c -Iinclude -Llib -lmymath

链接成功了,但是我们运行的时候却报错了,报错说无法找到我们的动态库文件!但是我们的链接却通过了。原因是我们确实把动态库的位置告诉了编译器,但是却没告诉操作系统!

image-20231121190107295

那么这里为什么没有成功呢?这里其实就是静态库和动态库的区别了,对于静态库将用户使用的二进制代码直接拷贝到可执行目标文件的程序中。但是我们的静态库不会。

5.动态库配置问题

运行时,OS是如何查找我们的动态库的?三种方法

5.1环境变量

动态库需要再一个环境变量LD_LIBRARY_PATH 中去寻找我们的动态库!(告诉操作系统动态库的位置)。

我们只需要把我们当前的动态库的路径添加到这个环境变量中即可:

image-20231121192516738

我们ldd查看一下链接的情况并且运行一下:

image-20231121192541623

当然这种方案我们不是很推崇是一种临时方案,原因是我们知道环境变量我们如果没有再配置文件修改的话,我们每次重新登录或者重启bash都会导致环境变量的初始化。

5.2软链接方案

sudo ln -s /learn/lesson11/ortherperson/lib/libmymath.so /lib64/libmymath.so

这个时候ldd我们再去查看的时候:

image-20231121193409826

并且我们这时候再去运行发现是没有任何问题的:

image-20231121193534934

并且对于软链接来说它不是临时的,就算我们重启bash也不会影响,因为他是真正写入到磁盘内部的,而不是在内存中!

5.3配置文件方案

首先我们查看一下系统的默认配置文件:

[mi@lavm-5wklnbmaja lesson11]$ ls /etc/ld.so.conf.d/
kernel-3.10.0-957.el7.x86_64.conf  mariadb-x86_64.conf

我们在这个目录下添加以一个我们的配置文件:xupt_lib.conf

//创建配置文件
[mi@lavm-5wklnbmaja lesson11]$ sudo touch /etc/ld.so.conf.d/xupt_lib.conf
//像配置文件中写入我们的动态库所在的绝对路径
[mi@lavm-5wklnbmaja lib]$ sudo vim /etc/ld.so.conf.d/xupt_lib.conf

我们ldd查看一下:

image-20231122150326397

发现似乎还是没有链接上,其实我们还少一步生效配置文件:

[mi@lavm-5wklnbmaja ortherperson]$ sudo ldconfig

运行一下看看:

image-20231122150654301

尝试运行:

image-20231122150722572

6.动态库加载过程的理解

静态链接形成的可执行程序中本身就有静态库中对应的方法实现!

首先我们的静态库存储在硬盘中,当多个可执行文件都要使用到这个库的时候,他就会加载到每个可执行程序内部。会让每个可执行程序的变大。其次因为它加载到了可执行程序内部,所以我们在外部删除这个静态库的时候我们的程序依然可以正常运行。所以主流会多使用动态库多一些:


6.1 动态库加载问题和周边问题:

链接:将可执行程序内部的外部符号,替换称为库中的具体地址。

只要我们把库加载到内存,映射到进程的地址空间中之后,我们的代码执行库中的方法,就依旧还是在自己的地址空间内进行函数跳转即可!

并且为什么动态库节省资源,原因是当多个进程都要使用到同一个动态库的时候,这个动态库只需要在内存加载一份,每个进程只需要在自己的进程地址空间中进行映射即可!因为我们曾经在链接动态库的时候程序内部已经存储了相关数据和函数的地址信息!

image-20231122154713731

有时候我们的库很大,我们的程序并不会用到其中所有的接口,所以我们的操作系统也没必要把库中所有的信息都加载到内存中。

6.2库中地址的理解

动态库必定面临一个问题:

不同的进程,运行的程度不同,需要使用的第三方库是不同的,注定了每一个共享空间中空闲位置是不确定的

在程序翻译链接,形成可执行程序的时候,程序内部有没有地址?

答案是有的:动态库中的地址,决定不能确定,所以不能使用绝对地址!动态库中的所有地址,都是偏移量(相对地址),默认从0开始。

当一个库,真正的被映射进地址空间的时候,它的起始地址才会被真正的确定!当我们映射的时候是将进程地址空间的内部的代码区包含库的相对地址+我们的动态库的初始地址,一块存储到进程地址空间对应的共享代码空间的位置!并且这个地址一旦被确定是不变的!所以我们经过这种方式就可以去访问动态库中的方法了!

所以动态库在我们的进程地址空间中随意加载,与我们在地址空间中加载的位置毫无关系!

所以这时候我们也可以理解之前,链接动态库的时候我们生成的汇编文件的时候带了一个参数-fPIC,被称作与位置无关码:也就是对应我们这里的相对地址,偏移量!

接下来我们验证一下:

我们重新生成一个非无关码的汇编文件:用于生成对应的静态库文件。

[mi@lavm-5wklnbmaja mylib]$ gcc -o myadd_static.o -c myadd.c
[mi@lavm-5wklnbmaja mylib]$ gcc -o mysub_static.o -c mysub.c
//生成对应的静态库
[mi@lavm-5wklnbmaja mylib]$ ar -rc libmymath.a myadd_static.o mysub_static.o 

将两个库拷贝到我们的ortherperson/lib目录下:

image-20231122171305250

接下来我们有一个问题,当静态库和动态库同时存在的情况下,我们的可执行文件会优先使用哪个呢?答案肯定是动态库

我们试验一下:重新编译文件并运行

image-20231122171700679

我们ldd查看一下可执行程序的链接情况:很显然是我们的动态库!

image-20231122171733025

那如果我们呢执意要静态链接呢?只需要再加一个参数-static

[mi@lavm-5wklnbmaja ortherperson]$ gcc -o mytest-s main.c -I./include -L./lib -lmymath -static

当我们尝试编译的时候报错了:这是因为我们没有安装对应的库:sudo yum install -y glibc-static

image-20231122183954762

我们分别在三种情况下编译:
①动态库和静态库都存在的情况生成:mytest-d

②动态库和静态库都存在的情况下加-static参数生成:mytest-s

③删除动态库只留下静态库再生成:mytest-u

ldd查看三个文件:

image-20231122184419491

所以我们可以得出结论:

①动态库和静态库同时存在,系统默认使用动态库

②编译器,在链接的时候,如果库提供了动和静,优先动,没有动,才使用静!

到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 Redis BitMap 实现签到与查询历史签到以及签到统计功能(SpringBoot环境)

目录 一、前言二、Redis BitMap 位图原理2.1、BitMap 能解决什么2.2、BitMap 存储空间计算2.3、BitMap 存在问题 三、Redis BitMap 操作基本语法和原生实现签到3.1、基本语法3.2、Redis BitMap 实现签到操作指令 四、SpringBoot 使用 Redis BitMap 实现签到与统计功能4.1、代码…

前端CSS实现响应式TimeLine效果(附源码)

文章目录 纯CSS搭建&#xff0c;先上效果图&#xff08;附有源码&#xff09;视图层 index.htmlindex.css 公用样式文件Main.css 主要的样式文件 纯CSS搭建&#xff0c;先上效果图&#xff08;附有源码&#xff09; 本效果为纯CSS搭建&#xff0c;适配移动端和PC端&#xff01…

MySQL 事务的底层原理和 MVCC(二)

7.2. undo 日志 7.2.1. 事务回滚的需求 我们说过事务需要保证原子性&#xff0c;也就是事务中的操作要么全部完成&#xff0c;要么什么也不做。但是偏偏有时候事务执行到一半会出现一些情况&#xff0c;比如&#xff1a; 情况一&#xff1a;事务执行过程中可能遇到各种错误&a…

力扣C++学习笔记——C++ 给vector去重

要使用std::set对std::vector进行去重操作&#xff0c;您可以将向量中的元素插入到集合中&#xff0c;因为std::set会自动去除重复元素。然后&#xff0c;您可以将集合中的元素重新存回向量中。以下是一个示例代码&#xff0c;演示如何使用std::set对std::vector进行去重&#…

数据结构学习笔记——多维数组、矩阵与广义表

目录 一、多维数组&#xff08;一&#xff09;数组的定义&#xff08;二&#xff09;二维数组&#xff08;三&#xff09;多维数组的存储&#xff08;四&#xff09;多维数组的下标的相关计算 二、矩阵&#xff08;一&#xff09;特殊矩阵和稀疏矩阵&#xff08;二&#xff09;…

opengl制作天空盒

首先创建顶点数组 unsigned int m_uiVaoBufferID; glGenVertexArrays(1, &m_uiVaoBufferID); 然后创建顶点缓冲区 float skyboxVertices[] {// positions-1.0f, 1.0f, -1.0f,-1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f,1.0f, 1.0f, -1.0f,-1.0f, 1.…

基于晶体结构算法优化概率神经网络PNN的分类预测 - 附代码

基于晶体结构算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于晶体结构算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于晶体结构优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

Android Studio 安装及使用

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

基于一致性算法的微电网分布式控制MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 本模型主要是基于一致性理论的自适应虚拟阻抗、二次电压补偿以及二次频率补偿&#xff0c;实现功率均分&#xff0c;保证电压以及频率稳定性。 一致性算法 分布式一致性控制主要分为两类&#xff1a;协调同…

深度学习之生成唐诗案例(Pytorch版)

主要思路&#xff1a; 对于唐诗生成来说&#xff0c;我们定义一个"S" 和 "E"作为开始和结束。 示例的唐诗大概有40000多首&#xff0c; 首先数据预处理&#xff0c;将唐诗加载到内存&#xff0c;生成对应的word2idx、idx2word、以及唐诗按顺序的字序列。…

基于材料生成算法优化概率神经网络PNN的分类预测 - 附代码

基于材料生成算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于材料生成算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于材料生成优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

矩阵知识补充

正交矩阵 定义&#xff1a; 正交矩阵是一种满足 A T A E A^{T}AE ATAE的方阵 正交矩阵具有以下几个重要性质&#xff1a; A的逆等于A的转置&#xff0c;即 A − 1 A T A^{-1}A^{T} A−1AT**A的行列式的绝对值等于1&#xff0c;即 ∣ d e t ( A ) ∣ 1 |det(A)|1 ∣det(A)∣…

【开源】基于Vue.js的教学过程管理系统

项目编号&#xff1a; S 054 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S054&#xff0c;文末获取源码。} 项目编号&#xff1a;S054&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 教师端2.2 学生端2.3 微信小程序端2…

D. Absolute Beauty - 思维

题面 分析 补题。配上题解的图&#xff0c;理解了很长时间&#xff0c;思维还需要提高。 对于每一对 a i a_i ai​和 b i b_i bi​&#xff0c;可以看作一个线段的左右端点&#xff0c;这是关键的一步&#xff0c;那么他们的绝对值就是线段的长度&#xff0c;对于线段相对位…

Microsoft Visual Studio 2019下载及安装流程记录

第一周任务&#xff1a; 1.笔记本上安装vc2019的环境 2.再把OpenCV安装上 3.根据网上的教程&#xff0c;试着写几个opencv的程序 一、安装Visual Studio 2019社区版 首先先完成安装vc2019的环境&#xff0c; 因为&#xff1a; Microsoft Visual C是用于C编程的工具集合&am…

计算机毕业论文内容参考|基于深度学习的交通标识智能识别系统的设计与维护

文章目录 导文摘要前言绪论1课题背景2国内外现状与趋势3课题内容相关技术与方法介绍系统分析总结与展望导文 基于深度学习的交通标识智能识别系统是一种利用深度学习模型对交通标识进行识别和解析的系统。它可以帮助驾驶员更好地理解交通规则和安全提示,同时也可以提高道路交通…

【tomcat】java.lang.Exception: Socket bind failed: [730048

项目中一些旧工程运行情况处理 问题 1、启动端口占用 2、打印编码乱码 ʮһ&#xfffd;&#xfffd; 13, 2023 9:33:26 &#xfffd;&#xfffd;&#xfffd;&#xfffd; org.apache.coyote.AbstractProtocol init &#xfffd;&#xfffd;&#xfffd;&#xfffd;: Fa…

Active Directory 和域名系统(DNS)的相互关系

什么是域名系统&#xff08;DNS&#xff09; 域名系统&#xff08;DNS&#xff09;&#xff0c;从一般意义上讲是一种将主机名或域名解析为相应IP地址的手段。 在 AD 的中&#xff0c;DNS 服务维护 DNS 域和子域的工作命名空间&#xff0c;这些域和子域主要有助于查找过程&am…

echarts 几千条分钟级别在小时级别图标上展示

需求背景解决效果ISQQW代码地址strategyChart.vue 需求背景 需要实现 秒级数据几千条在图表上显示&#xff0c;(以下是 设计图表上是按小时界别显示数据&#xff0c;后端接口为分钟级别数据) 解决效果 ISQQW代码地址 链接 strategyChart.vue <!--/** * author: liuk *…

2023 年 亚太赛 APMCM ABC题 国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 以五一杯 A题为例子&#xff0c;以下是咱们做的一些想法呀&am…