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,一经查实,立即删除!

相关文章

第2章 数据存储篇

目录 2.1 MongoDB&#xff1a;面向文档的灵活存储 2.1.1 MongoDB基础与架构 2.1.1.1基本概念 2.1.1.2MongoDB安装与配置 1&#xff09;安装MongoDB-Linux安装示例&#xff08;以Ubuntu为例&#xff09; 2&#xff09;更新包列表并安装MongoDB 3&#xff09;启动MongoDB服…

利用OPT算法解决最短访问次数问题

一、题目 数据库缓存&#xff0c;模拟访问规则如下&#xff1a; 当查询值在缓存中&#xff0c;直接访问缓存&#xff0c;不访问数据库。否则&#xff0c;访问数据库&#xff0c;并将值放入缓存。 若缓存已满&#xff0c;则必须删除一个缓存。 给定缓存大小和训练数据&#xff…

对代理模式和动态代理以及AOP的一些理解

代理模式&#xff1a; 代理模式&#xff0c;也叫做静态代理&#xff0c;是一种结构型设计模式&#xff0c;它为其他对象提供了一种代理&#xff0c;以控制对这个对象的访问。 代理模式可以在不修改原有类的情况下&#xff0c;对其功能进行扩展&#xff0c;编译时就确定了代理…

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

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

leetcode每日一练:顺序表OJ题

第一题&#xff1a;移除元素 题目要求&#xff1a;给一个数组nums和一个值val&#xff0c;你需要 原地 移除所有所有数值等于val的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用0(1)的额外空间并 原地 修改输入数组。 元素的顺序…

【Tools】AIGC:人工智能生成内容的新时代

那年夏天我和你躲在 这一大片宁静的海 直到后来我们都还在 对这个世界充满期待 今年冬天你已经不在 我的心空出了一块 很高兴遇见你 让我终究明白 回忆比真实精彩 &#x1f3b5; 王心凌《那年夏天宁静的海》 随着人工智能&#xff08;AI&#xff09;技术的…

三生随记——午夜咖啡馆

在城市的边缘&#xff0c;隐藏着一间古老的咖啡馆——“午夜咖啡馆”。它的外观不起眼&#xff0c;却总能在夜晚吸引那些寻找安宁或寻求刺激的顾客。据说&#xff0c;咖啡馆的老板是一位年长的绅士&#xff0c;他的脸上总是挂着神秘莫测的微笑。 艾米是一名作家&#xff0c;常常…

基于weixin小程序智慧物业系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;员工管理&#xff0c;房屋管理&#xff0c;缴费管理&#xff0c;车位管理&#xff0c;报修管理 工作人员账号功能包括&#xff1a;系统首页&#xff0c;维…

使用electron打包Vue前端项目的详细流程

使用electron打包Vue前端项目的详细流程 需要更改的东西 路由模式的修改 # 修改前&#xff1a;url不带#mode: history# 修改后&#xff1a;url带#mode: hash全局修改Cookies为localStorage 由于打包成exe或deb这类可执行文件后&#xff0c;本地是没有 Cookies 全局搜索Cooki…

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已经应用到各类机器人项目开发中…

ORACLE 、达梦 数据库查询指定库指定表的索引信息

在Oracle数据库中&#xff0c;索引是一种关键的性能优化工具&#xff0c;通过它可以加快数据检索速度。在本文中&#xff0c;我们将深入探讨如何详细查询指定表的索引信息&#xff0c;以及如何利用系统视图和SQL查询来获取这些信息。 索引在数据库中的重要性 索引是一种数据结…

操作符详解(下) (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. 数组的相对排序 - 力…

代理ip匿名原理

代理IP匿名的原理基于代理服务器的工作方式。当用户使用代理服务器访问互联网时&#xff0c;请求数据会先发送到代理服务器&#xff0c;然后由代理服务器再向目标服务器发送请求。在这个过程中&#xff0c;代理服务器会将用户真实IP地址替换成代理服务器的IP地址&#xff0c;从…