Linux:基础IO---动静态库

news2025/4/20 5:33:07

文章目录

      • 1. 动静态库前置知识
        • 1.1 动静态库知识回顾
        • 1.2 什么是动静态库
      • 2. 动静态库
        • 2.1 站在库的制作者的角度
        • 2.2 站在库的使用者的角度
        • 2.3 动态库是怎么被加载的(原理)

  • 序:上一篇文章我们从认识到理解,从理解到实现场景,我们知道了什么是软硬链接、数据交换的基本单位—页、操作系统是如何管理内存的还有深入清楚了一个被打开的文件在内核部分是如何被修改文件内容的,而本篇文章将从什么是动静态库,如何连接动静态库,以及动态库在系统内核部分是如何被访问的!!!

1. 动静态库前置知识

1.1 动静态库知识回顾

Linux: .so(动态库).a(静态库)
Windows: .dll(动态库) .lib(静态库)

编译型语言:开发包必然是下载安装对应的头文件和库文件

其中方法的实现就是在库当中

库其实就是把源文件(.c)经过一定翻译,然后打包给你提供一个头文件就行,不用你提供太多源文件

头文件提供你方法的声明,库文件提供你方法的实现+你的代码 == 你的软件(库文件:不做重复工作)

问题一:那么我们的.o文件和库是如何连接的?

动态连接–>动态库(注:动态库不能缺失,否则会导致很多程序无法运行)
静态连接–>静态库

1.2 什么是动静态库

动态库和静态库

动态库因为是共享库,能有效节省资源(磁盘空间、内存空间、网络空间)【优点】,动态库一但缺失,会导致很多程序无法进行【缺点】

静态库,不依赖于库,程序可以独立运行【优点】,体积大,比较消耗资源【缺点】,如果非要静态连接,可以加-static

2. 动静态库

2.1 站在库的制作者的角度

lib.XXX.a—动态链接
lib.XXX.so—静态链接

将我们的方法提供给别人使用:将源代码包装成库和.h文件给别人

问题一:一个程序是如何连接静态库的?

makefile如下:

dy-lib=libmethod.so
static-lib=libmymath.a

.PHONY:all
all: $(static-lib) $(dy-lib)

$(static-lib):mymath.o
	ar -rc $@ $^
mymath.o:mymath.c
	gcc -c $^

$(dy-lib):myprint.o mylog.o
	gcc -shared -o $@ $^ //其中的-shared选项表示要形成动态库
myprint.o:myprint.c
	gcc -fPIC -c $^ //-fPIC表示与地址无关码,在后面一章地址程序空间第二讲中会详细说明
mylog.o:mylog.c
	gcc -fPIC -c $^

.PHONY:clean
clean:
	rm -rf *.a *.o *.so mylib 

.PHONY:output
output:
	mkdir -p ./mylib/include
	mkdir -p ./mylib/lib
	cp mymath.h ./mylib/include 
	cp libmymath.a ./mylib/lib
	cp myprint.h ./mylib/include
	cp mylog.h ./mylib/include 
	cp libmethod.so ./mylib/lib

我们能直接gcc吗?在程序中包含静态库头文件,然后调用静态库中的函数,能直接gcc,就编译通过,并且执行吗?


如图:
在这里插入图片描述
答案显然是不行的!!!

当我们gcc时,gcc没办法通过这个头文件找到这个静态库的头文件的位置,所以程序中的头文件无法被识别!!!

这样是不是就是说,我们要在gcc的时候,将静态库的头文件的绝对或相对路径告诉gcc,才能使编译通过?我们可以试试,如果要告诉程序我们的静态库的头文件在哪,可以加个“-I +[头文件的绝对或相对路径]”选项来告诉gcc我们的静态库的头文件在哪!!!


如图:
在这里插入图片描述
当我们加了“-I”选项后,我们发现之前找不到头文件的报错消失了!!!但是新的问题又出现了!!!即使,gcc已经找到了静态库的头文件的位置了,但gcc没办法调用静态库中的函数!!!所以我们还要告诉gcc这个静态库的方法调用的库的绝对或相对路径!!!如果要告诉程序我们的静态库在哪,可以加个“-L + [.so库绝对或相对路径]”


如图:
在这里插入图片描述
我们发现,即使我们告诉了gcc,我们的头文件的路径和静态库的路径,我们依然没办法将他编译出来,这是为什么?答案就在于gcc即使找到了静态库的目录,gcc也不知道该调用哪一个静态库!!!所以我们的最后一步就是告诉gcc我们要在哪个路径下调用哪个静态库!!!,我们可以使用“-[静态库的名字(去掉前缀lib和后缀.so)]”来告诉gcc我们要调用的静态库的名字!!!


如图:
在这里插入图片描述
终于,我们成功调用了我们自己制作的静态库!!!

总结:
我们调用静态库时要给出调用头文件的路径和调用静态库的路径和静态库的名字!!!在这里大家可能会有个疑问,那就是为什么我们给出头文件的路径时,为什么不要表明我们要调用哪个头文件,其实在程序中我们已经说明了我们要调用哪一个头文件了,所以就不需要再去表明了!!!

补充:
A. 第三方库,在往后使用的时候,必定是要用gcc -l的
B. 深刻理解errno的本质
C. 如果系统中只提供静态链接,gcc则只能对该库进行静态链接
D. 如果系统中需要链接多个库,则gcc可以链接多个库

2.2 站在库的使用者的角度

问题一:一个程序是如何连接动态库的?

有了之前静态库的链接方式,我们也同样按照那样的顺序去链接试试,结果如下:
第一步:直接gcc
在这里插入图片描述
第二步:gcc并加上库头文件的路径
在这里插入图片描述
第三步:gcc加上库头文件的路径和动态库的路径和动态库名字
在这里插入图片描述
问题来了!为什么我们明明加上了库头文件的路径和动态库的路径和动态库名字,而且编译成功了,但是为什么不能正常运行???

当我们编译时,我们告诉了编译器这个动态库的路径和名字,但是当我们编译完后,要执行这个可执行程序时,我们的加载器根本就不知道这个动态库在哪!!!当我们使用命令"ldd+[可执行程序]"时,我们发现这个动态库确实是链接上去了,但是该动态库的指向确实“not found”,这也说明我们的动态库的路径并没有被加载器知道!!!

所以,我们就要让加载器知道我们的动态库在哪!!!

解决加载找不到动态库的方法:

A. 拷贝到系统默认但库路径/usr/lib64/
B. 在系统默认的库路径/usr/lib64/下建立软连接
C. 将自己的库所在的路径,添加到系统的环境变量LD_LIBRARY_PATH中
D. 在目录/etc/ld.so.conf.d中建立自己的动态库路径的配置文件,然后ldcconfig应用即可

实际上,我们用的库都是别人的成熟的库,都是采用直接安装到系统的方式!!!(例如:ncurses----基于终端的库)

这里以第四种方法(也是比较方便的方法)来加载动态库为例:
在这里插入图片描述
在系统路径下的/etc/ld.so.conf.d目录中,我们可以建立自己的动态库路径配置文件,先创建一个conf文件,然后将动态库的绝对路径放入该文件中,最后再ldcnfig进行应用,我们就可以使用动态库链接的可执行文件了!!!

如图:
在这里插入图片描述

动态库在运行时,是要被加载的(静态库没有)

常规的动态库被所有的可执行程序(动态链接的),都要使用,动态库----共享库
所以动态库在系统加载之后,会被所有进程共享。

2.3 动态库是怎么被加载的(原理)

在这里插入图片描述

在这里插入图片描述

当我们执行可执行程序时,当我们要执行动态库中的方法时,动态库会被操作系统加载到物理内存中,然后通过页表映射,映射到进程地址空间当中的共享区内!!!,正文代码就会去自己的进程地址空间的共享区中找到对应的方法,然后调用,将结果返回正文区。当有多个进程访问同一个动态库时,也是通过映射的方法映射同一个物理内存中的动态库,然后在自己的进程地址空间的共享区内调用方法并返回!!!这就是为什么动态库也叫做共享库!!!

结论:建立映射,从此往后,我们执行的任何代码,都是我们进程地址空间中进行执行!!!

事实:系统在运行中,一定会存在多个动态库,所以操作系统要将这些动态库给管理起来—先描述,再组织,所以在操作系统重,所有库的加载情况,操作系统都非常清楚!!!

问题一:如果此时,这个动态库中有一个全局变量errno,但多个进程一起报错,需要返回一个errno值时,岂不是会互相影响吗?

不会互相影响,当一个动态库被多个进程使用时,该动态库是被不同的进程加载到了他们自己的进程地址空间当中的,此时,该动态库的引用计数会加加,当要改变errno的值时,就会引发缺页中断,从而发生写实拷贝!!!此时各个进程的errno值是属于自己进程的,所以各个进程之间不会相互影响!!!

总结:

通过本篇文章我们知道了什么是动静态库以及动静态库的格式,以及如何连接动静态库,动态库和静态库的链接有什么区别,以及动态库在系统内核部分是如何被访问的!!!

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

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

相关文章

深度学习-torch,全连接神经网路

3. 数据集加载案例 通过一些数据集的加载案例,真正了解数据类及数据加载器。 3.1 加载csv数据集 代码参考如下 import torch from torch.utils.data import Dataset, DataLoader import pandas as pd ​ ​ class MyCsvDataset(Dataset):def __init__(self, fil…

Codex CLI - 自然语言命令行界面

本文翻译整理自:https://github.com/microsoft/Codex-CLI 文章目录 一、关于 Codex CLI相关链接资源 二、安装系统要求安装步骤 三、基本使用1、基础操作2、多轮模式 四、命令参考五、提示工程与上下文文件自定义上下文 六、故障排查七、FAQ如何查询可用OpenAI引擎&…

实现窗口函数

java 实现窗口函数 public class SlidingWin {public static void main(String[] args) {SlidingWin slidingWin new SlidingWin();double v slidingWin.SlidWin(2);System.out.println(v);}public double SlidWin(int k){int [] array new int[]{2,4,5,6,9,10,12,23,1,3,8…

清华《数据挖掘算法与应用》K-means聚类算法

使用k均值聚类算法对表4.1中的数据进行聚类。代码参考P281。 创建一个名为 testSet.txt 的文本文件,将以下内容复制粘贴进去保存即可: 0 0 1 2 3 1 8 8 9 10 10 7 表4.1 # -*- coding: utf-8 -*- """ Created on Thu Apr 17 16:59:58 …

MATLAB - 小车倒立摆的非线性模型预测控制(NMPC)

系列文章目录 目录 系列文章目录 前言 一、摆锤/小车组件 二、系统方程 三、控制目标 四、控制结构 五、创建非线性 MPC 控制器 六、指定非线性设备模型 七、定义成本和约束 八、验证非线性 MPC 控制器 九、状态估计 十、MATLAB 中的闭环仿真 十一、使用 MATLAB 中…

HAL库配置RS485+DMA+空闲中断收发数据

前言: (1)DMA是单片机集成在芯片内部的一个数据搬运工,它可以代替单片机对数据进行传输、存储,节约CPU资源。一般应用场景,ADC多通道采集,串口收发(频繁进入接收中断)&a…

【java实现+4种变体完整例子】排序算法中【计数排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格

以下是计数排序的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格: 一、计数排序基础实现 原理 通过统计每个元素的出现次数,按顺序累加得到每个元素的最终位置,并填充到结果数组中。 代码示…

嵌入式单片机开发 - Keil MDK 编译与烧录程序

Keil MDK 编译程序 1、Keil MDK 编译按钮 Build 按钮:重新编译整个工程的所有源文件,无论它们是否被修改过 Rebuild 按钮:仅编译修改过的文件及其依赖项,未修改的文件直接使用之前的编译结果 2、Keil MDK 编译结果 linking... …

裂项法、分式分解法——复杂分式的拆解

目录 一、裂项法 1. 核心思想 2. 适用场景 3. 步骤 4. 例题 二、分式分解 1. 核心思想 2. 适用场景 3. 步骤 4.例题 一、裂项法 1. 核心思想 将一项拆解为多项之差,使得在求和时中间项相互抵消,最终仅剩首尾少数项。 2. 适用场景 级数求和…

黑马点评秒杀优化

异步优化秒杀业务 回顾之前的内容黑马点评 秒杀优惠券集群下一人一单超卖问题-CSDN博客,为了处理并发情况下的线程安全和数据一致性的问题,我们已经完成了查询优惠券信息、判断秒杀是否开始和结束、检查库存、用户ID加锁、创建订单和扣减库存。 尽管之前…

JavaScript 的演变:2023-2025 年的新特性解析

随着Web技术的飞速发展,ECMAScript(简称ES)作为JavaScript的语言标准,也在不断进化。 本文将带你学习 ECMAScript 2023-2025 的新特性。 一、ECMAScript 2023 新特性 1.1 数组的扩展 Array.prototype.findLast()/Array.protot…

[Java · 初窥门径] Java 注释符

🌟 想系统化学习 Java 编程?看看这个:[编程基础] Java 学习手册 0x01:Java 注释符简介 在编写程序时,为了使代码易于理解,通常会为代码加一些注释。Java 注释就是用通俗易懂的语言对代码进行描述或解释&a…

Docker环境下SpringBoot程序内存溢出(OOM)问题深度解析与实战调优

文章目录 一、问题背景与现象还原**1. 业务背景****2. 故障特征****3. 核心痛点****4. 解决目标** 二、核心矛盾点分析**1. JVM 与容器内存协同失效****2. 非堆内存泄漏****3. 容器内存分配策略缺陷** 三、系统性解决方案**1. Docker 容器配置**2. JVM参数优化(容器…

【计算机网络】网络基础(协议,网络传输流程、Mac/IP地址 、端口号)

目录 1.协议简述2.网络分层结构2.1 软件分层2.2 网络分层为什么? 是什么?OSI七层模型TCP/IP五层(或四层)结构 3. 网络与操作系统之间的关系4.从语言角度理解协议5.网络如何传输局域网通信(同一网段) 不同网…

pgsql中使用jsonb的mybatis-plus和jps的配置

在pgsql中使用jsonb类型的数据时,实体对象要对其进行一些相关的配置,而mybatis和jpa中使用各不相同。 在项目中经常会结合 MyBatis-Plus 和 JPA 进行开发,MyBatis_plus对于操作数据更灵活,jpa可以自动建表,两者各取其…

使用MetaGPT 创建智能体(2)多智能体

先给上个文章使用MetaGPT 创建智能体(1)入门打个补丁: 补丁1: MeteGTP中Role和Action的关联和区别?这是这两天再使用MetaGPT时候心中的疑问,这里做个记录 Role(角色)和 Action&…

C# 使用.NET内置的 IObservable<T> 和 IObserver<T>-观察者模式

核心概念 IObservable<T> 表示 可观察的数据源&#xff08;如事件流、实时数据&#xff09;。 关键方法&#xff1a;Subscribe(IObserver<T> observer)&#xff0c;用于注册观察者。 IObserver<T> 表示 数据的接收者&#xff0c;响应数据变化。 三个核心…

Redis——网络模型之IO讲解

目录 前言 1.用户空间和内核空间 1.2用户空间和内核空间的切换 1.3切换过程 2.阻塞IO 3.非阻塞IO 4.IO多路复用 4.1.IO多路复用过程 4.2.IO多路复用监听方式 4.3.IO多路复用-select 4.4.IO多路复用-poll 4.5.IO多路复用-epoll 4.6.select poll epoll总结 4.7.IO多…

vue3 传参 传入变量名

背景&#xff1a; 需求是&#xff1a;在vue框架中&#xff0c;接口传参我们需要穿“变量名”&#xff0c;而不是字符串 通俗点说法是&#xff1a;在网络接口请求的时候&#xff0c;要传属性名 效果展示&#xff1a; vue2核心代码&#xff1a; this[_keyParam] vue3核心代码&…

旅游特种兵迪士尼大作战:DeepSeek高精准路径优化

DeepSeek大模型高性能核心技术与多模态融合开发 - 商品搜索 - 京东 随着假期的脚步日渐临近&#xff0c;环球影城等备受瞩目的主题游乐场&#xff0c;已然成为大人与孩子们心中不可或缺的节日狂欢圣地。然而&#xff0c;随之而来的庞大客流&#xff0c;却总让无数游客在欢乐的…