linux 动态库 静态库_静态库里面包含动态库

linux 动态库 静态库_静态库里面包含动态库动态库与静态库文件系统补完文件的三个时间acm动态库与静态库动态链接与静态链接静态库文件系统补完文件的三个时间acm我们通过stat指令查看文件信息:[lyl@VM-4-3-centos2022-3-14]$statlog.txtFile:‘log.txt’Size:0 Blocks:0IOBlock:4096regularemptyfileDevice:fd01h/64769d Inode:790871

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

在这里插入图片描述

文件系统补完

文件的三个时间acm

我们通过stat指令查看文件信息:

[lyl@VM-4-3-centos 2022-3-14]$ stat log.txt 
  File: ‘log.txt’
  Size: 0         	Blocks: 0          IO Block: 4096   regular empty file
Device: fd01h/64769d	Inode: 790871      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1001/     lyl)   Gid: ( 1001/     lyl)
Access: 2022-03-13 22:18:13.571644848 +0800
Modify: 2022-03-13 22:18:13.571644848 +0800
Change: 2022-03-13 22:18:13.571644848 +0800
 Birth: -

可以看到在文件信息下有3个时间,这三个时间分别代表着:

  • Access:最近访问文件的时间
  • Modify:文件内容最近修改的时间
  • Change:文件属性最近修改的时间
    在这里插入图片描述
    那么这三个时间有什么作用呢?
    我们在使用自动化构建工具Makefile时,如果连续make会发现:
    在这里插入图片描述
    这便是由Modify与Change两个时间决定的,若Modify时间不早于Change,则gcc指令可以执行,否则会显示此时mytest is up 同date.
    在这里插入图片描述

动态库与静态库

我们在实际开发中,经常要使用别人已经实现好的功能,这是为了开发效率和鲁棒性(健壮性);因为那些功能都是顶尖的工程师已经写好的,并且已经践行多年的代码。
那么如何使用他人开发的功能呢?可以使用:1.库,包括静态库与动态库。2.开源代码。3.基本的网络功能调用,比如各种网络接口、语音识别等等。
这其中,我们将详细介绍静态库和动态库。

动态链接与静态链接

一般情况下,为了更好的支持开发,第三方库或者是语言库,都必须提供静态库和动态库,这是方便程序员根据需要进行bin(二进制文件)的生成。
动态库是动态链接生成的,而静态库是静态链接生成的。
一般来说,我们直接gcc编译默认是动态链接的而如果加上-static选项,那么生成的可执行文件将为静态生成的
在使用-static选项时可能出现yum -y install glibc-static的报错,这其实是静态链接时没有找到libc.a。使用yum -y install glibc-static指令安装即可解决问题。

在这里插入图片描述
可以很明显的看到动态链接的文件大小明显要比静态链接的文件大小要小多了,这是为什么呢?
其实,动态链接是当执行到要调用的接口时,编译器会自动去搜寻所链接的库,而静态链接则是暴力的将所要用的库中可执行程序使用的二进制代码全部拷贝到我们生成的可执行文件中,这也就是为什么静态链接生成的文件这么大的原因了。
在这里插入图片描述

静态库与动态库

一般的命名方式为lib+库的名字+.a比如C语言提供的标准静态库名字就是libc.a
静态库是指程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
而动态库则是指程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表(头文件),而不是外部函数所在目标文件(.o)的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking),也就是说,动态链接是在需要调用接口时才会去将所用接口的二进制代码拷贝到内存中。
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
  • 这里需要提一下的是,我们之前所提过的进程地址空间中有一个共享区,而一般动态库的代码就映射在共享区,所有进程都共享着动态库的代码。
    在这里插入图片描述

动静态库的对比

动态库被加载在内存中,可以供多个使用库的程序共享映射到自己的虚拟地址空间使用,因此可以减少页面交换以及降低内存中代码冗余,并且因为与源程序模块分离,因此开发模式比较好。
而加载动态库的程序运行速度相对较慢,因为动态库运行时加载,映射到虚拟地址空间后需要重新根据映射起始地址计算函数/变量地址。
静态库则与之相反,其运行速度相对较快,但消耗资源较多。

生成静态库

我们为什么会制作库呢?一般是想让别人能够使用我们实现的功能,但又不暴露自己的源代码才会打包库。那么接下来我们来学习如何打包静态库。

打包静态库

由于生成静态库需要先生成目标文件(.o)再进行打包,故先编写相应的源文件再将其编译成目标文件:

[lyl@VM-4-3-centos 2022-3-14]$ gcc -c add.c -o add.o #生成目标文件
[lyl@VM-4-3-centos 2022-3-14]$ gcc -c sub.c -o sub.o #生成目标文件

此时的add.o和sub.o文件是已经编译好但还没有链接的两个文件,此时再用 ar命令将其打包成静态库:

[lyl@VM-4-3-centos 2022-3-14]$ ar -rc libmycal.a add.o sub.o #打包成静态库

这里的ar是gnu归档工具,rc表示(replace and create)。

[lyl@VM-4-3-centos 2022-3-14]$ ar -tv libmycal.a #查看静态库的目录列表
rw-rw-r-- 1001/1001   1240 Mar 14 11:11 2022 add.o
rw-rw-r-- 1001/1001   1240 Mar 14 11:11 2022 sub.o
  • t:列出静态库中的文件
  • v:verbose 详细信息

使用静态库

[lyl@VM-4-3-centos 2022-3-14]$ cp ./*.h ./lib #将头文件复制到lib目录下(提供函数入口地址,使用接口的前提) [lyl@VM-4-3-centos 2022-3-14]$ cp ./libmycal.a ./lib # 将静态库复制到lib目录下 

既然已经打包好了静态库,让我们包一下头文件来调用我们实现的接口:

#include <stdio.h>
#include "add.h"
#include "sub.h"

int main()
{ 
   
  int a = 10;
  int b = 20;
  printf("a+b:%d\n", Add(a, b));
  printf("a-b:%d\n", Sub(a, b));
  return 0;
}

在这里插入图片描述

发现代码编译不过去,报错说函数Add及Sub未定义,我们明明已经实现了接口并打包成静态库了,这是为什么呢?
其实gcc编译时去链接库和头文件是去默认路径以及当前路径寻找,而我们将静态库打包到lib目录下,gcc编译时就找不到我们的库了,所以我们需要加一些选项来告知gcc去寻找指定路径的库及头文件。
gcc寻找的默认路径:

/usr/include

在这里插入图片描述
因此,正确链接的指令为:

gcc -o main main.c -I ./lib -L ./lib  -lmycal -static

其中:

  • -I(i的大写) + 指定路径:是指告知gcc除了默认路径,还要去寻找一下指定的路径的头文件
  • -L + 指定路径:指定库所在的路径。
  • -l(L的小写)+库名字:表示要具体链接的是哪一个库,因为指定目录下可能不止一个库,所以要指明库的名字。
    由此,我们就静态链接生成了一个可执行文件main,运行main程序结果如下:
    在这里插入图片描述
    此时我们删除静态库libmycal.a,再运行main程序,发现程序照样可以运行。

生成动态库

学习完生成和使用静态库后,下面我们来生成一下动态库。

打包动态库

在这里,我们将生成动态库的依赖关系及方法写进自动化构建工具中:
在这里插入图片描述

需要注意的是:

  • 由于库在内存中是可加载的,它可能在内存中的任意位置,也可能被映射到进程地址空间的每个区域,所以为了保证库当中的代码执行不会出错,也就是要保证库中的代码是与位置无关的,因此生成.o文件时需要带上-fPIC选项表示生成与位置无关码。
  • 这里由于在依赖关系中已经点明了要生成的目标文件,故不带上$@也可以
  • 打包动态库不需要像静态库一样使用ar指令,直接用gcc即可,但是需要带上-shared选项表示生成共享库格式,这也体现了动态库代码映射在共享区的特点
    在这里插入图片描述

此时make就制作好了动态库:
在这里插入图片描述

使用动态库

和静态库使用一样带上三个选项打包动态库:
在这里插入图片描述
这里我们在运行程序时可能会报错:

error while loading shared libraries
cannot open shared object file: No such file or directory

这是因为,此时的可执行程序已经与编译器无关了,这属于运行问题,运行时系统也需要找到我们所使用的库,但在默认路径下没有我们的库。
这里解决方法有多种,但我倾向于推荐下面这一种:
修改环境变量LD_LIBRARY_PATH,将动态库所在路径添加到该环境变量中,这样程序在运行时系统就能够找到动态库,从而运行成功。

[lyl@VM-4-3-centos dynamic]$ echo $LD_LIBRARY_PATH
:/home/lyl/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
[lyl@VM-4-3-centos dynamic]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/lyl/2022-3-14/dynamic/lib
[lyl@VM-4-3-centos dynamic]$ echo $LD_LIBRARY_PATH
:/home/lyl/.VimForCpp/vim/bundle/YCM.so/el7.x86_64:/home/lyl/2022-3-14/dynamic/lib

当然,让系统找到我们的动态库还可以拷贝.so文件到系统共享库路径下, 一般指/usr/lib。但是这可能会污染系统原生的库,一般不推荐这样做。
其次,还有一种方法,在我们的系统下有/etc/ld.so.conf.d/这个路径:

[lyl@VM-4-3-centos dynamic]$ ls /etc/ld.so.conf.d/
bind-export-x86_64.conf  dyninst-x86_64.conf  hcoll.conf  kernel-3.10.0-1160.11.1.el7.x86_64.conf  mariadb-x86_64.conf  mxm.conf  sharp.conf

我们可以把库所在的路径写进这个路径当中,可以在这个路径下制造自己的.conf,然后再将库路径写进这个conf中:

echo "/home/lyl/2022-3-14/dynamic" > /etc/ld.so.conf.d/lyl.conf

当然这个方法也不推荐,毕竟可能污染库的头文件和库。

好了,动态库和静态库的全部内容至此介绍完毕。
文章编写不易,还希望各位能给个赞~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/188357.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • H264编码流程_h265和h265+视频编码有什么差别

    H264编码流程_h265和h265+视频编码有什么差别H264编码流程手绘图:H264编码网上图:

    2022年10月23日
  • 芯片设计之流水线设计-IC学习笔记(四)

    芯片设计之流水线设计-IC学习笔记(四)pipeline流水线设计是一种典型的面积换性能的设计。一方面通过对长功能路径的合理划分,在同一时间内同时并行多个该功能请求,大大提高了某个功能的吞吐率;另一方面由于长功能路径被切割成短路径,可以达到更高的工作频率,如果不需要提高工作频率,多出来的提频空间可以用于降压降功耗。

  • pycharm代码缩进快捷键_pycharm整体向前缩进

    pycharm代码缩进快捷键_pycharm整体向前缩进整体缩进:鼠标选中代码块,按tab键。反向缩进:鼠标选中代码块,按shift+tab.

  • RPC接口设计_java rpc项目

    RPC接口设计_java rpc项目写在前边分布式架构是互联网应用的基础架构,很多新人入职以来就开始负责编写和调用阿里的各种远程接口。但如同结婚一般,用对一个正确的接口就如同嫁一个正确的人一样,往往难以那么顺利的实现,或多或少大家都会在这个上边吃亏。每年双十一系统调用复盘的时候,我都会听到以下声音你们调我的接口报错了竟然不会自己重试?我的返回值应该从这里取我返回isSuccess()==true,不代表业务成功,你…

    2022年10月13日
  • OPC协议_opc协议端口号

    OPC协议_opc协议端口号当然,OPCUA组件也可以在Unix操作系统的信息技术(IT)系统中使用,诸如:Solaris、HPUX、AIX、Linux等,可以是企业资源计划(ERP)系统,可以是生产计划(MES)和监控软件(SCADA),还可以是电子商务应用。OPCUA接口协议包含了之前的A&E,DA,OPCXMLDAorHDA,只使用一个地址空间就能访问之前所有的对象,而且不受WINDOWS平台限制,因为它是从传输层Scoket以上来定义的,这点后面会提到,导致了灵活性和安全性比之前的OPC都提升了。……

  • docker 镜像构建_dockerfile引入两个镜像

    docker 镜像构建_dockerfile引入两个镜像前言如果我们已经安装了一个python3的环境,如果另一台机器也需要安装同样的环境又要敲一遍,很麻烦,这里可以配置Dockerfile文件,让其自动安装,类似shell脚本Dockerfile编写

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号