【Linux】动静态库-概念制作

news2024/10/3 2:14:41

文章目录

    • 前置知识:
      • 库的命名
      • C标准库
      • 动静态库
      • 安装C/C++静态库
      • 完整的库需要的东西
  • 制作静态库
    • 制作
    • 使用
      • 一个小疑惑:
  • 制作动态库
    • 制作
    • 使用
  • 总结:

前置知识:

一般库分为两种:动态库和静态库 静态库和动态库本质就是文件!也有inode


库的命名

库文件的命名一般为: libXXXXX.so 或者libXXXXX.a-

如何知道库的真实名字?

去掉lib前缀 去掉.a- .so-的后缀,剩下的就是库的名称

例如: libc-2.17.so动态库的真实名字就是:c-2.17


C标准库

问:C标准库在哪里?

安装在系统中

验证:

ldd 可执行程序:显示可执行程序依赖的库

image-20220720202952174

image-20220720202245650

其中这个libc-2.17.so就是C语言的标准库,名字为:c-2.17


那C++的库呢?

image-20220720203535048

库名字为: stdc++


gcc默认是动态链接编译:

image-20220720232402869


如果我们希望静态链接编译,就需要加-static选项

image-20220720232617806


动静态库

在Linux中:如果是动态库:库文件是以.so为后缀的

  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码

如果是静态库:库文件是以.a为后缀的

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再需要静态库

在windows中,动态库以.lib为后缀, 静态库以.dll为后缀

动态链接和静态链接的大小:

静态库 程序在编译链接的时候把库的代码复制到可执行文件当中的,生成的可执行程序在运行的时候将不再需要静态库,因此使用静态库生成的可执行程序的大小一般比较大

动态库生存的可执行程序体积比较小, 因为动态链接只是把我们要关联的函数在库里面关联起来,不会进行任何的拷贝的行为, 当函数执行时,如果要执行库函数的代码,就直接跳转到库中执行,

image-20220720232817262


总结:

静态库

优点:

  • 使用静态库生成可执行程序后,该可执行程序就可以独自运行,一旦形成就不再依赖库了,哪怕依赖的库被删除了,也不影响该可执行程序的运行

缺点:

  • 使用静态库生成可执行程序会占用大量空间,特别是当有多个静态程序同时加载而这些静态程序使用的都是相同的库,这时在内存当中就会存在大量的重复代码

动态库

在可执行文件开始运行前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接.动态库在多个程序间共享,节省了磁盘空间,操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间

优点:

  • 节省磁盘空间,且多个用到相同动态库的程序同时运行时,库文件会通过进程地址空间进行共享,内存当中不会存在重复代码

缺点:

  • 必须依赖动态库,可执行程序的移植性就比较差,如果库缺失了,可执行程序就运行不了

1)一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码

2)在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接

3)动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间,操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间


安装C/C++静态库

sudo yum install glibc-static
sudo yum install libstdc++-static

完整的库需要的东西

一套完整的库,包括3样东西: 库文件本身, 头文件, 说明文档

我们以前写C/C++代码的时候,一般都是将头文件和源文件分离, 在.h中声明. .c或者.cpp中定义,为什么要这样设计呢?

因为我们要制作库! 这样方便使用,而且保证了隐私性, 其中头文件会暴露库中方法的使用,而且方便维护!

—我们要知道程序的编译要经历如下过程:

  1. 预处理: 完成头文件展开、去注释、宏替换、条件编译等,最终形成xxx.i文件
  2. 编译: 完成词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,最终形成xxx.s文件
  3. 汇编: 将汇编指令转换成二进制指令,最终形成xxx.o文件
  4. 链接: 将生成的各个xxx.o文件进行链接,最终形成可执行程序

如果我们想把自己的方法给别人使用, 我们可以给别人提供源代码和头文件, 如果我们不想把源文件给别人, 我们可以把所有的.o文件打包成库,发给别人

制作库的本质:将所有的.o文件以某种方式打包


制作静态库

准备工作:

test_lib目录下的文件:

image-20220731191811969

other目录的文件:

image-20220731191801401


image-20220731191229689

此时直接编译发生错误, 报错原因是 gcc不能找到库的源文件, 因此我们需要在编译的时候跟上源文件的位置:

gcc mytest.c ../test_lib/add.c ../test_lib/sub.c -o mytest

image-20220731191856312


上述还不能称为制作库!


制作

我们现在test_lib目录下写这样一个Makefile文件:

image-20220731192850620

lib_math.a:add.o sub.o
	ar -rc lib_math.a $^	#将所有的.o文件打包归档打包形成lib_math

%.o:%.c		#生成.o文件依赖.c
	gcc -c $<  #依次根据.c文件编译生成所有的同名.o文件, $<:把上面的内容展开之后,一个一个的编译

.PHONY:output  #发布库
output:
	mkdir output	
	cp *.h output	#把当前路径下的所有.h文件拷贝到output文件夹下
	cp lib_math.a output	

.PHONY:clean
clean:
	rm -rf *.o lib_math.a output	#删除所有的.o文件和lib_math和output

Makefile文件的含义:

1.将库文件编译为.o

  • 其中**%是通配符, **%.o作含义是:把当前目录下的所有.o结尾的文件展开

2.用ar命令, 将所有的.o文件进行打包

  • ar命令是gnu的归档工具,常用于将目标文件打包为静态库,下面我们使用ar命令的-r选项和-c选项进行打包
    • -r(replace):若静态库文件当中的目标文件有更新,则用新的目标文件替换旧的目标文件
    • -c(create):建立静态库文件
ar -rc libname.a  #要打包的.o文件

3.用make output进行发布库,把相关内容放到output文件夹中

  • 注意:要把.h也发布出去. 这样别人才能知道库里面有什么

查看静态库的内容:

ar -tv lib_math.a   

其中:

  • -t 选项: 列出静态库的目录列表
  • -v 选项:列出详细信息

image-20220731193426155


我们甚至可以把我们写的库安装到系统中,但是非常不建议!!!

.PHONY:install
install:
	cp *.h /usr/include		#把当前路径下的所有.h文件拷贝到/usr/include下
	cp lib_math.a /lib64		#把静态库拷贝到lib64文件夹下

使用

假设要使用的人所在目录是 friend

image-20220731195141595

直接编译会报错!因为找不到头文件,为什么会找不到呢?

  • 因为编译器不会查找当前源文件同级目录下的目录中的内容,因为我们此时的头文件在output目录下, **所以我们需要带上-I./output**选项,告诉编译器在当前目录的output目录下查找头文件

image-20220731195839722

但是仍然报错了, 因为找不到库函数的实现了,所以我们还需要告诉库的路径在哪里: -L./output

实际可能存在很多库,编译器不知道链接这个路径下的哪个库,所以我们还需要带上库的名称 -l_math

  • 注意:我们这里的库是: lib_math.a 但是去掉头和尾才是库的名字 _math

总结:

1.因为编译器不知道你所包含的头文件add.h和sub.h在哪里所以需要指定头文件的搜索路径

2.因为头文件add.h当中只有my_add函数的声明,并没有该函数的定义,所以还需要指定所要链接库文件的搜索路径

3.实际中,在库文件的lib目录下可能会有大量的库文件,因此我们需要指明需要链接库文件路径下的哪一个库


-I,-L,-l这三个选项后面可以加空格,也可以不加空格

  • -I :指定头文件的搜索路径

  • -L:指定库搜索路径

  • -l :指明要链接哪一个库

image-20220731200316071


此时我们可以搞一个Makefile方便编译:

test:test.c
	gcc -o $@ $^ -I./output -L./output -l_math

.PHONY:clean
clean:
	rm -rf test

一个小疑惑:

我们之前写C/C++代码的时候,也使用到了各自库,为什么我们不需要加上述的这些选项来指明些什么呢?

因为之前的库默认在系统的路径下: 编译器能识别这些存在于配置文件中的路径,因为我们使用gcc编译的是C语言,而gcc就是用来编译C程序的,所以gcc编译的时候默认就找的是C库,但此时我们要链接的是哪一个库编译器是不知道的,因此我们还是需要使用-l选项,指明需要链接库文件路径下的哪一个库

例如: 库文件: /lib64 ,/usr/lib 头文件:/usr/include

所以说,如果我们想投机取巧,完全可以把对应的库和头文件拷贝到默认路径下,但是 这种做法严重不推荐! 可能会"污染"里面的东西 或者我们写的把库里面的东西覆盖掉了(命名不标准)


制作动态库

制作

image-20220731204513751

1.此时我们还是需要将库文件全部编译为.o文件, 但是此时需要添加一个选项: -fPIC, 因为要形成与位置无关码position independent code

  • -fPIC作用于编译阶段,告诉编译器产生与位置无关的代码,此时产生的代码中没有绝对地址,全部都使用相对地址,从而代码可以被加载器加载到内存的任意位置都可以正确的执行.这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的
gcc -fPIC -c add.c sub.c

2.把库进行打包, 此时使用的不是ar指令,而是-shared指令

gcc -shared -o $% $^#形成一个动态链接的共享库

3.使用make shared_lib 进行发布我们的动态库

  • 注意:要把.h(头文件)和so(动态库)也发布

所以Makefile文件为:

#形成一个动态链接的共享库
lib_math.so:add.o sub.o
	gcc -shared -o $@ $^

%.o:%.c 	#生成.o文件依赖.c文件
 	#   $<:依次编译.c文件生成同名的.o文件 -fPIC选项:生成位置无关码,程序内部的地址方案与位置无关
	gcc -fPIC -c $<

.PHONY:shared_lib
shared_lib:
	mkdir shared_lib 
	cp *.h shared_lib 
	cp lib_math.so shared_lib

.PHONY clean:
clean:
	rm -rf *.o lib_math.so 

image-20220731204616140


使用

我们先把shared_lib文件夹拷贝到friends目录下

image-20220731204842914


同样的,这里我们也需要指定路径搜索头文件 :-I./shared_lib ,同样的,也需要指明库文件的搜索路径:-L./shared_lib ,也需要指明链接的是哪一个库:-l_math 库lib_math.so的真实名字是:_math, 所以我们可以编写我们的Makefile了:

test:test.c
	gcc -o $@ $^ -I./shared_lib -L./shared_lib -l_math

.PHONY:clean
clean:
	rm -f mytest

image-20220731213432570

此时可以编译通过,但是运行的时候就报错了!

为什么呢?静态库不是也是这样做的吗? 为什么在这里就不行了呢?

因为静态库把目标模块导入直接拷贝到我们的文件中, 运行时不需要再去找了, 而动态库,编译的时候仍然需要去找库在哪里, 运行的时候,也需要加载动态库

image-20220731224334192

但是我们上面编译的时候不是已经告诉了库路径了吗? 但这只是告知了编译器头文件的库路径在哪里,当程序编译完成后,已经和编译器无关了, 运行的时候加载器还是不知道库路径在哪里


所以我们要怎么解决呢?

做法1:拷贝.so文件到系统共享库路径下(不推荐)

动态库的头文件直接拷贝到共享库路径: /usr/bin目录下!

image-20220731224923015

做法2:更改LD_LIBRARY_PATH

通过导入LD_LIBRARY_PAYH这个环境变量 这个环境变量是程序运行动态查找库时所要搜索的路径, 指明程序启动后动态库的搜索路径!

export LD_LIBRARY_PATH=路径 	#导入LD_LIBRARY_PATH环境变量

image-20220731220837446

image-20220731220940495

注意:这种在命令行上设置的环境变量,只在当前登录期间有效,


做法3:配置/etc/ld.so.conf.d/

这个是系统搜索动态库的路径, /etc/ld.so.conf.d/路径下存放的全部都是以.conf为后缀的配置文件,而这些配置文件当中存放的都是路径,系统会自动在/etc/ld.so.conf.d/路径下找所有配置文件里面的路径,之后就会在每个路径下查找你所需要的库 这种做法可以永久生效!

我们若是将自己库文件的路径也放到该路径下,那么当可执行程序运行时,系统就能够找到我们的库文件了

1)将库文件所在目录的路径存入一个以.conf为后缀的文件当中

image-20220731225254834

2)该.conf文件拷贝到/etc/ld.so.conf.d/目录下

image-20220731225410179

3)需要使用ldconfig命令将配置文件更新一下,更新之后系统就可以找到该可执行程序所依赖的动态库了

image-20220731225606227


总结:

1.制作库的本质: 将所有的.o文件打包

  • 静态库: ar -rc
  • 动态库:gcc -fPIC -shared

2.发布库:将 所有的.h文件 *.h 和 .a /.so发布出去

3.使用:拿到别人的库和头文件,加入到自己的项目中

静态库可以直接使用,动态库还要告知系统动态库的路径, 如果你提供的是一个静态库,那我们只能将这个库静态链接到程序中;,如果你提供的是一个动态库,那我们只能将这个库动态链接到程序中

如果既想动态链接,又想静态链接,一般要提供两个版本的库文件

问:gcc默认是怎么链接

gcc优先是动态链接 并且是release版本!


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于部标JT808的车载视频监控需求与EasyCVR视频融合平台解决方案设计

一、方案背景 众所周知&#xff0c;在TSINGSEE青犀视频解决方案中&#xff0c;EasyCVR视频智能融合共享平台主要作为视频汇聚平台使用&#xff0c;不仅能兼容安防标准协议RTSP/Onvif、国标GB28181&#xff0c;互联网直播协议RTMP&#xff0c;私有协议海康SDK、大华SDK&#xf…

谷歌seo做的外链怎样更快被semrush识别

本文主要分享做谷歌seo外链如何能让semrush工具快速的记录并能查询到。 本文由光算创作&#xff0c;有可能会被剽窃和修改&#xff0c;我们佛系对待这种行为吧。 谷歌seo做的外链怎样更快被semrush识别&#xff1f; 答案是&#xff1a;多使用semrush搜索目标网站可加速爬虫抓…

SOLIDWORKS Premium 2023 SP1.0 三维设计绘图软件

SOLIDWORKS 中文完美正式版提供广泛工具来处理最复杂的问题,并提供深层技术完成关键细节工作。新功能可助您改善产品开发流程,以更快地将创新产品投入生产。Solidworks 是达索公司最新推出的三维CAD系统,它可让设计师大大缩短产品的设计时间,让产品得以快速、高效地投向市场…

2023年/2024届 暑期实习 【汇总+更新】

文章目录百度2024届暑期实习生招聘米哈游2023春季校园招聘正式启动&#xff08;含暑期实习&#xff09;拼多多2024届暑期实习生招聘百度2024届暑期实习生招聘 百度2023届校园招聘春季补录仍在持续进行中&#xff0c;本周日&#xff08;3月5日&#xff09;截止网申&#xff0c;…

ARM基础

文章目录1.ARM成长史1.1 ARM发展的里程碑11.2 ARM发展的里程碑21.3 ARM发展的里程碑31.4 ARM发展的里程碑42.ARM的商业模式和生态系统3.先搞清楚各种版本号3.1 ARM 的型号命名问题3.2 ARM 的几种版本号3.3 ARM型号的发展历程4.SoC和CPU的区别 & 外设概念的引入4.1 SoC和CPU…

面试问到不会的技术问题?大小公司?程序员、校招面试技巧

大家好&#xff0c;欢迎来到停止重构的频道。本期我们分享一下程序员面试的相关经验。可能是3月离职高峰&#xff0c;又或者毕业生准备找工作的缘故&#xff0c;最近有一些朋友问我们关于面试方面的经验。问题五花八门&#xff1a;面试总是紧张&#xff1f;项目、工作经验怎么介…

2023功能测试真的没有出路了吗?不会自动化测试的我留下了悔恨的泪水...

直接抛出我的结论&#xff1a;手工做业务类测试&#xff0c;没有前途。10K的工资已经是天花板 个人建议赶紧从业务测试跳出来&#xff0c;立即学习代码&#xff0c;走自动化测试方向。目前趋势&#xff0c;业务测试需要用自动化做。 为了让大家能够信服我的观点&#xff0c;本…

python-爬虫-字体加密

直接点 某8网 https://*****.b*b.h*****y*8*.com/ 具体网址格式就是这样的但是为了安全起见,我就这样打码了. 抛出问题 我们看到这个号码是在页面上正常显示的 F12 又是这样就比较麻烦,不能直接获取.用requests库也是获取不到正常想要的 源码的,因为字体加密了. 查看页面源代码…

开发一个会员管理系统

背景 由于现在公司内客户量剧增&#xff0c; 简单的靠电话及笔记本记录&#xff0c;来维护客户有些困难&#xff0c;但又不想去花钱购买那些专业版的会员管理系统&#xff0c;只能自己动手撸一个相对简易的会员系统来使用了。 开发语言及使用技术 后端&#xff1a;java、mys…

滑动窗口(同向)同向双指针 leetcode713 3 1004 1234

同向双指针的理解 双指针从同一侧开始走一般是right进行无脑遍历&#xff0c;left控制边界&#xff08;导致模板化&#xff09;深刻理解题目概念以及**&#xff08;right - left 1&#xff09;** 的含义多思考画图 模板 class Solution { public:int numSubarrayProductLess…

NLP中一些工具列举

文章目录StanfordcoreNLPStanzaTankitspaCySuPar总结StanfordcoreNLP 这个老早就出来了&#xff0c;用java写的&#xff0c;但是已经有很多比他效果好的了。 Stanza 2020ACL发表的&#xff0c;看名字就知道和上一个是同一家的。 用已经切好词的句子进行依存分析。 这个功能…

百度“文心一言”携手酷开科技,实现AI智能领域新突破!

进入21世纪&#xff0c;AI人工智能一直都是讨论度非常高的话题之一&#xff0c;各行各业的领导者都开始在智能领域进行了初步探索&#xff0c;这也证明了AI人工智能在未来一定会在很大程度上影响我们的生活、工作。 近日&#xff0c;深圳市酷开网络科技股份有限公司成为百度文…

Kuangbin 线性DP 最大和加强加强版

呃呃&#xff0c;一道题写了我一下午4546. 最大和加强加强版 - AcWing题库题意&#xff1a;思路&#xff1a;首先这道题没有明显的阶段&#xff0c;因此状态设计不能按照阶段去设计我们按照题目给的量去设计状态&#xff1a;设dp[i][j]为考虑前i个数分为j组的最大可能和如果这样…

百度前端二面vue面试题指南

Vue 组件间通信有哪几种方式&#xff1f; ​ Vue 组件间通信是面试常考的知识点之一&#xff0c;这题有点类似于开放题&#xff0c;你回答出越多方法当然越加分&#xff0c;表明你对 Vue 掌握的越熟练。Vue 组件间通信只要指以下 3 类通信&#xff1a;父子组件通信、隔代组件通…

5个好用的视频素材网站

推荐五个高质量视频素材网站&#xff0c;免费、可商用&#xff0c;赶紧收藏起来&#xff01; 1、菜鸟图库 视频素材下载_mp4视频大全 - 菜鸟图库 网站素材非常丰富&#xff0c;有平面、UI、电商、办公、视频、音频等相关素材&#xff0c;视频素材质量很高&#xff0c;全部都是…

Java——异常

目录 什么是异常 异常处理主要的5个关键字 异常的体系结构 异常语法 异常的分类 异常的处理流程 异常的处理 防御式编程 异常的抛出 throw的注意事项 异常的捕获 异常声明throws try-catch捕获处理 finally 自定义异常类 throw和throws区别 什么是异常 程序在运行时出现错…

什么情况下Java程序会产生死锁?如何定位、修复?

第18讲 | 什么情况下Java程序会产生死锁&#xff1f;如何定位、修复&#xff1f; 今天&#xff0c;我会介绍一些日常开发中类似线程死锁等问题的排查经验&#xff0c;并选择一两个我自己修复过或者诊断过的核心类库死锁问题作为例子&#xff0c;希望不仅能在面试时&#xff0c;…

NOC2021年测试卷1

一、单项选择题(共15题,每题3分,共45分) 1.下列应用不能体现人工智能技术的是()。 A、使用语音输入法输入文字B、使用OCR软件从图像中识别汉字C、某软件支持在线中英文互译D、某网站自动统计歌曲下载次数2.点击绿旗执行图中的脚本,若角色的坐标为 (25, 20) ,则说出的内…

元数据管理实践数据血缘

元数据管理实践&数据血缘 什么是元数据&#xff1f;元数据MetaData狭义的解释是用来描述数据的数据&#xff0c;广义的来看&#xff0c;除了业务逻辑直接读写处理的那些业务数据&#xff0c;所有其它用来维持整个系统运转所需的信息&#xff0f;数据都可以叫作元数据。比如…

微服务一 实用篇 - 2. SpringCloud02

《微服务一 实用篇 - 2. SpringCloud02》 提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!! 《微服务一 实用篇 - 2. SpringCloud02》《微服务一 实用篇 - 2. SpringCloud02》1.Nacos配置管理1.1.统一配置管理1.1.1.在nacos中添加配置文件1.1.2.从微服务拉取…