动静态库--
目录
一 静态库
1. 创建静态库
2. 使用静态库
2.1 第一种
2.2 第二种
二 动态库
1. 创建动态库
2. 使用动态库
三 静态库 VS 动态库
四 动态库加载
1. 可执行文件加载
2. 动态库加载
一 静态库
Linux静态库:.a结尾
Windows静态库:.lib结尾
1. 创建静态库
ar -xxx 形成的文件 目标文件
// r (replace) 存在则替换
// c (create) 不存在则创建
2. 使用静态库
2.1 第一种
先生成 .o 文件
g++/gcc -c 可执行文件
构建静态库文件:把一个或多个.o文件打包
ar -rc 形成的静态库文件 .o 文件
把静态库文件放在系统默认的工作目录下,把头文件也放到系统默认的工作目录下。
然后
gcc/g++ 可执行文件 -l 去掉前缀lib和后缀.a,只留下中间的字符串
这种方式严重不推荐使用,因为系统存放的是官方提供的库,建议不要和第三方写的库混在一起。
示例:
// fun.cc
int add(int x,int y)
{return x+y;
}
int sub(int x,int y)
{return x-y;
}
// fun.hpp
int add(int x,int y);
int sub(int x,int y);
// test.cc
#include <iostream>
#include "fun.hpp"int main()
{std::cout<<add(10,20)<<std::endl;std::cout<<sub(10,20)<<std::endl;return 0;
}
1. 首先把方法形成点o文件。
g++ -c fun.cc 形成 fun.o
2. 然后再把 fun.o 打包成静态库。
ar -rc libmyfun.a fun.o 形成 libmyfun.a
3. 在把头文件 fun.hpp 放在系统默认的工作目录 /usr/include/
4. 再把 libmyfun.a 放在系统默认的工作目录 /lib64/
5. 最后一步把包含的头文件去掉双引号替换成尖括号,除了源文件,其他的可以删除了,因为已经拷贝到系统目录下了。
6. 最后 g++ test.cc -l myfun 去掉 前缀 lib 和 .a 后缀。
2.2 第二种
前面是借用系统默认路劲来进行方便查找的,也可以自己指定头文件指定路劲和库文件指定路径。
gcc/g++ 可执行文件 -I 自己的头文件所在的目录 -L 自己的所在的目录 -l 库文件名 去掉前缀lib和后缀.a
1. 为什么库文件要指定名称,头文件不需要?因为头文件默认是在系统找,但你 -I 指定了路劲,就在指定的路劲下找,因为你已经包了头文件,所以就不需要指定头文件名了。
2. 如果不用尖括号表示,就不在系统找,用双引号表示就需要包你的头文件处于当前目录的相对路径。
示例:
1. 还是和上面一样把方法打包成静态库,在编译的时候进行 -I指定头文件路径,-L指定库文件路径,-l指定库文件名。
2. 把源代码里面的尖括号去掉换成双引号也行
-I 和 双引号本质是一样的都是指定路径下找,但 -I不需要指名库文件名,源代码已经包含了,双引号要指名。
二 动态库
Linux静态库:.so结尾
Windows静态库:.dll结尾
1. 创建动态库
1. 创建 .o 文件
gcc/g++ -fpic -o 文件名
2. 创建动态库
gcc/g++ -shared .o文件 -o 形成的文件名 -> lib开头 .so结尾
2. 使用动态库
gcc/g++ 可执行文件名 -I 指定头文件路径 -L 指定方法路径 -l 指定方法名 去掉lib和.so
生成的可执行文件直接运行会报链接错误,因为动态库是程序运行的时候进行连接,虽然gcc/g++能编过,因为指定了,但后续执行可执行文件,就是操作系统做的了,但操作系统不知道你是要动态查找库,所以要加选项,
第一种方法:
因为操作系统在运行时也会在系统默认的路径下查找动态库,所以直接把库名拷贝到这个路径下即可。
第二种方法:
与动态库进行软连接到系统目录下,本质和第一种是一样的。
第三种方法:
把动态库路径导入到环境变量中 LD_LIBRARY_PATH 但是是内存级的,或者直接修改用户家目录的隐藏文件 .bashrc ,给LD_LIBRARY_PATH配置动态库路径。
第四种方法:
在 /etc/ld.so.conf.d 这个目录下新建一个文件以.conf结尾,并写入动态库路径。
三 静态库 VS 动态库
如果同时有静态库和动态库,则优先连接动态库,除非加上 -static 选项表示全部静态连接,否则有动态库连接动态库,没有则连接静态库。
静态库是在连接的时候把库文件直接拷贝到源文件中,体积非常大,而动态库则是在运行的时候去查找库,体积小。
静态库,每个可执行文件都会拷贝一份,动态库所有程序在运行时共享。
静态库如果变更,则重新需要编译源代码,动态库只需要改变库方法里的实现即可。
四 动态库加载
1. 可执行文件加载
1.1 经过编译之后的文件
先来看看这个代码
#include <iostream>int add(int x,int y)
{return x+y;
}
int main()
{add(1,2);return 0;
}
进行反汇编 objdump -d 可执行文件
1168 <Z3addii>:
| 1168: f3 0f 1e fa | endbr64 |
| 116c: 55 | push %rbp |
| 116d: 48 89 e5 | mov %rsp,%rbp |
| 1170: 89 7d fc | mov %edi,-0x4(%rbp) |
| 1173: 89 75 f8 | mov %esi,-0x8(%rbp) |
| 1176: 8b 55 fc | mov -0x4(%rbp),%edx |
| 1179: 8b 45 f8 | mov -0x8(%rbp),%eax |
| 117c: 01 d0 | add %edx,%eax |
| 117e: 5d | pop %rbp |
| 117f: c3 | ret |1180 <main>:
| 1180: f3 0f 1e fa | endbr64 |
| 1184: 55 | push %rbp |
| 1185: 48 89 e5 | mov %rsp,%rbp |
| 1188: be 02 00 00 00 | mov $0x2,%esi |
| 118d: bf 01 00 00 00 | mov $0x1,%edi |
| 1192: e8 d1 ff ff ff | call 1168 <Z3addii> |
| 1197: b8 00 00 00 00 | mov $0x0,%eax |
| 119c: 5d | pop %rbp |
| 119d: c3 | ret |
显然文件进行汇编之后是有地址的,也就是说文件没有没加载到内存,在磁盘上就已经有了地址了,定义的变量数据都被转换成地址了。
1. 每个函数内部的地址都是相对于该函数的起始位置的偏移量,比如 1168 -> 1 ,-> 2 , -> 3,1加上1168就能访问到具体的语句,被称为相对编址,而上图没有采用,而是采用的绝对地址,1168 -> 116c,直接访问116c不需加上偏移量,被称为绝对编址,这种采用绝对编制范围 全0 ~ 全F,也可以说是逻辑地址(虚拟地址),这个文件里面的地址都是采用ELF格式进行编制的,有自己的固定格式。
2. 虚拟地址空间可以划分各个不同的区域,文件经过编译后生成的汇编文件通过ELF格式划分出不同的各个区域,并通过加载器进行扫描,得出各个区域的起始和结束地址。
2. 可执行文件加载
1. 程序加载是先创建内核数据结构还是先加载可执行文件?
先创建内核数据结构,并构建虚拟地址空间(mm_struct),也就是一个结构体,每个区域开始和结束用start,end来标识,那么怎么初始化?
操作系统能直接分配代码段和数据段的虚拟地址吗?假设一个函数占10字节,一个占100字节,操作系统怎么知道?只有可执行文件自己知道。
通过读取磁盘上的文件,通过ELF+加载器得到每个区域的起始地址和结束地址,在由操作系统进行映射到虚拟地址空间代码段,所以虚拟地址空间不是操作系统独有的,是由:操作系统 + 可执行文件 + 加载器 + 编译器。
2. 加载到内存
1. 虚拟地址已经映射了可执行文件的各个区域的起始和结束地址了,但想运行程序,首先要找到main函数的起始地址,所以在可执行文件加载前通过加载器扫描每个区域,也能扫描到mian函数的起始地址,在放到CPU内部的PC寄存器里,表示当前执行的指令的下一跳地址。
2. 加载前与给虚拟地址进行初始化代码段,数据段,加载到内存分配物理地址,并和原来初始化后的区域构建映射关系,通过页表,再有CPU执行PC指向的地址,进行页表查表到内存对应的程序。
2. 动态库加载
1. 上面说了可执行文件的加载,下面来看看动态库是如何加载和虚拟地址关联起来的。
2. 动态库加载和可执行文件加载类似,通过加载器扫描到每个区域的起始和结束地址,然后把库的起始地址映射到堆栈之间的共享区构建映射,在通过距离库的起始地址的偏移量+距离映射了的虚拟地址的偏移量,在通过查页表就能访问到内存中的方法了。
3. 动态库加载到内存,他的地址是不变的,不管虚拟地址是否变化,最终映射到的库的起始地址是不变的。
4. 内存中有很多动态库被使用,那么势必也需要维护起来,所以每个程序需要的动态库,首先去内存中进行查找,找不到就去查磁盘在加载到内存中。
相关文章:

动静态库--
目录 一 静态库 1. 创建静态库 2. 使用静态库 2.1 第一种 2.2 第二种 二 动态库 1. 创建动态库 2. 使用动态库 三 静态库 VS 动态库 四 动态库加载 1. 可执行文件加载 2. 动态库加载 一 静态库 Linux静态库:.a结尾 Windows静态库:.lib结尾…...
【检索增强生成(RAG)全解析】从理论到工业级实践
目录 🌟 前言🏗️ 技术背景与价值🩹 当前技术痛点🛠️ 解决方案概述👥 目标读者说明 🧠 一、技术原理剖析📊 核心架构图解💡 核心工作流程🔧 关键技术模块⚖️ 技术选型对…...

git clone时出现无法访问的问题
git clone时出现无法访问的问题 问题: 由于我的git之前设置了代理,然后在这次克隆时又没有打开代理 解决方案: 1、如果不需要代理,直接取消 Git 的代理设置: git config --global --unset http.proxy git config --gl…...
Lesson 22 A glass envelope
Lesson 22 A glass envelope 词汇 dream v. 做梦,梦想 n. 梦 用法:1. have a dream 做梦 2. have a good / sweet dream 做个好梦 [口语晚安] 3. dream about 人/物 梦到…… 4. dream that 句子 梦到…… 例句:他昨晚…...

文件系统·linux
目录 磁盘简介 Ext文件系统 块 分区 分组 inode 再谈inode 路径解析 路径缓存 再再看inode 挂载 小知识 磁盘简介 磁盘:一个机械设备,用于储存数据。 未被打开的文件都是存在磁盘上的,被打开的加载到内存中。 扇区:是…...

【Matlab】雷达图/蛛网图
文章目录 一、简介二、安装三、示例四、所有参数说明 一、简介 雷达图(Radar Chart)又称蛛网图(Spider Chart)是一种常见的多维数据可视化手段,能够直观地对比多个指标并揭示其整体分布特征。 雷达图以中心点为原点&…...
【信息系统项目管理师】第24章:法律法规与标准规范 - 27个经典题目及详解
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 【第1题】【第2题】【第3题】【第4题】【第5题】【第6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16题】【第17题】【第18题】【第19题】【第20题】【第…...

使用JProfiler进行Java应用性能分析
文章目录 一、基本概念 二、Windows系统中JProfiler的安装 1、下载exe文件 2、安装JProfiler 三、JProfiler的破解 四、IDEA中配置JProfiler 1、安装JProfiler插件 2、关联本地磁盘中JProfiler软件的执行文件 3、IDEA中启动JProfiler 五、监控本地主机中的Java应用 …...

遥感解译项目Land-Cover-Semantic-Segmentation-PyTorch之一推理模型
文章目录 效果项目下载项目安装安装步骤1、安装环境2、新建虚拟环境和安装依赖测试模型效果效果 项目下载 项目地址 https://github.com/souvikmajumder26/Land-Cover-Semantic-Segmentation-PyTorch 可以直接通过git下载 git clone https://github.com/souvikmajumder26/Lan…...
最大似然估计(Maximum Likelihood Estimation, MLE)详解
一、定义 最大似然估计 是一种参数估计方法,其核心思想是: 选择能使观测数据出现概率最大的参数值作为估计值。 具体来说,假设数据 D x 1 , x 2 , … , x n D{x_1,x_2,…,x_n} Dx1,x2,…,xn独立且服从某个概率分布 P ( x ∣ θ ) P(…...
【单片机】如何产生负电压?
以下是对知乎文章《单片机中常用的负电压是这样产生的!》的解析与总结,结合电路原理、应用场景及讨论要点展开: 一、负电压产生的核心原理 负电压本质是相对于参考地(GND)的电势差为负值,需通过电源或储能…...
Java 8 Stream 流操作全解析
文章目录 **一、Stream 流简介****二、Stream 流核心操作****1. 创建 Stream****2. 中间操作(Intermediate Operations)****filter(Predicate<T>):过滤数据****1. 简单条件过滤****2. 多条件组合****3. 过滤对象集合****4. 过滤 null 值…...
java线程中断的艺术
文章目录 引言java中的中断何时触发中断阻塞如何响应中断中断的一些实践基于标识取消任务如何处理阻塞式的中断合理的中断策略时刻保留中断的状态超时任务取消的最优解处理系统层面阻塞IO小结参考引言 我们通过并发编程提升了系统的吞吐量,特定场景下我们希望并发的线程能够及…...
【信息系统项目管理师】一文掌握高项常考题型-项目进度类计算
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 一、进度类计算的基本概念1.1 前导图法1.2 箭线图法1.3 时标网络图1.4 确定依赖关系1.5 提前量与滞后量1.6 关键路径法1.7 总浮动时间1.8 自由浮动时间1.9 关键链法1.10 资源优化技术1.11 进度压缩二、基本公式…...
HarmonyOS 鸿蒙应用开发基础:转换整个PDF文档为图片功能
在许多应用场景中,将PDF文档的每一页转换为单独的图片文件是非常有帮助的。这可以用于文档的分享、扫描文档的电子化存档、或者进行进一步的文字识别处理等。本文将介绍如何使用华为HarmonyOS提供的PDF处理服务将整个PDF文档转换为图片,并将这些图片存放…...
Flask-SQLAlchemy核心概念:模型类与数据库表、类属性与表字段、外键与关系映射
前置阅读,关于Flask-SQLAlchemy支持哪些数据库及基本配置,链接:Flask-SQLAlchemy_数据库配置 摘要 本文以一段典型的 SQLAlchemy 代码示例为引入,阐述以下核心概念: 模型类(Model Class) ↔ 数…...
刷题 | 牛客 - js中等题-下(更ing)30/54知识点解答
知识点汇总: 数组: Array.prototype.pop():从数组末尾删除一个元素,并返回这个元素。 Array.prototype.shift():从数组开头删除一个元素,并返回这个元素。 array.reverse():将数组元素反转顺…...
RAM(随机存取存储器)的通俗解释及其在路由器中的作用
RAM(随机存取存储器)的通俗解释及其在路由器中的作用 一、RAM是什么? RAM(Random Access Memory) 就像餐厅的“临时工作台”: 核心作用:临时存储正在处理的任务(如厨师同时处理多道…...

六、【前端启航篇】Vue3 项目初始化与基础布局:搭建美观易用的管理界面骨架
【前端启航篇】Vue3 项目初始化与基础布局:搭建美观易用的管理界面骨架 前言技术选型回顾与准备准备工作第一步:进入前端项目并安装 Element Plus第二步:在 Vue3 项目中引入并配置 Element Plus第三步:设计基础页面布局组件第四步…...
【项目需求分析文档】:在线音乐播放器(Online-Music)
1. 用户管理模块 1.1 注册功能 功能描述 提供注册页面,包含用户名、密码输入框及提交按钮。用户名需唯一性校验,密码使用 BCrypt 加密算法存储。注册成功后自动跳转至登录页面。 1.2 登录功能 功能描述 提供登录页面,包含用户名、密码输入…...

C++ 前缀和数组
一. 一维数组前缀和 1.1. 定义 前缀和算法通过预处理数组,计算从起始位置到每个位置的和,生成一个新的数组(前缀和数组)。利用该数组,可以快速计算任意区间的和,快速求出数组中某一段连续区间的和。 1.2. …...
PHP 实现通用数组字段过滤函数:灵活去除或保留指定 Key
PHP 实现数组去除或保留指定字段的通用函数详解 一、文章标题 《PHP 实现通用数组字段过滤函数:灵活去除或保留指定 Key》 二、摘要 在实际开发中,我们经常需要对数组进行字段级别的操作,例如从一个数组中删除某些敏感字段(如密码、token),或者只保留特定字段用于接口…...
NACOS2.3.0开启鉴权登录
环境 名称版本nacos2.3.0(Linux)java java version "17.0.14" 2025-01-21 LTS # # Copyright 1999-2021 Alibaba Group Holding Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use thi…...

细胞冻存的注意事项,细胞冻存试剂有哪些品牌推荐
细胞冻存的原理 细胞冻存的基本原理是利用低温环境抑制细胞的新陈代谢,使细胞进入一种“休眠”状态。在低温条件下,细胞的生物活动几乎停止,从而实现长期保存。然而,细胞在冷冻过程中可能会因为细胞内外水分结冰形成冰晶而受损。…...

快速上手Linux火墙管理
实验网络环境: 主机IP网络f1192.168.42.129/24NATf2(双网卡) 192.168.42.128/24 192.168.127.20/24 NAT HOST-NOLY f3192.168.127.30/24HOST-ONLY 一、iptables服务 1.启用iptables服务 2.语法格式及常用参数 语法格式:参数&…...

[创业之路-375]:企业战略管理案例分析 - 华为科技巨擘的崛起:重构全球数字化底座的超级生命体
在人类文明从工业时代(机械、电气、自动化)迈向数字智能(硬件、软件、算法、虚拟、智能)时代的临界点上,一家中国企业正以令人震撼的姿态重塑全球科技版图。从通信网络的底层架构到智能终端的生态闭环,从芯…...
【paddle】常见的数学运算
根据提供的 PaddlePaddle 函数列表,我们可以将它们按照数学运算、逻辑运算、三角函数、特殊函数、统计函数、张量操作和其他操作等类型进行分类。以下是根据函数功能进行的分类: 取整运算 Rounding functions 代码描述round(x)距离 x 最近的整数floor(…...

AI基础知识(05):模型提示词、核心设计、高阶应用、效果增强
目录 一、核心设计原则 二、高阶应用场景 三、突破性技巧 以下是针对DeepSeek模型的提示词设计思路及典型应用场景示例,帮助挖掘其潜在能力: 一、核心设计原则 1. 需求明确化:用「角色定位任务目标输出格式」明确边界 例:作为历…...
分布式事务之Seata
概述 Seata有四种模式 AT模式:无侵入式的分布式事务解决方案,适合不希望对业务进行改造的场景,但由于需要添加全局事务锁,对影响高并发系统的性能。该模式主要关注多DB访问的数据一致性,也包括多服务下的多DB数据访问…...

推测解码算法在 MTT GPU 的应用实践
前言 目前主流的大模型自回归解码每一步都只生成一个token, 尽管kv cache等技术可以提升解码的效率,但是单个样本的解码速度依然受限于访存瓶颈,即模型需要频繁从内存中读取和写入数据,此时GPU的利用率有限。为了解决这种问题,…...