Linux_动、静态库

目录

一、静态库

1、静态库的概念 

2、制作静态库的指令

3、制作静态库

4、链接静态库

二、动态库 

1、动态库的概念

2、制作动态库的指令 

3、制作动态库 

4、链接动态库

5、动态库的加载 

三、静态库与动态库的区别

结语


前言:

        在Linux下大部分程序进行编译时,都会接触静态库或动态库,因此动静态库在Linux下是个很重要的概念,他们都是文件,其中静态库后缀是.a,动态库后缀是.so。动静态库里保存的是函数的具体方法,他们的不同点在于链接阶段时,静态库会把方法直接拷贝到程序中,而动态库会把方法加载到内存中,并且在可执行程序中记录了动态库在内存的地址,以便在运行时能够让可执行程序从内存中定位具体方法。

一、静态库

1、静态库的概念 

         静态库是由.o文件打包而来的,因此库里面保存的是二进制,程序链接静态库时,会将静态库里的方法拷贝至可执行程序,所以使用静态库会导致可执行程序变大,则会占用内存和磁盘的空间,但是该可执行程序运行时不再需要链接外部的库,程序的独立性较强。

2、制作静态库的指令

        静态库的命名方式必须以lib为前缀,以.a为后缀,使用指令生成静态库:

ar -rc libxxx.a xxx.o
//将xxx.o文件打包成静态库

         这里.o文件可以是多个,即可以将多个.o文件打包成静态库,由于静态库存放的是函数方法,所以要先有一个.c源文件存放函数实现,以及有一个.h文件存放函数声明,代码如下:

//math.h
#pragma once
#include<stdio.h>int Add1(int x,int y);//math.c
#include"math.h"int Add1(int x,int y)
{return x+y;
}

        并且在主函数中调用函数add:

//test.c
#include"math.h"int main()
{int sum = Add1(5,3);printf("sum=%d\n",sum);return 0;
}

        先测试以上代码是否正确:

        从结果看以上代码的逻辑没问题。

3、制作静态库

        写一个makefile,便于完成静态库的制作,makefile的具体工作:生成math.c的.o文件,然后打包.o文件生成静态库文件,并且创建一个目录,将.h和.a文件打包到该目录下,这样直接将整个目录给到外部使用,.h文件主要是让用户知道该静态库有哪些方法可以被调用,类似说明书的作用。

        makefile代码如下:

libmath.a:math.oar -rc $@ $^math.o:math.cgcc -c $^ -o $@.PHONY:clean
clean:rm -f *.o *.a.PHONY:mk
mk:mkdir -p lib_math/includemkdir -p lib_math/libmathcp *.a lib_math/libmathcp *.h lib_math/include

        测试结果如下:

4、链接静态库

二、动态库 

        正常编译一个程序时,用的指令是gcc xxx.c -o a.out,该指令默认让编译器和链接器到指定的路径下去寻找.so(动态库)文件,给指令加上-static后就去指定的路径下寻找.a(静态库)文件,共同点是寻找的路径是被设置好的(寻找#include的头文件也是如此,系统默认到指定路径下找头文件),很明显上面自己制作的静态库是在我们自己创建的目录下,所以需要对默认指令进行路径指定化,并且寻找头文件math.h也需要指定路径,操作如下:

gcc test.c -I ./lib_math/include -L ./lib_math/libmath -lmath

        测试结果:

        这里要注意两个细节:

1、-L的时候要精确到.a文件,-I的时候不需要精确到具体的.h文件是因为代码中已经用include包了那个.h文件。

2、链接.a文件的时候用-l并且后面紧跟库的名称,并且该库的名称要去掉前缀和后缀,即只留下和#include<>尖括号中一样的名称。

        运行a.out:

        发现运行结果正确,并且细心观察此时a.out文件内容较大,是因为静态库在程序链接时会将对应方法拷贝到程序中形成最终的可执行程序。

1、动态库的概念

         动态库也是由.o文件打包而来的,生成.o文件后对.o文件进行加工得到动态库,跟静态库不同的是,他的文件后缀是.so,并且动态库类似可执行程序(静态库是一个文件),因为他需要被加载到内存中以便让多个进程共用其方法,所以他不必拷贝到程序中节省了内存和磁盘的空间。

2、制作动态库的指令 

         首先使用gcc编译指令形成.o文件,只不过该指令中需要加上选项-fPIC,指令如下:

gcc -fPIC -c xxx.c
//执行该指令得到一个xxx.o文件
//fPIC:产生位置无关码,即偏移量
//因为动态库加载到内存中是不固定地址的,
//所以需要根据偏移量找到在进程地址空间中加载的动态库的方法位置,即动态库的起始地址+偏移量。

         接着对生成的.o文件进行打包即可生成动态库,和制作静态库不一样,制作动态库的指令也是gcc,只不过需要加上-shared选项,并且对动态库的命名方式需加前缀lib和后缀.so

gcc -shared -o libxxx.so xxx.o
//执行该指令得到一个xxx.so的动态库

3、制作动态库 

         1、沿用上文的头文件、源文件,首先用math.c生成动态库所需的.o文件:

        2、打包.o文件形成动态库:

         3、和上述静态库一样的逻辑,将.h文件和.so文件放到一个目录下:

4、链接动态库

         因为编译的指令始终是gcc,所以链接动态库的指令和链接静态库是一样的,又因为是链接我们自己制作的库,所以需要用-I和-L来指定路径,并且连接指定库时要去掉前缀lib和后缀.so,链接指令如下:

gcc test.c -I ./lib_math/include -L ./lib_math/libmath -lmath

        测试结果:


         从结果看果然生成了a.out,这一切看起来都很顺序,然后运行a.out后发现: 

        报错的原因是找不到动态库,虽然在gcc指令中指定了库的路径,但是这只是让编译器在编译的时候可以找到库,然而动态库本身需要被加载到内存中,所以动态库也需要让加载器知道动态库的路径,而加载器默认会去/lib64这个目录下查找,所以我们需要通过某种方式让我们的的动态库出现在这个目录下

        用软链接的方式: 

        发现结果是可行的,因此得出一个结论:连接动态库还需要将库文件安装到系统下,并且动态链接后形成的可执行程序确实比静态链接形成的可执行程序要小,原因就是程序中用到的动态库方法被加载到内存中的共享区供所有进程使用,并没有直接拷贝到程序中。 

5、动态库的加载 

        从上文可以知道,动态库会被加载到内存中,可执行程序会保存动态库在内存中的地址,以便在程序运行时能够根据该地址找到具体的方法,动态库只会被加载一份至物理内存中,只不过多个进程的共享区会指向同一个物理内存,这样一来就无需加载相同的库文件至内存中。动态库和内存以及进程的关系示意图如下:

三、静态库与动态库的区别

1、静态库在链接时会把调用方法拷贝到程序中,从而形成最终的可执行程序。动态库不会直接拷贝,而是在程序运行时加载到内存中,让程序动态调用。

2、静态库导致可执行程序变大。而动态库不会让可执行程序变大。

3、制作静态库的指令是ar -ra。制作动态库的指令是gcc -shared -o,并且需用-fPIC形成.o文件。

4、使用静态库时无需将静态库放到系统路径下。使用动态库时需要将动态库放到系统路径下。

5、静态库独立性强,依赖性低。动态库独立性低,依赖性强。

结语

         以上就是关于Linux的动静态库讲解,只要我们的程序用到了第三方库那么就离不开动静态库,因此大部分的程序都要和动静态库打上交道,动静态库最核心的点在于静态库会加载到程序中,而动态库会加载到内存中,通过这两点再向外拓展。

        最后如果本文有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!!  

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

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

相关文章

【JavaEE】多线程代码案例(1)

&#x1f38f;&#x1f38f;&#x1f38f;个人主页&#x1f38f;&#x1f38f;&#x1f38f; &#x1f38f;&#x1f38f;&#x1f38f;JavaEE专栏&#x1f38f;&#x1f38f;&#x1f38f; &#x1f38f;&#x1f38f;&#x1f38f;上一篇文章&#xff1a;多线程&#xff08;2…

Android Studio环境搭建(4.03)和报错解决记录

1.本地SDK包导入 安装好IDE以及下好SDK包后&#xff0c;先不要管IDE的引导配置&#xff0c;直接新建一个新工程&#xff0c;进到开发界面。 SDK路径配置&#xff1a;File---->>Other Settings---->>Default Project Structure 拷贝你SDK解压的路径来这&#xff0c;…

ros笔记01--初次体验ros2

ros笔记01--初次体验ros2 介绍安装ros2测试验证ros2说明 介绍 机器人操作系统(ROS)是一组用于构建机器人应用程序的软件库和工具。从驱动程序和最先进的算法到强大的开发者工具&#xff0c;ROS拥有我们下一个机器人项目所需的开源工具。 当前ros已经应用到各类机器人项目开发中…

操作符详解(下) (C语言)

操作符详解下 操作符的属性1.优先级2.结合级 表达式求值1.整型提升2.如何进行整形提升呢&#xff1f;3.算术转换4.问题表达式解析 操作符的属性 C语言的操作符有2个重要的属性&#xff1a;优先级、结合性&#xff0c;这两个属性决定了表达式求值的计算顺序。 1.优先级 优先级…

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题&#xff1a;第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

RabbitMQ 进程内流控(Flow Control) 源码解析

1. 概述 1.1 为什么要流控&#xff1f; 流控主要是为了防止生产者生产消息速度过快&#xff0c;超过 Broker 可以处理的速度。这时需要暂时限制生产者的生产速度&#xff0c;让 Broker 的处理能够跟上生产速度。 Erlang进程之间不共享内存&#xff0c;每个进程都有自己的进程邮…

42.HOOK引擎核心代码

上一个内容&#xff1a;41.HOOK引擎设计原理 以 40.设计HOOK引擎的好处 它的代码为基础进行修改 主要做的是读写寄存器 效果图 添加一个类 htdHook.h文件中的实现 #pragma once class htdHook { public:htdHook(); };htdHook.cpp文件中的实现&#xff1a; #include "…

独辟蹊径:我是如何用Java自创一套工作流引擎的(下)

作者&#xff1a;后端小肥肠 创作不易&#xff0c;未经允许严禁转载。 姊妹篇&#xff1a;独辟蹊径&#xff1a;我是如何用Java自创一套工作流引擎的&#xff08;上&#xff09;_java工作流引擎-CSDN博客 1. 前言 在上一篇博客中&#xff0c;我们详细介绍了如何利用Java语言从…

LC437.路径总和Ⅲ、LC207.课程表

给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点到子节点&am…

【每日刷题】Day77

【每日刷题】Day77 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. LCR 159. 库存管理 III - 力扣&#xff08;LeetCode&#xff09; 2. LCR 075. 数组的相对排序 - 力…

Linux——passwd文件,grep,cut

/etc/passwd文件含义 作用 - 记录用户账户信息&#xff1a;共分为7段&#xff0c;使用冒号分割 含义 - 文件内容意义&#xff1a;账户名&#xff1a;密码代号x&#xff1a;UID&#xff1a;GID&#xff1a;注释&#xff1a;家目录&#xff1a;SHELL - 第7列/sbin/nologin&#x…

c++(三)

1. STL 1.1. 迭代器 迭代器是访问容器中元素的通用方法。如果使用迭代器&#xff0c;不同的容器&#xff0c;访问元素的方法是相同的&#xff1b;迭代器支持的基本操作&#xff1a;赋值&#xff08;&#xff09;、解引用&#xff08;*&#xff09;、比较&#xff08;和!&…

隐私计算实训营第二期第11讲组件介绍与自定义开发

首先给大家推荐一个博主的笔记&#xff1a;隐语课程学习笔记11- 组件介绍与自定义开发-CSDN博客 官方文档&#xff1a;隐语开放标准介绍 | 开放标准 v1.0.dev240328 | 隐语 SecretFlow 01 隐语开放标准 隐语开放标准是为隐私保护应用设计的协议栈。 目前&#xff0c;隐语开…

mysql8.0-学习

文章目录 mysql8.0基础知识-学习安装mysql_8.0登录mysql8.0的体系结构与管理体系结构图连接mysqlmysql8.0的 “新姿势” mysql的日常管理用户安全权限练习查看用户的权限回收:revoke角色 mysql的多种连接方式socket显示系统中当前运行的所有线程 tcp/ip客户端工具基于SSL的安全…

Wp-scan一键扫描wordpress网页(KALI工具系列三十二)

目录 1、KALI LINUX 简介 2、Wp-scan工具简介 3、信息收集 3.1 目标IP&#xff08;服务器) 3.2kali的IP 4、操作实例 4.1 基本扫描 4.2 扫描已知漏洞 4.3 扫描目标主题 4.4 列出用户 4.5 输出扫描文件 4.6 输出详细结果 5、总结 1、KALI LINUX 简介 Kali Linux 是一…

STM32CubeIDE使用标准库

以STM32F030为例使用标准库文件。 1、新建工程&#xff0c;选择需要使用配置的型号。 2、在工程选型中&#xff0c;选择新建空工程。 3、新建空工程 新建完成&#xff0c;系统只有main函数和启动文件.s有用。 4、启动文件 启动文件&#xff0c;同样是一个汇编文件&#xf…

【Matlab函数分析】imread从图形文件读取图像

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

如何利用AI生成可视化图表(统计图、流程图、思维导图……)免代码一键绘制图表

由于目前的AI生成图表工具存在以下几个方面的问题&#xff1a; 大多AI图表平台是纯英文&#xff0c;对国内用户来说不够友好&#xff1b;部分平台在生成图表前仍需选择图表类型、配置项&#xff0c;操作繁琐&#xff1b;他们仍需一份规整的数据表格&#xff0c;需要人为对数据…

软件框架(Framework)是什么?

可实例化的、部分完成的软件系统或子系统&#xff0c;它为一组系统或子系统定义了统一的体系结构(architecture)&#xff0c;并提供了构造系统的基本构造块(building blocks)&#xff0c;还为实现具体功能定义了扩展点(extending points)。 框架实现了体系结构级别的复用。 其…

系统工程与信息系统基础(上)

目录 系统工程 霍尔三维结构的三维&#xff1a; 切克兰德方法&#xff1a; 并行工程方法&#xff1a; 综合集成法&#xff1a; WSR系统方法&#xff1a; 系统工程生命周期阶段 探索性阶段 概念阶段 开发阶段 生产阶段 使用阶段 保障阶段 退役阶段 系统工程生命周…