Linux的库文件
目录
概述:
静态库:
静态库概述:
静态库的制作
共享库(动态库)
共享库概述
动态库制作
动态库临时生效
动态库长期生效
动态库的升级
位置无关代码
概述:
库文件一般就是编译好的二进制文件,用于在链接阶段同目标代码一块生成可执行文件,或者运行可执行文件的时候被加载,以遍调用库文件中的某段代码。
动态链接都是索引的.so文件,静态链接都是压缩打包的.a文件。
库文件和可执行文件相比:
- 相同点:两者都是编译好的二进制文件
- 不同点:库文件没法直接执行(直观上看,他的源代码中没有main函数,而只是一些函数模块的定义和实现,没有运行的入口主函数,所以库文件没法直接执行)。
我们的程序开发,无论是运行的时候,还是编译,链接的时候,一般都需要借助一些库来实现他们的功能,而很少直接通过程序的源代码生成完全独立的可执行文件。
静态库:
静态库概述:
静态库实际上就是一些目标文件的(一般是以.o结尾)的集合,静态库一般是以.a结尾,只用于链接生成可执行文件阶段。
具体来说,以c程序为例子,一般我们编译程序源代码的时候过程大致是:
- 以.c为后缀的源文件经过编译生成.o文件的目标文件
- 以.o为后缀的目标文件经过链接生成最终的可执行文件。
我们可以在链接的时候直接链接.o的目标文件,也可以将这些.o文件打包集中起来,统一链接,而生成的打包集成了所有.o文件,也就是静态库。
静态库只在程序连接的时候时候,连接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中,一旦链接完成生成可执行文件之后,执行程序的时候就不再需要静态库了。
由于每一个静态库的应用程序都是需要拷贝所用到的函数的代码,所以静态库链接生成可执行文件会比较大,多个程序运行的时候占用的内存空间比较大,(每个程序在内存中都有一份复制的静态库代码),但是由于运行的时候不用从外部动态加载额外的库了,速度会比共享库快。
静态库的制作
实例:假设在实际工作中设计了两个算法,但是需要卖给其他公司使用,为了保护公司的知识产权是不能将源代码交给其他公司的,这样我们可以将两个算法封装或者打包到一个静态库中。
假设实现这两个算法的函数为func1()和func()2。
新建一个头文件hello.h,在hello.h中对两个函数进行声明:
编写一个简单的程序“hello.c”
将hello.c编译生成.o文件
gcc -c hello.c -o hello.o
使用ar命令(ar是archive的意思)将hello.o文件打包成一个静态库文件libhello.a
ar rcs libhello.a hello.o
注意:
- 如果需要将多个.o文件打包成文件库,则在命令行后边填写所有.o文件的名字即可
- 生成的库的名字必须是libxxx.a格式(注意:这里是尽量最好使用lib开头的格式,因为其他格式的编译方式是不一样的)
编译参数:<rcs>
r:表明将模块加入到静态库中,c表示创建静态库,s表示产生索引
使用nm命令查看库文件中包含的符号:nm libhello.a
使用 ar -t 命令查看静态库是由那些.o文件组成的:ar -t libhello.a
编写一个带有主函数的程序main.c,并且在main.c中调用静态库中的func1和func2函数:
现在所有文件下都在同一个目录下,没法直接体现出来静态库的作用。
在IO_file_test目录下新建一个static_lib_test目录进行测试将文件移动到下边设备树结构。(这里是一个比较常用的目录结构,但是为了方便测试三个文件都放在一个文件目录下即可)
解释:
include目录下是.h文件
lib里边是链接的静态库文件
src里边是.c文件
编译:
gcc main.c -L../lib -lhello -I../include -o main
编译解释:
-L指向的是链接的静态库路径
-l(小L)是静态库的命称(去掉lib之后的)
-I(大i)链接存放.h文件的路径
编译现象:
在静态库的概述中会标红的地方提到了(一旦链接完成生成可执行文件之后,执行程序的时候就不再需要静态库了),所以这时删除掉libhello.a文件后程序仍然可以执行。
共享库(动态库)
共享库概述
共享库也叫做动态库。
静态库缺点:
- 内存消耗大;(假设一个静态库的大小为1M,当两千个程序都用到这库将消耗掉2G内存)
- 当静态库中的代码优化的时候,所有调用该静态库的程序需要重新编译,这样太过与麻烦。
动态库特点:
- 动态库在程序编译的时候并不会被链接到目标代码当中,而是在程序运行的时候才被载入。
- 不同的应用程序如果调用相同的库,那么在内存中里只需要有一份共享库的实例,规避了空间浪费问题。
- 动态库在程序运行的时候才能被载入,也解决了静态库对程序的更新,部署和发布页带来的麻烦。用户只需要更新动态库即可,增量更新。
动态库制作
参照静态库目录下创建三个文件如下:内容和静态库的也相同
编译链接生成.o文件
将编译好生成好的hello.o编译编译生成动态库:gcc -shared -fPIC -o libhello.so hello.o
注意:
- -shared:表明是使用的共享库
- -fPIC:表明生成与位置无关的代码、
- 动态库后缀为.so
- 动态库格式libxxx.so
- 如果还有其他链接的.o文件,直接在hello.o后边加上,用空格隔开
使用nm命令查看一个库文件中包含的符号: nm libhello.so
对照静态库测试目录制作动态库目录格式:
将上边共享库目录的文件对应拷贝到共享库测试目录里边如下:
进行编译:gcc main.c -L../lib -lhello -I../include -o main
但是如果直接执行的话,编译器会爆出一个错误。
错误的主要意思是在加载的时候打不开动态库文件,但是注意:动态库在在程序执行的时候会被加载。
这是因为在Linux中启动一个ELF格式的二进制可执行文件会自动启动和运行一个program loader(程序加载器:用来加载一些库)。对于Linux系统,这个loader的名字是ld-linux.so.X(X是版本号)。这个loader启动后会load所有的其他本程序的要使用的共享函数库。动态库与静态库不同,在执行文件的阶段需要加载动态库文件,而加载的动态库文件需要在指定位置或者添加在环境变量中,才能正确的加载动态库文件。
动态链接库的查找先后顺序:
- LD_LIBRARY_PATH环境变量中的路径
- /etc/ld.so.cache缓存文件
- /usr/lib和/lib
动态库临时生效
可以临时将libhello.so所在的路径追加到环境变量LD_LIBRARY_PATH中
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/IO_file_test/shared_lib_test/lib
冒号后边跟是自己的动态库路径。
修改完成之后我们可以使用echo $LD_LIBRARY_PATH查看环境变量被修改的值
注意: 在终端使用expert命令来修改当前环境变量的值,只是对当前会话临时生效,如果切换到一个新的会话窗口或者新的终端,关闭当前会话窗口都会失效。
动态库长期生效
- 修改系统启动配置文件,将export命令添加到启动文件当中
设置环境变量:
1.打开 vim ~/.bashrc 文件
2.在文件末尾添加一行
export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径(如果需要删除环境变量,需要在~/.bashrc中删除环境变量后,关掉终端,重新启动终端才能生效)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/IO_file_test/shared_lib_test/lib
3.重新加载配置文件 source ~/.bashrc
- 将动态库文件拷贝到/usr/lib或者/lib目录下(一般不采用这个种方式,因为这样会污染系统,并且不方便项目迁移)
- 修改/etc/ld.so.conf文件
动态库的升级
引入:
在实际工作当中,我们可能经常需要对动态库的板本进行升级,假如原来的库为libhello.so,那么升级完以后还需要保留每一个旧的板本,动态库的名字就不能重复,但是程序在加载的时候只加载libhello.so文件,解决:所以我们可以对每一个板本的动态库文件进行不同的命名,然后在新建立软链接,链接需要使用的实体库即可。
根据动态的命名规则,我们可以将动态库的第一个板本命名为:libhello.so.1.0.0,然后创建软连接
ln -s libhello.so.1.0.0 libhello.so
假设我们在原来的库上增加了某些接口我们可以将新库的版本名命名为libhello.so.1.1.0,删除原来的软连接文件,并重新创建软链接文件到该文件。
位置无关代码
位置无关代码(PIC:position-independent code),也被称为地址无关代码,是指源代码被编译成二进制文件(可以是执行文件也可以是某个库文件),编码方式也和位置(地址)无关。
程序在运行的时候是需要被加载到物理内存上运行的,但是操作系统为了方便每个进程进行内存管理,使用虚拟内存技术,每一个进程运行时都会得到4G的虚拟内存。这个虚拟内存可以认为每个进程任务自己认为自己有4G的空间,着只是每个进程认为的,但是实际上,在虚拟内存对应的物理内存上,可能只对应一点点的物理内存,实际用了多少内存,就会对应多少物理内存。
使用静态库和动态库编译生成的可执行文件在运行时候在内存上的加载方式:
如果使用了静态库编译可执行程序,每个函数在内存中的位置(地址)在编译完成以后就已经决定了。
但是共享库(动态库)是在可执行程序执行的时候加载进去的,动态编译后的函数的调用地址是自动计算出来的,这就是与位置无关的代码。
下边是找到的一个资料对位置无关代码的验证:
在64为机器上可以运行32位的指令。
相关文章:

Linux的库文件
目录 概述: 静态库: 静态库概述: 静态库的制作 共享库(动态库) 共享库概述 动态库制作 动态库临时生效 动态库长期生效 动态库的升级 位置无关代码 概述: 库文件一般就是编译好的二进制文件&…...

JAVA Web 学习(五)Nginx、RPC、JWT
十二、反向代理服务器——Nginx 支持热部署,几乎可以做到 7 * 24 小时不间断运行,即使运行几个月也不需要重新启动,还能在不间断服务的情况下对软件版本进行热更新。性能是 Nginx 最重要的考量,其占用内存少、并发能力强、能支持…...

Python编程的十大神奇依赖库
Python是一门广受欢迎的编程语言,其生态系统丰富多彩,拥有许多令人惊叹的依赖库,可以帮助程序员们在各种领域中创造出令人瞠目结舌的应用。在这篇文章中,我们将探讨Python编程的十大神奇依赖库,它们像魔法一样…...
Java类的继承
XHTMLMapper继承 XWPFDocumentVisitor: 由于endVisitTableCell是抽象方法,XHTMLMapper中必须要实现; existErr()子类是否重写都是自由的; public abstract class XWPFDocumentVisitor<T, O extends Options, E extends IXWPFM…...

【DC渗透系列】DC-4靶场
主机发现 arp-scan -l┌──(root㉿kali)-[~] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:6b:ed:27, IPv4: 192.168.100.251 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.100.1 00:50:56:c0:00:08 …...

开源软件全景解析:驱动技术创新与行业革新的力量
目录 什么是开源 开源的核心 开源软件的特点 为什么程序员应该拥抱开源 1.学习机会: 2.社区支持: 3.提高职业竞争力: 4.加速开发过程: 5.贡献和回馈: 开源软件的影响力 开源软件多元分析: 开源…...

目标检测及相关算法介绍
文章目录 目标检测介绍目标检测算法分类目标检测算法模型组成经典目标检测论文 目标检测介绍 目标检测是计算机视觉领域中的一项重要任务,旨在识别图像或视频中的特定对象的位置并将其与不同类别中的对象进行分类。与图像分类任务不同,目标检测不仅需要…...
跟着cherno手搓游戏引擎【20】混合(blend)
抽象: Renderer.h: #pragma once #include"RenderCommand.h" #include "OrthographicCamera.h" #include"Shader.h" namespace YOTO {class Renderer {public:static void Init();static void BeginScene(OrthographicCamera& …...

leetcode 3.无重复字符的最长字串(滑动窗口) (C++)DAY2
文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示…...
Android Build 依赖项
在项目中的Build.Gradle文件中dependencies代码块中添加指定依赖项。 有三种不同类型的依赖项 本地模块依赖项 implementation project(:mylibrary)这个mylibrary 必须在 settings.gradle 中使用的库名称相同 本地文件依赖项 implementation fileTree(dir: libs, include:…...

SpringMVC精简知识点
SpringMVC 数据格式化基本数据类型和字符串自动转换特殊数据类型和字符串自动转换 验证及国际化应用实例注意事项和使用细节注解的结合使用数据类型转换校验核心类-DatBinder取消某个属性的绑定中文乱码解决处理json和HttpMessageConverter<T>作业布置SpringMVC文件上传自…...
如何写好论文——(17)如何用批判性思维检阅文献
在写论文的时候,往往需要引用很多文献资料,作为论点来证明我们的研究目标是合理的。在讨论和结论中,我们往往也需要引用很多的文献资料和我们自己的研究结果放在一起,来证明我们的研究结果是有意义的。所以在选择文献资料的时候&a…...

git将项目的某次签入遴选(Cherry-Pick)另一个项目
需求:将项目Product,分支feature/platform,签入959294ce6b75ee48c5cb22c46d7398654628a896,遴选到项目BRP,分支dev 第一步:使用原签入生成patch文件(git format-patch -1 <commit_hash>&a…...

开源节点框架STNodeEditor使用
节点,一般都为树形Tree结构,如TreeNode,XmlNode。 树形结构有其关键属性Parent【父节点】,Children【子节点】 LinkedListNode为链表线性结构,有其关键属性Next【下一个】,Previous【上一个】,…...
算法每日一题: Nim游戏 | 找规律
哈哈,大家好,我是星恒,今天的每日一题真开心,连做了3天牢,终于ak了一道,太不容易了 这道题其实就是找规律,刚开始我还以为是动归,但是列举了不少例子之后,发现有自己直接…...

分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别
分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别 目录 分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现G…...
Dockerfile保留字
目录 一、Dockerfile保留字是什么? 二、Docker构建流程 1. 从基础镜像运行容器 2. 执行指令并修改容器 3. 提交新的镜像层 4. 基于新镜像运行新容器 5. 执行下一条指令 6. 循环执行指令 7. 所有指令执行完成 三、保留字 1. FROM 使用基础镜像作为起点 2.…...
Linux的7个运行级别
目录 1、有那7个运行级别? 2、那么如何查看运行级别呢? 3、那么我想临时切换运行级别? 4、那么我想修改配置文件中的运行级别呢? 1、有那7个运行级别? 0:停机状态。系统默认运行级别不能设置为0,否则系统不能正常启动&a…...
Linux期末总复习( 详解 )
文章目录 一、选择题二、填空题三、简答题四、操作题 一、选择题 1.在创建Linux分区时,一定要创建( D )两个分区 A. FAT/NTFS B. FAT/SWAP C. NTFS/SWAP D.SWAP/根分区 2.在Red Hat Linux 9 中,系统默认的…...

【Linux系统化学习】进程等待
目录 进程等待 进程等待的必要性 进程等待的方法 wait方法 等待一个进程(阻塞等待) waitpid方法 任意等待多个进程(阻塞等待) 父进程获取子进程的退出信息 非阻塞轮询等待 进程等待 进程等待的必要性 之前讲过,子进程退…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...