您的位置:首页 > 教育 > 锐评 > 厦门网站设计定制_莱芜金点子招工招聘_南宁优化网站网络服务_长沙网站推广和优化

厦门网站设计定制_莱芜金点子招工招聘_南宁优化网站网络服务_长沙网站推广和优化

2025/4/18 11:25:33 来源:https://blog.csdn.net/2301_80774875/article/details/146964809  浏览:    关键词:厦门网站设计定制_莱芜金点子招工招聘_南宁优化网站网络服务_长沙网站推广和优化
厦门网站设计定制_莱芜金点子招工招聘_南宁优化网站网络服务_长沙网站推广和优化

Linux系列


文章目录

  • Linux系列
  • 前言
  • 一、动静态库的概念引入
    • 1.1 库的基本概念
    • 1.2 静态库(Static Library)
    • 1.3 动态库(Dynamic Library)
    • 1.4 动静态库的核心区别
  • 二、动静态库的实现
    • 2.1 静态库的创建及使用
    • 2.2 动态库的创建和使用
    • 三、优缺点对比
        • 静态库
        • 动态库
  • 总结


前言

在Linux系统开发中,静态库和动态库是我们经常使用的两种库文件类型,使用库文件进行开发工作,可以大大提高我们的开发效率,学习动静态库的差异及使用方式是我们熟练运用它的前提。
本篇文章我们将通过自己制作动静态库,来深入的学习动静态的使用、差异、原理。


一、动静态库的概念引入

在我们学习语言的过程中,不可避免的会使用库函数,那么它到底是什么呢?又是如何实现的呢?
接下来我们会慢慢回答这个问题。

1.1 库的基本概念

库是用来实现代码共享的,是预编译的代码集合(.o文件的集合),用来提供可复用的函数、类或数据,从而简化我们的开发过程提高开发效率,当我们使用库中的代码时只需要对库链接就可以使用。库又分为动态库和静态库两种类型,这两者各有其特点。

1.2 静态库(Static Library)

静态库通常由多个.o文件打包形成,以.a为后缀的文件集合。当可执行程序链接静态库时,在程序编译阶段会将使用到的,库中的程序所在的.o文件,全部嵌入至可执行文件中。

静态库的特点:

  • 文件编译时会将程序所用到的代码所在的.o文件全部嵌入至可执行文件中。
  • 每个可执行文件相对库来说是独立的(依赖代码已嵌入可执行文件)。
  • 不需要在程序运行时进行额外的文件加载。
  • 链接静态库会增加可执行文件的体积。
  • 库文件更新时需要重新编译所依赖该库的可执行文件。

1.3 动态库(Dynamic Library)

动态库比较复杂,我会在本片后面,及其后续文章不断补充相关知识

动态库是在程序运行时再加载的共享库,当程序执行时通过链接器与动态库建立关系,这个过程并不会发生拷贝。动态库同样是以多个.o文件打包的,以.so为后缀的文件集。

动态库的特点:

  • 程序运行时由操作系统动态加载、链接。
  • 一份被加载到内存的动态库,可被多个程序共享,减少了内存、磁盘的空间消耗。
  • 程序不需要额外内存,相较于链接静态库的可执行文件所占内存较小。
  • 更行动态库不需要重新编译可执行文件。

1.4 动静态库的核心区别

特性静态库 (.a)动态库 (.so)
链接方式编译时直接嵌入到可执行文件中运行时由动态链接器(如 ld-linux.so加载
文件体积可执行文件较大(包含库代码拷贝)可执行文件较小(仅记录引用)
内存占用每个进程独立加载库代码,内存冗余多个进程共享同一份库内存
更新维护需重新编译程序替换 .so 文件后立即生效
依赖管理无外部依赖,独立运行需确保运行时库路径正确
加载速度启动快(无需加载库)启动稍慢(需加载库)

静态库: 静态库的链接发生在可执行程序的编译时。编译器会将可执行文件中所涉及库中的代码,对应的.o文件嵌入到可执行文件中。
动态库: 动态库的链接发生在程序运行。动态库的链接会在程序启动时将动态库加载至内存的共享区,并库代码链接至可执行程序中(具体行为会在下篇文章中详细介绍)。

二、动静态库的实现

静态库和动态库本质都是.o文件的集合,只是在应用层两者的库文件的打包方式及访问方式存在差异,下面我们使用简单的代码,感受库的创建及使用,来深入学习。

在此过程中我们会以库的制作者和使用者两个视角来感受

2.1 静态库的创建及使用

代码部分:

  #pragma once   //防止头文件被重复包含                                                                                                                   #include<stdio.h>extern int myerrno;//标识该变量在源文件中已声明,具体作用可以搜一下int mydiv(int x,int y);

上面代码为mymath.h文件代码,学到这里我们就必须知道了,在我们编写代码时包含的.h文件(头文件)其实就是相当于库函数的一份说明书,内部并不存在具体函数实现。

  #include"mymath.h"int myerrno=0;int mydiv(int x,int y){                                                                                                                                 if(y==0){myerrno=1;//防止除0错误return -1;}return x/y;}

上述代码为mymath.c文件内容。

  1 static-lib=libmymath.a2 $(static-lib):mymath.o3     ar -rc $@ $^4 mymath.o:mymath.c5     gcc -c $^6 .PHONY:output7 output: 8    mkdir -p mylib/include9    mkdir -p mylib/lib10    cp *.h mylib/include11    cp *.a mylib/lib12 13 .PHONY:clear14 clear:15     rm -rf *.o *.a  mylib        

上面代码为Makefile文件内容,我来简单的解释一下:

2~3:使用ar -rc指令将.o文件打包成名为libmymath.a的静态库。

6~12:模拟库的发布,供使用者使用(Linux中也存在,存储库及头文件的目录)。

在这里插入图片描述
创建出我们的静态库并将库发布。

在这里插入图片描述
使用者将别人的库安装到自己所在路径。

   #include<mymath.h>int main(){int tmp=mydiv(10,1);printf("%d\n",tmp);return 0;}       

上面为main.c文件内容。
注意到了这里我们的库还是无法做到,像使用系统中的默认库那样使用,当你编译此文件时会发生链接错误,当我们的程序执行时找不到mymath.h的内容,这点很容易理解,他们都不在同一路径下,那么为什么c语言的库函数就可以直接编译呢?在Linux系统中,当我们在指向一个程序时,系统默认会去/usr/include/路径下寻找程序所包含的头文件,会去/lib64/路径下去找程序所需要的库文件,所以要想我们的库可以像c库一样被使用,只需将我们所写的libmymath.a库和mymath.h拷贝到上述系统路径即可,这里我们就不演示了,下面我们介绍另一种方法:

gcc 目标文件 -I 指定头文件搜索路径 -L 指定库文件搜索路径 -l指定链接库文件
gcc main.c -I mylib/include/ -L mylib/lib/ -lmymath

这里需要注意的是,当我们指定库文件是,只需要库文件名即可:lib库文件名.a。

在这里插入图片描述
程序成功编译并执行,此时a.out可执行文件中,已经嵌入一份mymath.o文件的数据了,即使你将库删除文件仍能执行,这里我就不演示了。

2.2 动态库的创建和使用

这里我们着重讲解两者不同的部分

代码部分:
mymethod.h文件内容:

  1 #pragma once2 #include<stdio.h>                                                                                                                 3 int print(char *str);    

mymethod.c文件的内容:

  1 #include"mymethod.h"2 3 int print(char *str)                                                                                                              4 {5   printf("%s\n",str);6   return 0;7 }

Makefile文件的内容:

  1 dy-lib=libmymethod.so2 $(dy-lib):mymethod.o3     gcc -shared -o $@ $^4 mymethod.o:mymethod.c5     gcc -fPIC -c $^6 .PHONY:output7 output: 8    mkdir -p mylib/include9    mkdir -p mylib/lib10    cp *.h mylib/include11    cp *.so mylib/lib12 .PHONY:clear13 clear:14     rm -rf *.o  *.so mylib        

2~3:将.o文件打包变为动态库,与静态库的打包方式不同。

4~5:将.c文件编译为.o文件
-fPIC:生成位置无关码,会在下篇介绍

接下来我们直接将库生成,并发布,以使用者角度再次探讨:

    1 #include<mymethod.h>2 3 int main()4 {                                                                                                                               5   print("abcdefg");6   return 0;7 }

在这里插入图片描述
在这里插入图片描述

现在我们使用程序链接静态库一样的方式,链接了动态库并生成了可执行文件,但是如果我们仅做了上面这些行为,生成的可执行程序还是无法执行,这是因为不同于静态链接的行为(将库嵌入到可执行文件),动态链接在链接时只是记录依赖关系,真正的加载是在原型时。所以即使用户在编译时正确指定了-L-l选项,生成的可执行文件在运行时仍然找不到动态库。

解决程序找不到动态库的方法:

1、将库文件和头文件拷贝到系统默认的库路径/lib64/usr/include下(系统默认链接搜索路径)。
2、在上述路径下与我们的库文件建立软连接(软连接的相关只是,上篇我们)。
3、将自己的库所在路径,添加到系统的环境变量LD_LIBRARY_PATH中。
4、在/etc/ld.so.conf.d路径下建立自己的动态路径的配置文件,然后重新ldconfig即可。

上述方法大家可以自己尝试,这里就不做展示了

三、优缺点对比

静态库
  • 优点
    • 无运行时依赖,部署简单。
    • 启动速度快(无需加载库)。
  • 缺点
    • 可执行文件体积大,浪费磁盘和内存。
    • 更新需重新编译,维护成本高。
动态库
  • 优点
    • 节省磁盘和内存资源。
    • 支持热更新(替换 .so 文件即可)。
  • 缺点
    • 依赖管理复杂(需设置 LD_LIBRARY_PATHrpath)。
    • 版本冲突风险(如 libfoo.so.1libfoo.so.2 不兼容)。

总结

本篇文章我们就介绍到这里,需要补充的是,gcc在编译程序时默认链接动态库,如果想要链接静态库可以使用-static显示指定。对于动态如如何实现共享,以及如何加载到内存这点我会在下篇介绍。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com