【Linux从入门到精通】动静态库的原理与制作详解

  

  本篇文章主要是围绕动静态库的原理与制作进行展开讲解的。其中涉及到了inode的概念引入和软硬连接的讲解。会结合实际操作对这些抽象的概念进行解释,希望会对你有所帮助。

文章目录

一、inode 概念

二、软硬链接

2、1 软连接

2、2 硬链接

三、动静态库概念

3、1 静态库制作

3、2 静态库的使用

3、2、1 加载到系统的文件中 

3、2、2 指定路径直接使用

3、3 动态库制作

3、4 动态库的使用

3、4、1 指定路径直接使用

3、4、2 环境变量:LD_LIBRARY_PATH 

3、4、3 系统文件:/etc/ld.so.conf.d/ 

 四、总结


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:Linux从入门到精通  👀

💥 标题:动静态库💥

 ❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️ 

一、inode 概念

  一个文件里面没有任何内容,文件的大小就是0吗?实际上并不是。我们知道,文件不仅仅要保存其内容,属性也是必不可少的。属性保存在哪里呢?

  Inode(Index Node)是文件系统中的一个重要概念,用于存储和管理文件的元数据。在UNIX和类UNIX操作系统中,如Linux,每个文件都与一个唯一的inode相关联。

Inode 包含了以下文件的元数据信息:

  1. 文件类型:指示文件的类型,如常见的普通文件、目录、符号链接等。
  2. 文件权限:描述了对文件的访问权限,包括拥有者、所属组和其他用户的读、写、执行权限。
  3. 文件大小:表示文件占用的磁盘空间大小。
  4. 日期和时间戳:记录了文件的创建时间、最近修改时间和最近访问时间。
  5. 硬链接计数:记录有多少个硬链接指向该文件。硬链接是指多个文件名指向同一个inode的情况。
  6. 文件数据块的物理地址:指示文件数据在磁盘上的存储位置。

  通过使用inode,操作系统可以有效地管理文件系统中的文件。例如,当需要读取或写入文件时,操作系统可以根据文件的inode查找文件的数据块的物理位置,以快速定位并访问文件内容。

  需要注意的是,inode与文件名是独立的。文件名与inode之间的对应关系由文件系统的目录结构来维护。当文件被打开或者通过文件名访问时,操作系统会根据文件系统的目录结构使用inode来定位文件。

二、软硬链接

2、1 软连接

  软连接(Symbolic Link)是一个指向另一个文件或目录的链接。它是一个特殊类型的文件,其中包含了所指向文件或目录的路径信息。软连接可以跨越不同的文件系统,甚至可以指向不存在的文件或目录。删除软连接不会影响被链接的文件或目录本身,而只会删除软连接本身。下面我们看一个实际的例子。

  如上图,我们在上图的路径中有一个可执行程序 mytest。假设我们想在其他路径下执行该程序,一种办法就是使用 相对路径/绝对路径 找到该可执行程序。具体如下图:

  但是每次都需要加上路径去执行该程序是不是优点太过繁杂。那有没有其他的便捷的方法呢?这里就可使用到软连接:ln -s ./test_8_19/bin/mytest mytest。具体如下图:

  对这种方法有一种莫名熟悉的感觉。在windows下,不就是在桌面创建快捷方式嘛!!!

软连接的主要特点和用途包括:

  • 文件间的共享:通过创建软连接,多个文件可以引用同一个文件,减少存储空间的占用。
  • 简化路径:软连接可以提供简洁的路径名,使得访问文件更加方便。
  • 跨文件系统的链接:软连接可以跨越不同的文件系统进行链接,增强了灵活性。
  • 动态更新:当原始文件或目录发生改变时,软连接也会实时更新,保持链接的有效性。

2、2 硬链接

  硬连接(Hard Link)是一个直接指向目标文件或目录的链接。硬连接与原始文件或目录没有区别,它们共享同一个索引节点,指向同一个磁盘区域,从而形成了相同的文件内容和属性。删除硬链接不会影响原始文件或目录,因为硬链接实际上是原始文件或目录的另一个名称。

  如上图,我们使用link指令创建了一个硬链接。我们发现他们的inode竟然相同。那么创建硬链接,并不是真正的创建文件。而是在目录下,建立了文件名与指定inode的映射关系而已!通俗理解,就是给指定文件起别名

  硬链接的主要特点和用途包括:

  • 文件备份:通过创建硬链接,可以在不占用额外存储空间的情况下,生成与原始文件内容完全相同的备份文件。
  • 文件共享:多个硬链接可以引用同一个文件,可以在不同位置使用相同的文件。
  • 快速访问:由于硬链接实际上是同一个文件,所以可以通过多个链接快速访问文件,提高效率。(隐藏文件 . ..)

  需要注意的是:

  • 软连接可以跨越不同的文件系统进行链接,而硬连接只能在同一文件系统中创建链接。
  • 删除原始文件并不会立即影响已经创建的硬链接,因为硬链接与原始文件共享相同的磁盘空间,只有当所有链接都被删除后,才会真正释放磁盘空间。
  • 软连接可以指向不存在的文件或目录,而硬连接必须指向已存在的文件或目录。

三、动静态库概念

3、1 静态库制作

  静态库是一种将一组预编译的目标文件(.o)打包成一个单独的文件的技术。它的主要作用是将代码模块化并提供给其他开发者使用,以便在编译阶段将这些模块链接到他们的程序中。

  静态库的形成: 静态库是由多个编译好的目标文件组成的,这些目标文件包含了被编译源代码的函数和数据。当我们将这些目标文件打包成一个单独的库文件时,就形成了静态库。通常,静态库的文件扩展名是.a(在Windows上也可以是.lib

形成静态库的过程包括:

  • 预处理:处理源代码中的宏定义、条件编译等预处理指令。
  • 编译:将预处理后的源代码编译成汇编代码。
  • 汇编:将汇编代码转换成机器码,并生成目标文件(通常是.o文件)。
  • 链接:将多个目标文件链接在一起形成静态库文件。

  如下图,我们经过编译生成了目标文件(.o)。

  我们再对 .o 文件打包生成静态库:ar -rc libhello.a mymath.o myprint.o。

  上述打包的过程就是生成静态库的过程。通俗来讲,静态库就是对.o 文件进行打包形成的

  我们所生成静态库的名字前缀必须是lib,后缀必须是.a 。这个就是规定。

  为了方便使用,我们将静态库和头文件统一放到一个目录下。具体操作如下:

libhello.a:mymath.o myprint.oar -rc libhello.a mymath.o myprint.omymath.o:mymath.cgcc -c mymath.c -o mymath.omyprint.o:myprint.cgcc -c myprint.c -o myprint.o.PHONY:hello
hello:mkdir -p hello/libmkdir -p hello/includecp -rf *.h hello/includecp -rf *.a hello/lib.PHONY:clean
clean:rm -rf *.a *.o hello

3、2 静态库的使用

  我们再把打包静态库和头文件目录(hello)拷贝到上级目录下一个文件中进行调用使用。

  我们直接编译main.c 文件,可以吗?看下图:

  是不可以的。编译时会自动在本目录下查找头文件。如果找不到,就回去系统的文件中查找。该目录下确实是没有,所以试过报错的。那怎么才能使用呢?

3、2、1 加载到系统的文件中 

  gcc 编译时,头文件的默认搜索路径是:/usr/include。库文件的默认搜索路径是:/lib64。当我们把自己所写的头文件和静态库加载到系统默认的搜索路径后,就会自动找到我们所引入的头文件和库函数。具体操作如下:

  但是此时我们进行编译,还是会进行报错。如下图:

  这是为什么呢?我们自己写的库属于第三方库,在编译时必须需要指定库的名字。具体如下:

  虽然这样可以使用静态库,但是不支持这种做法。这样就有可能会污染系统的文件。

3、2、2 指定路径直接使用

  加载到系统的文件中不是一种很优的方法。哪还有其他方法吗?答案有的。我们在编译时直接告诉编译器路径:gcc main.c -I ./hello/include/ -L ./hello/lib/ -lhello。具体如下图:

3、3 动态库制作

   我们知道,静态库在编译过程中,目标文件被编译链接生成的可执行程序中包含所有函数和数据。可执行程序所占用内存比较大。当程序运行时,所有的代码和数据都被加载到内存中,并占用固定的内存地址。这种方式是静态链接,使得可执行文件的体积较大,且不具备代码共享的特性。而动态库并不是这样的,且动态库的生成与静态库也有所区别。我们接着往下看。

  动态库(Dynamic Link Library,简称DLL)是一种可执行文件,包含可以被多个程序同时调用的函数和数据。与静态库相比,动态库提供了更为灵活和高效的代码共享方式。

形成动态库的过程主要包括以下几个步骤:

  1. 编写动态库代码:根据需求编写所需的函数和数据,并将其封装在一个动态链接库项目中。

  2. 编译动态库代码:使用合适的编译器将动态库代码编译成二进制形式,生成具有扩展名为.dll(在Windows系统中)或.so(在Linux系统中)的文件。

  3. 链接动态库:将动态库文件与主程序进行链接,使主程序能够使用库中的函数和数据。在这个过程中,主程序并不会把动态库的内容复制到自己的代码中,而是在运行时通过动态链接来加载和使用库中的函数和数据。

  通过上图我们发现,在生成.o文件时多出了-fPIC选项。-fPIC选项是什么意思呢?

  gcc的-fPIC选项是用于生成可重定位目标文件(Position Independent Code,PIC)的编译选项。通过使用该选项,生成的目标文件可以在内存中的任何位置加载和执行,而不需要进行修改或重新链接

  在编译过程中,目标文件只包含程序所需的函数和数据的引用信息,真正的函数和数据则通过动态链接库(Dynamic Linking Library,DLL)提供。在程序运行时,操作系统会将需要的函数和数据从动态链接库中加载到内存,并进行地址重定向。这种方式使得可执行文件的体积较小,且不同程序之间可以共享同一个动态链接库。

  而-fPIC选项则是在编译过程中产生与位置无关的代码,主要用于动态链接库的创建。使用该选项可以确保生成的目标文件能够适应不同的内存布局和地址空间。具体来说,-fPIC选项会通过使用相对寻址(relative addressing)的方式替代绝对寻址(absolute addressing),使得目标文件中的函数和数据可以在不同的内存地址加载和执行。

  当我们有了目标文件(.o)后,再看如下图生成动态库:

3、4 动态库的使用

  为了同时生成静态库和动态库,我们再次进行对makefile文件进行改写,代码如下:

.PHONY:all
all:libhello.so libhello.alibhello.so:mymath_d.o myprint_d.ogcc -shared mymath_d.o myprint_d.o -o libhello.so
mymath_d.o:mymath.cgcc -c -fPIC mymath.c -o mymath_d.o
myprint_d.o:myprint.cgcc -c -fPIC myprint.c -o myprint_d.olibhello.a: mymath.o myprint.oar -rc libhello.a mymath.o myprint.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o
myprint.o:myprint.cgcc -c myprint.c -o myprint.o.PHONY:output
output:mkdir -p output/libmkdir -p output/includecp -rf *.h output/includecp -rf *.a output/libcp -rf *.so output/lib.PHONY:clean
clean:rm -rf *.o *.a *.so output

3、4、1 指定路径直接使用

   我们同样是先把打包动静态库和头文件目录(hello)拷贝到上级目录下一个文件中进行调用使用。动态库的直接指定路径使用与静态库相似。我们看如下实例:

  我们知道,动态库和静态库真是的名字去掉前后缀后都是hello。那我们直接使用-lhello,指定的是动态库还是静态库呢?也就是默认情况下是动态链接呢?还是静态链接呢?我们看选图:

  我们发现,默认情况下是动态链接。但是并没有找到动态库!且生成的可执行程序也不能执行。这又是为什么呢?原因是我们需要把动态库加载到内存中后,可被多个进程使用(因此也被称为共享库)。但是我们只是告诉gcc动态库所在的路径了,并没有告诉操作系统动态库在哪里!

3、4、2 环境变量:LD_LIBRARY_PATH 

  在Linux下,默认查找共享库的环境变量是LD_LIBRARY_PATHLD_LIBRARY_PATH是一个包含目录路径的环境变量,用于告诉动态链接器(ld.so)在哪些目录中搜索共享库文件

当程序需要加载共享库时,动态链接器会按照以下顺序进行搜索:

  1. 优先搜索程序内部指定的路径。
  2. 如果没有找到,接下来会搜索LD_LIBRARY_PATH中指定的路径。
  3. 如果还是没有找到,最后动态链接器会按照一定的默认规则搜索系统预定义的路径,如/usr/lib/lib等。

  通过设置LD_LIBRARY_PATH环境变量,可以临时修改共享库的搜索路径。例如,可以使用以下命令来设置LD_LIBRARY_PATH环境变量:

export LD_LIBRARY_PATH=/path/to/shared/libs

  该命令将/shared/libs目录添加到共享库搜索路径中。在当前的终端会话中,程序运行时将会优先搜索该路径下的共享库。

  但是LD_LIBRARY_PATH是一个临时的环境变量设置,只对当前终端会话有效。如果希望永久修改共享库的搜索路径,可以考虑修改系统范围内的配置文件,如/etc/ld.so.conf.d/目录下的配置文件,并执行相应的更新操作,例如使用ldconfig命令。稍后我们也会详细介绍。

  现在以我自己为例子来添加动态库到共享库的环境变量中。具体如下图:

  其实我们也不难发现,每个路径都是用 :来进行分割的。我们添加成功后,我们再次执行a.out 时,系统就回根据环境变量自动找到改动挑库所在的位置。运行如下图:

3、4、3 系统文件:/etc/ld.so.conf.d/ 

  在Linux系统中,/etc/ld.so.conf.d/目录是用来配置共享库搜索路径的。共享库在运行时被程序动态链接使用,这些库存储在特定的路径下。ld.so是动态链接器(loader)的一部分,它负责在运行程序时定位和加载所需的共享库。

  在/etc/ld.so.conf.d/目录中,可以创建不同的配置文件,每个文件对应一个共享库搜索路径。这些配置文件通常以.conf为后缀名。通过在这些配置文件中添加共享库的路径,可以告诉动态链接器在特定的目录中搜索共享库

  当系统启动或需要加载共享库时,动态链接器会读取这些配置文件,并根据其中的路径进行查找。如果某个共享库存在于指定的路径中,那么它将被加载到内存中供程序使用。使用/etc/ld.so.conf.d/目录可以方便地管理共享库路径的配置。可以在不同的配置文件中分别设置不同的共享库路径,这样可以根据需要独立地管理和更新路径的配置,而不会影响到其他配置文件。

  我们再来看一下具体的操作实例。我们在 /etc/ld.so.conf.d/ 下创建一个test.conf 文件。然后把我们动态库所在的路径编辑加入test.conf 文件中。

  我们再看就可以找到动态库了。

 四、总结

  动态库和静态库是两种代码库的形式,它们主要用于程序的模块化开发和代码共享。它们具有以下不同之处:

  1. 静态库(Static Library): 静态库在编译时会被完全链接到可执行文件中,使得可执行文件包含了所有需要的库函数和数据。使用静态库的主要优点是程序的独立性,无需依赖外部库文件即可运行。静态库适用于一些较小的应用,或者需要独立部署的情况。

  2. 动态库(Dynamic Library): 动态库在程序运行时由操作系统进行加载和链接,而不是在编译时完全链接到可执行文件。程序在运行时只需要动态库的引用并调用相应函数即可。使用动态库的主要优点是节约系统资源和提高可维护性。多个程序可以共享同一个动态库,减少了内存占用和可执行文件的大小。

为什么要有动态库和静态库呢?主要原因包括:

  1. 代码共享:将常用的功能进行封装成库,可以被多个应用程序共享使用,避免重复编写相同的代码,提高了代码的复用性和开发效率。

  2. 系统资源的优化:动态库的方式可以在程序运行时动态加载和链接,节省了内存的占用空间,提高了系统资源的利用效率。

  3. 可维护性:使用库的方式可以使得程序模块化,便于维护和更新。当库需要升级或修复BUG时,只需替换库文件而无需修改引用该库的程序。

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

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

相关文章

【rust/egui】(三)看看template的app.rs:序列化、持久化存储

说在前面 rust新手,egui没啥找到啥教程,这里自己记录下学习过程环境:windows11 22H2rust版本:rustc 1.71.1egui版本:0.22.0eframe版本:0.22.0上一篇:这里 serde app.rs中首先定义了我们的Templ…

爬虫框架- feapder + 爬虫管理系统 - feaplat 的学习简记

文章目录 feapder 的使用feaplat 爬虫管理系统部署 feapder 的使用 feapder是一款上手简单,功能强大的Python爬虫框架 feapder 官方文档 文档写的很详细,可以直接上手。 基本命令: 创建爬虫项目 feapder create -p first-project创建爬虫 …

高品质音乐下载命令行工具Musicn

又到了小苏同学的生日🎂,宝贝,生日快乐!祝永远健康、快乐、心想事成! 什么是 Musicn ? Musicn 是一个可播放及下载高品质🎵音乐🎵的命令行工具。支持咪咕、酷我、酷狗和网易云的服务…

Azure文件共享

什么是Azure文件共享 Azure文件共享是一种在云中存储和访问文件的服务。它允许用户在不同的计算机、虚拟机和服务之间共享数据,并在应用程序中进行访问、修改和管理。 Azure文件共享可以用于各种用途,例如: 共享文件资源给多个虚拟机或服务…

江南大学计算机考研分析

24计算机考研|上岸指南 江南大学 江南大学计算机考研招生学院是人工智能与计算机学院。目前均已出拟录取名单。 江南大学人工智能与计算机学院成立于2020年3月,办学历史可追溯到1994年设立的计算机应用专业。学院秉持江南大学“彰显轻工特色,服务国计民…

python基础5——正则、数据库操作

文章目录 一、数据库编程1.1 connect()函数1.2 命令参数1.3 常用语句 二、正则表达式2.1 匹配方式2.2 字符匹配2.3 数量匹配2.4 边界匹配2.5 分组匹配2.6 贪婪模式&非贪婪模式2.7 标志位 一、数据库编程 可以使用python脚本对数据库进行操作,比如获取数据库数据…

Android Studio Giraffe控制台乱码

这几天在使用Android Studio Giraffe进行一个App的开发,在项目构建的时候,控制台输出中文都是乱码,看着很不爽,进行了两项配置,中文就可以正常输出了,看起来就爽多了。 第一个配置:点击Help菜单…

[JavaWeb]【四】web后端开发-SpringBootWeb入门

目录 一 Spring 二 SpringBootWeb入门 2.1 入门需求 2.2 分析 2.3 开始创建SpringBootWeb 2.4 创建类实现需求 2.5 启动程序 2.6 访问 三 HTTP协议 3.1 HTTP-概述 3.2 HTTP-请求协议 3.3 HTTP-响应协议 3.3.1 响应状态码 && 响应类型 3.4 HTTP-协议解析 前言…

【Unity】按Esc进入操作菜单

本文章是基于如下视频的自我总结 https://www.youtube.com/watch?vJivuXdrIHK0 步骤如下 1、在Canvas 界面添加一个Panel Panel中添加一个按钮,调整按钮的大小为合适大小 调整字体的大小为合适大小 可以为字体添加Shadow组件,产生阴影效果 2、调整按…

牛客网华为OD前端岗位,面试题库练习记录02

题目一 删除字符串中出现次数最少的字符(HJ23) JavaScript Node ACM 模式 const rl require("readline").createInterface({ input: process.stdin }); var iter rl[Symbol.asyncIterator](); const readline async () > (await iter.next()).value;void (asyn…

【机器学习】处理不平衡的数据集

一、介绍 假设您在一家给定的公司工作,并要求您创建一个模型,该模型根据您可以使用的各种测量来预测产品是否有缺陷。您决定使用自己喜欢的分类器,根据数据对其进行训练,瞧:您将获得96.2%的准确率! …

Django模型基础

文章目录 一、models字段类型概述属性命名限制使用方式逻辑删除和物理删除常用字段类型 二、常用字段参数常用字段选项(通过字段选项,可以实现对字段的约束) 实践创建模型执行迁移命令 并 创建超级用户登录admin后台添加文件和图片字段定义模型字段和约束及在Admin后…

计算机竞赛 卷积神经网络手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…

【0815作业】搭建select的TCP客户端、poll客户端、tftp文件上传

IO多路复用(重点!!!) 进程中如果同时需要处理多路输入输出流,在使用单进程单线程的情况下,同时处理多个输入输出请求。在无法用多进程多线程,可以选择用IO多路复用;由于不…

DTC 19服务学习1

在UDS(统一诊断服务)协议中,0x19是用于DTC(诊断故障代码)信息的服务。以下是你提到的子服务的功能和作用: 0x01 - 报告DTC按状态掩码。这个子服务用于获取当前存储在ECU中的DTC列表。状态掩码用于过滤DTC&a…

通过爬虫抓取上市企业利润表并在睿思BI中展示

睿思BI从v5.3开始支持网络爬虫,可以从指定URL抓取表格数据,本示例实现从网络上抓取上市企业招商银行的利润表数据,并在睿思BI中进行展现。 功能演示URL:https://www.ruisitech.com/rsbi-ultimate/#/dashboard/ShareView?token31…

【C语言】动态通讯录 -- 详解

⚪前言 前面详细介绍了静态版通讯录【C语言】静态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客,但是静态版通讯录的空间是无法被改变的,而且空间利用率也不高。为了解决静态通讯录这一缺点,这时就要有一个能够随着存入联系人数量的增加而增大…

记录hutool http通过代理模式proxy访问外面的链接

效果: 代码: public class TestMain {public static void main(String[] args){HttpRequest httpRequest HttpRequest.get("https://www.youtube.com").timeout(30000);httpRequest.setProxy(new Proxy(Proxy.Type.HTTP,new InetSocketAddre…

简单理解Linux中的一切皆文件

一款操作系统要管理各种各样不同的硬件,因为硬件的不同所以它们使用的文件系统也不同。但是按道理来说,文件系统的不同对于用户来说可不是一件好事,操作不同的硬件就要使用不同的方法。 但是Linux有一切皆文件。 简单来说,Linux…

【数据分析入门】Matplotlib

目录 零、图形解析与工作流0.1 图形解析0.2 工作流 一、准备数据1.1 一维数据1.2 二维数据或图片 二、绘制图形2.1 画布2.2 坐标轴 三、绘图例程3.1 一维数据3.2 向量场3.3 数据分布3.4 二维数据或图片 四、自定义图形4.1 颜色、色条与色彩表4.2 标记4.3 线型4.4 文本与标注4.5…