Linux:动静态库

目录

一、软硬链接

1、软链接

2、硬链接

二、动态库和静态库

编写一个库

①静态库

使用静态库的方法

②动态库

使用动态库的方法

库存在的意义


一、软硬链接

软硬链接的本质区别就是:有无独立的inode

软链接有独立的inode,也就意味着软链接是一个独立的文件

硬链接没有独立的inode,即硬链接并不是一个独立的文件

ln -s是软链接的语法,不加-s就是硬链接

上图将soft.txt与testlink1软链接,将hard.txt与testlink2硬链接,通过ls -li(-i表示显示对应的inode值),可以看出进行软链接的soft.txt与testlink1的inode不同,而进行硬链接的hard.txt与testlink2的inode却是相同的,即表示硬链接没有独立的inode

1、软链接

软链接相当于Windows下的快捷方式,如下所示:

我们有一个文件夹test

test里还有个文件夹hello,hello里有个文件test.c,test.c经过gcc形成可执行文件test.exe,test.c文件内容如下:

如果在当前路径下,想运行这个test.exe这个可执行文件:

即使通过相对路径的方式运行,也是比较麻烦的,所以这时使用软链接:

将该路径下的test.exe与test/hello/下的test.exe建立软链接,这时如果想执行刚刚的可执行文件,只需运行test.exe即可:

所以软链接相当于Windows下的快捷方式

可以理解为:软链接的文件内容,是指向的文件对应的路径

unlink删掉软链接


2、硬链接

由于硬链接没有独立的inode,所以硬链接不是独立的文件,所以创建硬链接并不是真正的创建新文件,而是在指定的目录下,建立了文件名和指定inode的映射关系,也就是起别名

在ls -li时,我们可以发现这样一个属性:

这样的数字表示的就是硬链接数

例如我们上面将hard.txt与testlink2硬链接了,所以他们共同的这个硬链接数属性就是2:

而如果删除其中一个:

这时hard.txt的硬链接数就变为了1

所以当我们删除一个文件时,并不是删除文件的inode,而是将inode中包含的引用计数count即硬链接数--,直到引用计数为0,这个文件才真正的删除了


下面看下一个问题,分别创建一个目录dir和一个普通文件test.c:

为什么dir的硬链接数是2,而普通文件的硬链接数是1

其实很简单,当我们创建普通文件test.c时,创建出来后,test.c这个文件名映射到自己的inode,所以硬链接数为1

而目录dir,创建出来后,自己的目录名dir映射到自己的inode,这是其中一个;自己目录内部有一个  .  ,也与inode有对应的映射关系,这时第二个,因此目录的硬链接数默认为2

这也就是我们平时运行可执行文件时是./test.exe,前面的.也就是表示是在当前路径下


而如果我们在dir目录下,再创建一个dir1目录:

这时dir的硬链接数变为了3,这又是什么原因呢

其实也很简单,我们分别进入dir和dir1,都进行ls -lia,列出详细信息

可以发现dir中的 . 与dir1中的 .. 的inode都是790425,所以我们就清楚这里的第三个硬链接数就是来自dir1中的 .. 

因此也就能解释,为什么cd ..就是返回上一级路径,原因就是这里的..与上一级路径的inode是相同的,也就是当前路径的..就是上一级路径的别名,所以cd ..就是返回上一级路径

.和..就是下图所表示的关系:

因此如果我们继续在dir中创建目录,硬链接数也就会增加:

原本是3,再mkdir两个就变为5,经过上面讲解,就可以知道新增的2个就是dir2和dir3中的 .. ,所以通过这一点,我们以后观察目录的硬链接数数是多少,只需要-2(减去的是dir与dir中的.这两个对应关系),就是里面包含的目录数

所以上面的dir硬链接数是5,-2即包含的目录有三个,分别是dir1/2/3:


二、动态库和静态库

关于动静态库,我们前面的博客也提到过,Linux中,静态库是.a结尾,动态库是.so结尾 

下面要讲到的动静态库的制作和使用,都是为了后续更好的使用别人的库做准备

编写一个库

首先明确一点,库中不能有main函数,因为库是给别人用的,如果有main函数,别人也有main函数,就重复定义了

①静态库

首先有一个mklib的目录(制作库),里面有四个文件,分别是:

myadd.h、myadd.c、myshow.h、myshow.c

myadd.h

myadd.c

myshow.h

myshow.c

然后创建一个目录uselib(使用库),

里面有main.c,用于使用myshow和myadd

下面可以初步使用一下,首先将mkdir中的myadd.c和myshow.c变为.o文件:

然后将所有.o和.h文件都cp到uselib中,再将main.c也变为.o文件:

此时uselib中就有全部的.c和.h文件,这时生成可执行exe文件并运行:

是能够运行的


但是这种方式.o文件太多了,拷贝给别人使用时不方便,且编译时这些.o文件都需要打上去,万一不留神少打一个.o文件,就会出问题

所以我们可以把所有的.o打包,形成一个静态库

语法是:ar -rc [库名] .o文件 

ar是归档工具,是归档文件的缩写

-rc中r表示替换,c表示创建

库名:前缀必须是lib,后缀必须是.a

这里的libtest.a就是创建出来的静态库

为了方便,创建Makefile文件:

所以我们就可以make clean清除.o文件与静态库,make生成.o与静态库:

而发布库时,需要include目录和lib目录:

include目录,包含库的所有头文件

lib目录,包含对应的库文件

所以此时在我们的Makefile文件中新增内容:

此时make test,就会生成test的目录,里面有include和lib目录:


至此有了test目录,我们将该目录拷贝到uselib中去使用:

test就是别人的库,而main.c是我准备使用别人的库的main函数

使用静态库的方法

第一种方法:拷贝到库目录下:

头文件gcc的默认搜索路径是:/usr/include

库文件的默认搜索路径是: /lib64

所以将头文件与库文件拷贝到库目录下,编译时就能够找到它们了

将所有.h拷贝到/usr/include中:

这时/usr/include 下就有了myadd.h和myshow.h了

再将libtest.a拷贝到/usr/lib中:

这时/lib64中就有了libtest.a了

而自己写的库是属于第三方库

我们刚刚所写的库名字叫做libtest.a,所以我们gcc时必须表明需要链接的库名,前面加上-l,且将前缀lib和后缀.a都去掉就是库名,即test

生成了一个可执行文件a.out,运行a.out:

至此运行成功,成功使用了静态库libtest.a

我们刚刚的拷贝库到系统的默认路径下,就叫做库的安装

这第一种方法拷贝到库目录下,是不建议的,因为我们自己写的方法并不具有可靠性


第二种方法:直接使用静态库

如果我们直接gcc main.c,会报错:

告诉我们找不到myadd.h,因为默认在库中搜索,搜索不到再到当前路径搜索,而当前路径是uselib,里面并没有.h文件,.h文件在./test/include中,所以-I表示指定让头文件搜索的路径

这时报错找不到show和add函数,所以-L表示库文件的搜索路径,后面-l跟上特定路径下的库名

这时成功生成a.out可执行文件,./a.out运行成功

总结gcc main.c -I ./test/include -L ./test/lib -ltest

-I(大写)是头文件的搜索路径,-L是库文件的搜索路径-l(小写)加上特定路径下的库名


②动态库

动态库的四个函数内容不变,.h和.c也在mklib中,和上面静态库一样

形成的动态库的.o文件必须要加-fPIC选项,.o文件名称加个_d,与静态库保持区分:

而形成动态库,在gcc时需要加上-shared:

-o后面的libtest.so,lib是前缀,.so是后缀,中间的test是库名

此时就生成了libtest.so的动态库

此时了解如何生成的动态库后,就可以把这个过程也编入到Makefile中:

上面的.PHONY:all,是为了一次同时生成静态库和动态库

此时执行make:

可以发现同时生成了静态库和动态库

再执行make test,就会生成test的目录,里面有include和lib目录:


同样我们将该目录拷贝到uselib中去使用:

此时uselib中内容有:

此时动静态库都存在,编译器默认使用动态库:

使用了gcc main.c -I ./test/include -L ./test/lib -ltest,运行a.out时,提醒无法使用动态库,证明了上述结论,使用ldd a.out查看同样可以发现使用的是动态库:

而动静态库都存在时,我们如果想强行使用静态库,需要加上-static选项:

此时就能够执行a.out了

所以站在使用者的角度,得出以下结论:

如果我们只有静态库,gcc只能针对该库进行静态链接

如果动静态库同时存在,默认使用动态库

如果动静态库同时存在,我们加上-static选项可以强行使用静态库

-static的作用:改变默认优先使用动态库的原则,变为直接使用静态库的方案


使用动态库的方法

动态库同样可以像静态库那样,直接拷贝到库目录下,但是我们自己写的库不具有可靠性,所以并不建议这样做,所以这里就不举例这种方式了

第一种方法:添加库所在的位置到LD_LIBRARY_PATH中(临时方案)

LD_LIBRARY_PATH:库加载的搜索路径

系统在搜索库路径时,会在系统的lib64路径下搜素,找到动态库就会使用,如果没找到就终止,如果系统的lib64路径没找到,而LD_LIBRARY_PATH路径也设置了,那就可以在这个路径下搜索

原始的LD_LIBRARY_PATH有下面内容:

我们自己的动态库在这个路径:/home/fcy/lesson2/uselib/test/lib

所以执行:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/fcy/lesson2/uselib/test/lib

将该路径添加到LD_LIBRARY_PATH中,LD_LIBRARY_PATH=$LD_LIBRARY_PATH:是为了添加时不覆盖之前的内容,用冒号隔开

执行完后,再查看LD_LIBRARY_PATH,就发现刚刚动态库所在的路径被添加到LD_LIBRARY_PATH里面了

这时运行a.out就能成功运行了:

ldd查看a.out:

就会发现,可以查到我们自己的动态库libtest.so

但是这种方法,如果你把你的Xshell软件关了,重新打开一遍,刚刚做的工作就又失效了,所以这种方法只能作为临时方案


第二种方法:添加库所在的位置到/etc/ld.so.conf.d中(永久方案)

系统里有一个路径/etc/ld.so.conf.d,里面保存的是可以自定义配置搜索库路径的永久解决方案:

操作方法很简单,我们先在/etc/ld.so.conf.d里新创建一个普通文件tmp.conf,以.conf结尾(sudo创建)

然后将我们刚刚动态库所在的路径,sudo方式vim打开并粘贴进去:

sudo vim /etc/ld.so.conf.d/tmp.conf

sudo ldconfig,就是让配置文件生效,更新一下

然后运行a.out就能成功运行

ldd a.out也能查看能够找到动态库

 


第三种方法:软链接方案

在/lib64目录下,创建一个软链接,链接到我们的动态库路径下

这时执行a.out,就能成功执行了:

ldd a.out查看也能找到动态库:

找到的是lib64/libtest.so,而lib64/libtest.so是软链接,所以找到了动态库

不需要时再将这个软链接删掉即可,sudo unlink /lib64/libtest.so


库存在的意义

对于这些库,自然有他们存在的意义

对于使用者来说:

有了库,可以大大减少我们开发的周期,从而提高我们软件的质量

对于开发库的人员角度来说:

第一、使用者使用简单

第二、为了代码安全


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

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

相关文章

redis高可用---持久化

redis高可用 在集群当中有一个非常重要的指标,提供正常服务的时间的百分比(365天) 99.9%,redis高可用含义更广泛,支持服务是指标之一,数据容量扩展,数局的安全性。(容量、安全性) redis中实现高…

【HCSD大咖直播】亲授大厂面试秘诀【云驻共创】

同学们,毕业季是否找到了自己心仪的工作呢?是否了解大厂面试流程、要求以及技巧呢?华为云IoT高级工程师,传授大厂面试秘诀,教大家如何轻松get大厂offer!提前为大厂面试做准备,赢在起跑线&#x…

新安装win11,搜索框无法输入的问题

正确的做法是如下: 1首先进入win11系统,在搜索框中输入“ 控制面板 ”将其打开2在控制面板中找到“时间和语言“ 标题 再选择“ 语言和区域”, 标题 在显示的语言上面,点击省略号,进入语言选项 标题 在键盘处,删除不需要的输入法…

C++纯虚函数和抽象类 制作饮品案例(涉及知识点:继承,多态,实例化继承抽象类的子类,多文件实现项目)

一.纯虚函数的由来 在多态中&#xff0c;通常父类中虚函数的实现是毫无意义的&#xff0c;主要都是调用子类重写的内容。例如&#xff1a; #include<iostream>using namespace std;class AbstractCalculator { public:int m_Num1;int m_Num2;virtual int getResult(){r…

docker和docker-compose生产的容器,不在同一个网段,解决方式

在实际项目中&#xff0c;使用docker run xxXx 和docker-compose up -d 不在同一个网段&#xff0c;一个是默认是172.17.x.x, 另一个是172.19.x.x。为解决这个问题需要自定义一个网络&#xff0c;我命名为“my-bridge” 首先熟悉几条命令&#xff1a; docker network ls 或…

如何理解低代码开发工具?

目录 一、低代码平台是什么 1. 数据输入 2. 数据流转 3. 数据加工 4. 数据输出 &#xff08;1&#xff09;视图&#xff1a;单表的数据的简单展示 &#xff08;2&#xff09;看板&#xff1a;提供单表、多表数据的多种图表组合展示 二、低代码能力 ➪ 全栈可视化编程&#xff1…

你知道Linux操作系统的前世今生吗?Linux系统又该如何搭建呢?

文章目录 前言1. Linux 是什么1.1 Unix & Linux 发展历程图1.2 Linux 的发展1.3 Linux 的发行版 2. Linux 环境搭建2.1 环境搭建方式2.2 使用云服务器 3. 使用终端软件连接到 Linux3.1 什么是终端软件3.2 下载安装 XShell3.3 使用 XShell 登陆主机 总结 前言 可能很多人都…

labelImg

labelImg 在anaconda虚拟环境中安装labelImg 进入conda虚拟环境DL2中 输入命令&#xff1a; pip install PyQt5 pip install pyqt5-tools pip install lxml pip install labelimg PyQt5:是用于创建GUI应用程序的跨平台工具包&#xff0c;它将Python与Qt库融为一体 Lxml&#…

深信服技术认证“SCSA-S”划重点:渗透测试工具使用

为帮助大家更加系统化的学习网络安全知识&#xff0c;尽快通过深信服安全服务认证工程师认证&#xff0c;深信服推出“SCSA-S认证备考秘笈”共十期内容&#xff0c;“考试重点”内容框架&#xff0c;帮助大家快速get重点知识~ 划重点来啦 深信服安全服务认证工程师&#xff08;…

CVE-2023-0179提权利用

前言 在CVE-2023-0179-Nftables整型溢出中&#xff0c;分析了漏洞的成因&#xff0c;接下来分析漏洞的利用。 漏洞利用 根据漏洞成因可以知道&#xff0c;payload_eval_copy_vlan函数存在整型溢出&#xff0c;导致我们将vlan头部结构拷贝到寄存器&#xff08;NFT_REG32_00-N…

【SpringBoot】通过profiles设置环境

效果图&#xff0c;通过profiles设置环境 在父级pom.xml中添加配置 <profiles><profile><id>dev</id><properties><application.environment>dev</application.environment></properties><activation><activeByDefau…

OceanBase:OBServer节点管理

目录 1.查看节点 2.添加节点 2.1 创建数据目录 2.2.OceanBase 运行时所依赖的部分三方动态库 2.3.安装 OceanBase 数据库的 RPM 包 2.4.启动节点 observer 进程 2.5.向集群中添加节点 3.隔离节点 4.重启节点 4.1 停止服务 4.2 转储 4.3 关闭进程 4.4 启动进程 4.…

【原创】为MybatisPlus增加一个逻辑删除插件,让XML中的SQL也能自动增加逻辑删除功能

前言 看到这个标题有人就要说了&#xff0c;D哥啊&#xff0c;MybatisPlus不是本来就有逻辑删除的配置吗&#xff0c;比如TableLogic注解&#xff0c;配置文件里也能添加如下配置设置逻辑删除。 mybatis-plus:mapper-locations: classpath*:mapper/*.xmlconfiguration:mapUnd…

Java-认识String类

本章重点&#xff1a; 1. 认识 String 类 2. 了解 String 类的基本用法 3. 熟练掌握 String 类的常见操作 4. 认识字符串常量池 5. 认识 StringBuffer 和 StringBuilder 1.String类的重要性 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组…

C++中的内存管理

✨前言✨ &#x1f4d8; 博客主页&#xff1a;to Keep博客主页 &#x1f646;欢迎关注&#xff0c;&#x1f44d;点赞&#xff0c;&#x1f4dd;留言评论 ⏳首发时间&#xff1a;2023年11月21日 &#x1f4e8; 博主码云地址&#xff1a;博主码云地址 &#x1f4d5;参考书籍&…

如何选择适合的开源框架来构建微服务架构?

随着科技的飞速发展&#xff0c;云计算和大规模应用的需求日益显著&#xff0c;这促使微服务架构在软件开发领域中占据了主流地位。微服务架构的广泛应用为开发人员提供了灵活性、可伸缩性和高可用性&#xff0c;从而推动了快速的应用程序开发。然而&#xff0c;在构建微服务架…

ky10 server x86 安装、更新openssl3.1.4(在线编译安装、离线安装)

查看openssl版本 openssl version 离线编译安装升级 #!/bin/shOPENSSLVER3.1.4OPENSSL_Vopenssl versionecho "当前OpenSSL 版本 ${OPENSSL_V}" #------------------------------------------------ #wget https://www.openssl.org/source/openssl-3.1.4.tar.gzech…

git撤销某一次commit提交

一&#xff1a;撤销上一次commit提交&#xff0c;但不删除修改的代码 可以使用使用VSCode 二&#xff1a;使用 git reset --hard命令删除提交时&#xff0c;将会删除该提交及其之后的所有更改&#xff08;相当于你想要回滚到的提交的提交ID&#xff09; git reset --hard 版本…

ubuntu18.04安装并运行ORB-SLAM2

查看版本号 lsb_release -a 换源 Ubuntu系统自带的源都是国外的网址&#xff0c;国内用户在使用的时候下载比较慢甚至无法获取&#xff0c;需要替换成国内的镜像源 备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list.old 打开文件 sudo gedit /etc/apt/so…

【Python】153是一个非常特殊的数,它等于它的每位数字的立方和,即153=1*1*1+5*5*5+3*3*3。编程求所有满足这种条件的三位十进制数。

问题描述 153是一个非常特殊的数&#xff0c;它等于它的每位数字的立方和&#xff0c;即1531*1*15*5*53*3*3。编程求所有满足这种条件的三位十进制数。 输出格式 按从小到大的顺序输出满足条件的三位十进制数&#xff0c;每个数占一行。 方法一&#xff1a; for i in range(10…
最新文章