【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)文件,将二进制文件和库使用者的二进制文件进行连接即可形成可执行程序

  makefile

  1 test:Add.o Sub.o testmain.o
  2     gcc -o $@ $^
  3 %.o:%.c
  4     gcc -c $<  

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

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

    makefile    


    static-lib=libmymath.a
  2 $(static-lib):Add.o Sub.o
  3     ar -rc $@ $^                                                         
  6 %.o:%.c
  7     gcc -c $<
  8 .PHONY:clean
  9 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.a
  2 $(static-lib):Add.o Sub.o
  3     ar -rc $@ $^
  6 %.o:%.c
  7     gcc -c $<
  8 .PHONY:output
  9 output:
 10     mkdir -p mymath_lib/include
 11     mkdir -p mymath_lib/lib 
 12     cp -f *.h mymath_lib/include
 13     cp -f *.a mymath_lib/lib
 14 .PHONY:clean
 15 clean:
 16     rm -rf *.o test mymath_lib

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

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

-I 头文件路径

 

动态库

动态库的生成

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

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

makefile

  1 dy-lib=libmymath.so 
  2 $(dy-lib):Add.o Sub.o
  3     gcc -shared -o $@ $^
  4 %.o:%.c
  5     gcc -fPIC -c $<
  6 .PHONY:output
  7 output:
  8     mkdir -p mymath_lib/include
  9     mkdir -p mymath_lib/lib 
 10     cp -f *.h mymath_lib/include
 11     cp -f *.a mymath_lib/lib
 12 .PHONY:clean
 13 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下动静态库的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!!  

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-21 13:14:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-21 13:14:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-02-21 13:14:04       82 阅读
  4. Python语言-面向对象

    2024-02-21 13:14:04       91 阅读

热门阅读

  1. 备份服务器数据的重要

    2024-02-21 13:14:04       51 阅读
  2. 锁相放大器,数字锁相放大器.C和python版的源代码

    2024-02-21 13:14:04       50 阅读
  3. spring boot 3.0如何优雅的使用s3协议连接minio

    2024-02-21 13:14:04       47 阅读
  4. Converter学习

    2024-02-21 13:14:04       52 阅读
  5. shell关联数组用法

    2024-02-21 13:14:04       50 阅读
  6. webScoket实时通讯聊天

    2024-02-21 13:14:04       57 阅读
  7. CSS的全局值 initial inherit revert overlay unset

    2024-02-21 13:14:04       48 阅读
  8. MFC中不同编码格式内容的写入

    2024-02-21 13:14:04       48 阅读
  9. 手写table表格(一表头多数据)

    2024-02-21 13:14:04       51 阅读