【Linux系统化学习】动静态库 | 软硬链接

2024-02-20 23:52

本文主要是介绍【Linux系统化学习】动静态库 | 软硬链接,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

硬链接和软链接

硬链接

软链接 

动态库和静态库

静态库

静态库的生成

静态库的使用

将库打包和使用

动态库

动态库的生成

动态库的使用 

库搜索路径


硬链接和软链接

硬链接

上篇文章我们说到真正找到磁盘上的文件并不是文件名,而是inode。其实在Linux中可以让多个文件名对应同一个inode,这样的方式就是硬链接

指令:ln 

总结: 

  • 硬链接不是一个独立的文件 ,就是在指定目录内部的一组映射关系。相当于引用计数;当没有文件名和inode映射时表示该文件被真正的删除。

  • 硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。

注:硬链接只可以链接文件不可以链接目录;因为引入了对目录的硬连接就有可能在目录中引入循环,在目录遍历的时候系统就会陷入无限循环当中,这样导致无法定位到访问目录。但是我们的Linux系统可以硬链接目录;每个目录文件中含有两个隐藏文件,分别为当前目录和上级目录,当前目录隐藏文件就和当前目录硬链接。

软链接 

硬链接是通过inode引用另外一个文件,软链接是通过名字引用另外一个文件。

指令:ln -s

总结:

软连接是一个独立的文件,有独立的inode;软连接内容时指向目标文件的路径,类似于Windows的快捷方式


动态库和静态库

在之前的文章中我们提到过系统库,当时只是简单的讲解了下静态库和动态库的优缺点;这篇文章我们要从一个库的制作者和使用者来详细介绍第三方库的制作和使用。

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚
  • 拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。

静态库

我们以一个库的制作者的角度自己编写一个可以实现整数加减的库;就是将实现整数加减的两个函数声明和定义分开,声明放在头文件中,实现放在源文件中。

头文件

  1 #pragma once 2 #include<stdio.h>                                                        3 extern int Add(int,int);
 1 #pragma once 2 #include<stdio.h>                                                        3 extern int Sub(int,int);

源文件 

  1 #include"Add.h"2 int Add(int x,int y)3 {4     return x+y;                                                          5 }
  1 #include"Sub.h"2 int Sub(int x,int y)3 {4     return x-y;                                                          5 }

当我们以库的制作者的身份将库写好后;我们就以普通程序员的身份使用这个库编写简单的程序。

  1 #include"Add.h"2 #include"Sub.h"3 int main()4 {5     int x =10;6     int y=20;7     printf("%d + %d = %d\n",x,y,Add(x,y));8     printf("%d - %d = %d\n",x,y,Sub(x,y));                               9     return 0;10 }

第一种使用方法就是将我们自己编写的源代码和库的源代码一起编译链接形成一个可执行程序即可。

但是这种使用方法我们要拿到库的源代码;再将库的每个源代码和我们的源代码一起预处理、编译、链接形成可执行程序。对于我们这种小库可能没什么影响,对于一些大的库源文件很多,每个源文件都进行这三部操作的话,很是浪费时间。

静态库的生成

对于上面的问题我们可以很好的解决;不是库的源文件浪费时间么,同时作为库的制作者我们也不想将我们的源代码公开,那我们可以将我们的库先编译成为二进制文件(.O)文件,将二进制文件和库使用者的二进制文件进行连接即可形成可执行程序

  makefile1 test:Add.o Sub.o testmain.o2     gcc -o $@ $^3 %.o:%.c4     gcc -c $<  

但是当我们库很大源文件很多时,形成的二进制文件也特别多;要是我们给库使用者二进制文件少给一个呢?

当我们想要这个库时候是不是只需要将我们的源文件编译成.o文件和库文件进行链接即可。因此我们可以将库的源文件编译成.o文件打包交给程序员即可。

    makefile    static-lib=libmymath.a2 $(static-lib):Add.o Sub.o3     ar -rc $@ $^                                                         6 %.o:%.c7     gcc -c $<8 .PHONY:clean9 clean:10     rm -rf *.o test

指令:ar -rc libmymath.a add.o sub.o
ar是gnu归档工具,rc表示(replace and create)

当我们库的源文件很多时,我们可以使用makefile,将我们的源代码自动生成二进制文件,再将我们的二进制文件全部形成我们的静态库。这里我们库的源文件很少,我就直接给大家手动生成。

通过上面的操作我们就可以将库的源文件生成二进制文件,进行生成静态库。

静态库的使用

将生成好的二进制文件和头文件拷贝到,我们的使用者编写的源代码下就可以使用库了。但是我们在使用静态库时还有很多小细节要注意。

将静态库和我们的源文件进行链接时首先要表用链接库的名称,和静态库的路径。其中库的名称是去掉后缀(.a)和lib。

  • -l 静态库的名称   代表我们链接哪一个静态库
  • -L 路径    代表所要链接静态库的所在路径

将库打包和使用

上面只是进行了二进制文件的打包当我们库源文件很多时,头文件也很多;因此我们可以将头文件和二进制文件分开存储在一个目录中打包交给使用的程序员。这里我们就不打包了,我们只将其放在同一个目录中使用。

    static-lib=libmymath.a2 $(static-lib):Add.o Sub.o3     ar -rc $@ $^6 %.o:%.c7     gcc -c $<8 .PHONY:output9 output:10     mkdir -p mymath_lib/include11     mkdir -p mymath_lib/lib 12     cp -f *.h mymath_lib/include13     cp -f *.a mymath_lib/lib14 .PHONY:clean15 clean:16     rm -rf *.o test mymath_lib

但是打包好的头文件和二进制文件在统一目录下,而我们的源文件并不在统一目录下,因此我们在使用的时候还要加上一些选项。

注:头文件的查找在当前目录下或者指定目录下查找,因此我们加上头文件的路径。

-I 头文件路径

 

动态库

动态库的生成

动态库也是将所有的的源文件形成二进制文件文件生成的;但是和动态库的生成方式和使用方式略有差异。 

注意:动态库的生成是使用gcc编译器来完成的,因此比较重要

makefile1 dy-lib=libmymath.so 2 $(dy-lib):Add.o Sub.o3     gcc -shared -o $@ $^4 %.o:%.c5     gcc -fPIC -c $<6 .PHONY:output7 output:8     mkdir -p mymath_lib/include9     mkdir -p mymath_lib/lib 10     cp -f *.h mymath_lib/include11     cp -f *.a mymath_lib/lib12 .PHONY:clean13 clean:14     rm -rf *.o *.so mymath_lib                                
~                                   

  • shared: 表示生成共享库格式
  • fPIC:产生位置无关码(position independent code)
  • 库名规则:libxxx.so

有了上面静态库的生成,静态库的生成我们就不过多赘述,只是生成动态库执行的选项不一样而已。

动态库的使用 

动态库的使用也是有很多的小细节,使用不当也会产生找不到动态库或者找不到头文件的问题。 

就像下面我们直接使用使用静态库的方法使用动态库,系统还是找不到我们的库在哪里。 

 

原因:

静态库是直接和我们的可执行程序链接在一起的,在连接的时候告诉我们的编译器我们库的路径编译器就可以找到。但是对于动态库不是链接在可执行程序中,可执行程序和库必须都加载到内存中,我们告诉了gcc编译器我们的库在哪里,但是操作系统要将我们的库加载到内存中,操作系统却不知道我们的库在哪里,系统默认找不到。因此我们要解决系统找不到我们库的问题。

库搜索路径

方法一:将头文件和库文件安装到系统中 

  • /usr/include
  • /lib64

在我们这两个系统路径下分别存放着库的头文件和二进制文件,我们可以将我们的二进制文件和头文件分别拷贝到上面的系统路径下即可。

方法二:建立一个软链接

在生成可执行程序的目录下建立一个库的软链接即可。

方法三:修改环境变量

LD_LIBRARY_PATH

执行我们的可执行程序系统不仅会在指定的路径下寻找我们的动态库,还会在一个环境变量中寻找。Linux中存在这样一个环境变量记录着动态库的存储路径。我们可以将我们的动态库添加到这一环境变量中即可。

注意

当我们退出我们的云服务器,重新登录后添加的环境变量就将会重置。 

方法四:更改配置文件

Linux下含有一个文件夹其中包含有关动态库加载的配置文件,里面只含有一个路径。我们可以在其目录下创建一个相同格式的空白文件,再将我们库的路径填入其中保存即可。


今天对Linux下动静态库的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!!  

这篇关于【Linux系统化学习】动静态库 | 软硬链接的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/729951

相关文章

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法

《ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法》本文介绍了Elasticsearch的基本概念,包括文档和字段、索引和映射,还详细描述了如何通过Docker... 目录1、ElasticSearch概念2、ElasticSearch、Kibana和IK分词器部署

Linux流媒体服务器部署流程

《Linux流媒体服务器部署流程》文章详细介绍了流媒体服务器的部署步骤,包括更新系统、安装依赖组件、编译安装Nginx和RTMP模块、配置Nginx和FFmpeg,以及测试流媒体服务器的搭建... 目录流媒体服务器部署部署安装1.更新系统2.安装依赖组件3.解压4.编译安装(添加RTMP和openssl模块

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

Linux环境变量&&进程地址空间详解

《Linux环境变量&&进程地址空间详解》本文介绍了Linux环境变量、命令行参数、进程地址空间以及Linux内核进程调度队列的相关知识,环境变量是系统运行环境的参数,命令行参数用于传递给程序的参数,... 目录一、初步认识环境变量1.1常见的环境变量1.2环境变量的基本概念二、命令行参数2.1通过命令编程

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

Linux编译器--gcc/g++使用方式

《Linux编译器--gcc/g++使用方式》文章主要介绍了C/C++程序的编译过程,包括预编译、编译、汇编和链接四个阶段,并详细解释了每个阶段的作用和具体操作,同时,还介绍了调试和发布版本的概念... 目录一、预编译指令1.1预处理功能1.2指令1.3问题扩展二、编译(生成汇编)三、汇编(生成二进制机器语