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.o
	ar -rc $@ $^

math.o:math.c
	gcc -c $^ -o $@

.PHONY:clean
clean:
	rm -f *.o *.a

.PHONY:mk
mk:
	mkdir -p lib_math/include
	mkdir -p lib_math/libmath
	cp *.a lib_math/libmath
	cp *.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.mfbz.cn/a/759542.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记——动态路由——OSPF(报头信息、报文信息、三张表)

六、OSPF协议的报头信息、报文信息、三张表 OSPF的协议报文在一个广播域内进行传递&#xff0c;是直接封装在IP报文中的&#xff0c;协议号为89。 OSPF本身5种类型&#xff1a;分别是Hello报文、DD报文、LSR报文、LSU报文、LSAck报文&#xff0c;各种不同类型的LSA其实只是包含…

Jedis、Lettuce、RedisTemplate连接中间件

jedis就像jdbc一样&#xff0c;用于两个端直接的连接。 1.创建Spring项目 这里不过多赘述... 2.导入连接工具jedis 在pom文件中导入jedis的依赖。 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version&…

第一周:李宏毅机器学习笔记

第一周学习周报 摘要一、机器学习基础理论1. 什么是机器学习&#xff1f;2. 机器学习“寻找”的函数有哪些类型&#xff1f;3. 机器学习中机器如何“寻找”函数&#xff1f;三步走3.1 第一步&#xff1a;设定函数的未知量&#xff08;Function with Unknown Parameters&#xf…

昇思25天学习打卡营第12天|ShuffleNet图像分类

1. 学习内容复盘 ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一样主要应用在移动端&#xff0c;所以模型的设计目标就是利用有限的计算资源来达到最好的模型精度。ShuffleNetV1的设计核心是引入了两种操作&a…

C++ 数据库MySQL 学习笔记(3) - 数据库操作

C 数据库MySQL 学习笔记(3) - 数据库操作 视图操作 视图是从一个或多个表中导出来的表&#xff0c;是一种虚拟存在的表。视图就像一个窗口&#xff0c;通过这个窗口可以看到系统专门提供的数据&#xff0c;这样用户可以不看整个数据库表中的数据&#xff0c;而只关心对自己有…

Chrome备份数据

Chrome备份数据 1、 导出谷歌浏览器里的历史记录 参考&#xff1a;https://blog.csdn.net/qq_32824605/article/details/127504219 在资源管理器中找到History文件&#xff0c;文件路径&#xff1a; C:\Users\你的电脑用户名\AppData\Local\Google\Chrome\User Data\Default …

【Linux】Linux系统配置,linux的交互方式

1.Linux系统环境安装 有三种方式 裸机安装或者双系统 -- 不推荐虚拟机安装 --- 不推荐云服务器/安装简单&#xff0c; 维护成本低——推荐&#xff0c; 未来学习效果好 我们借助云服务器 云服务器&#xff08;Elastic Compute Service&#xff0c;ECS&#xff09;的标准定义…

昇思25天学习打卡营第7天|网络构建

昇思25天学习打卡营第7天|网络构建 前言函数式自动微分函数与计算图微分函数与梯度计算Stop GradientAuxiliary data神经网络梯度计算 个人任务打卡&#xff08;读者请忽略&#xff09;个人理解与总结 前言 非常感谢华为昇思大模型平台和CSDN邀请体验昇思大模型&#xff01;从今…

基于SpringBoot的超市进销存系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架 工具&#xff1a;MyEclipse、Tomcat 系统展示 首页 首页界面图 个人中心 个人中心…

使用LabVIEW和示波器测试IGBT参数

使用LabVIEW和示波器测试绝缘栅双极型晶体管&#xff08;IGBT&#xff09;参数的综合解决方案。过程包括硬件设置、示波器和其他必要设备的配置&#xff0c;以及开发LabVIEW程序以自动化数据采集、过滤、关键参数计算和结果显示。该方法确保了IGBT测试的准确性、可靠性和高效性…

Python自动化运维 系统基础信息模块

1.系统信息的收集 系统信息的收集&#xff0c;对于服务质量的把控&#xff0c;服务的监控等来说是非常重要的组成部分&#xff0c;甚至是核心的基础支撑部分。我们可以通过大量的核心指标数据&#xff0c;结合对应的检测体系&#xff0c;快速的发现异常现象的苗头&#xff0c;进…

5.How Fast Should You Be When Learning?(你应该用多快的速度学习? (二))

Are you failing to reach an ideal or you dont know what the ideal is? 你是否没有达到理想状态&#xff0c;或者不知道理想状态是什么? A lot of learing involves having a mental representation of what the ideal performance ought to be, a method or approach t…

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

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

维卡币(OneCoin)是投资骗局!中国成维卡币传销重灾区,信徒们醒醒吧!创始人被通缉,生死不明!

维卡币(英文名&#xff1a;OneCoin)是一个隐藏在加密货币外表下的庞氏骗局&#xff0c;因传销诈骗和违法吸金被起诉&#xff0c;受害者遍布全球。它的创始人Ruja Ignatova因欺骗和洗钱被列为通缉嫌疑人&#xff0c;成为全球最大金融诈骗案件之一的逃犯&#xff0c;目前美国政府…

ELK企业级实战

一、Elstic stack在企业的常⻅架构 https://www.bilibili.com/video/BV1x94y1674x/?buvidXY705117E90F73A790429C9CFBD5F70F22168&vd_source939ea718db29535a3847d861e5fe37ef ELK 解决取得问题 痛点1: ⽣产出现故障后&#xff0c;运维需要不停的查看各种不同的⽇志进⾏…

Flutter 入门与实战(十一):底部弹窗ModelBottomSheet详解

这是我参与更文挑战的第6天,活动详情查看: 更文挑战 在实际开发过程中,经常会用到底部弹窗来进行快捷操作,例如选择一个选项,选择下一步操作等等。在 Flutter 中提供了一个 showModelBottomSheet 方法用于弹出底部弹窗,本篇介绍如何使用底部弹窗。 实现效果 最终实现效果…

【使用sudo apt-get出现报错】——无法获得锁 /var/lib/dpkg/lock-open(11:资 源暂时不可用) ,是否有其他进程正占用它?

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、ubuntu中进程正在被占用1. 问题描述2. 原因分析3. 解决 总结 前言 一、ubuntu中进程正在被占用 1. 问题描述 在Ubuntu中&#xff0c;使用终端时输入带有…

50-3 内网信息收集 - 域环境搭建

搭建准备: 在搭建准备阶段,我们需要准备三台 Windows 虚拟机:Windows Server 2012、Windows 7 和 Windows Server 2008。接下来,我们将配置 Windows Server 2012 作为域控制器,而 Windows 7 和 Windows Server 2008 将作为成员机加入域。建议保持这三台虚拟机的内存不超过…

Servlet_Web小结

1.web开发概述 什么是服务器&#xff1f; 解释一&#xff1a;服务器就是一款软件,可以向其发送请求,服务器会做出一个响应. 可以在服务器中部署文件,让他人访问 解释二&#xff1a;也可以把运行服务器软件的计算机也可以称为服务器。 web开发&#xff1a; 指的是从网页中向后…

C++学习全教程(Day2)

一、数组 在程序中为了处理方便,常常需要把具有相同类型的数据对象按有序的形式排列起来&#xff0c;形成“一组”数据&#xff0c;这就是“数组”(array&#xff09; 数组中的数据&#xff0c;在内存中是连续存放的&#xff0c;每个元素占据相同大小的空间&#xff0c;就像排…