解锁动静态库的神秘力量1:从代码片段到高效程序的蜕变

简介: 解锁动静态库的神秘力量1:从代码片段到高效程序的蜕变

一·库的含义及分类:
库是写好的现有的,成熟的,可以复⽤的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个⼈的代码都从零开始,因此库的存在意义⾮同寻常。

本质上来说库是⼀种可执⾏代码的⼆进制形式,可以被操作系统载⼊内存执⾏。库有两种:

静态库 .a[Linux]、.lib[windows] 动态库 .so[Linux]、.dll[windows]

也可以理解为.o系列文件集合打包;那么为啥需要库呢?

因为如果有多个.c文件或者很多都要复用这些,那么总是把它们一同编译就显得有点冗余了;因此不妨使用库。

假设没有库,对于一堆维.c文件我们就直接gcc一步处理成可执行程序,然后运行(. h必须要在当前目录否则找不到) :

下面我们来以一些测试代码带大家进行讲解工作:

1.1静态库的形成与使用:
下面我们从这两方面带大家理解静态库:

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

这里静态库是直接拷贝到可执行程序中,gcc找到后完成编译,程序就可以跑,不需要运行exe时系统再去找库,但是动态库需典 。

说白了就是静态库会把对应的那一堆.o文件拷贝进可执行文件(这里对于动态库就不行了,后面我们细讲)。

其次就是,我们静态库要有lib和以.a后缀,然而库名是去掉这些。

下面形成静态库需要这几步:

1·把全部.c文件编译成.o。

2·把.o文件都打包生成静态库。

3·使用静态库与目标文件链接形成可执行程序。

这样我们就生成了.o文件。

完成静态库的形成。

使用静态库去和其他文件链接:

这样就可以跑起来了:

其实也是非常简单的。

1.2动态库的形成与使用:
步骤和上面静态库的大差不大,只是有些地方需要改动一下:

这里的-fPIC也是不可少的:

形成动态库(注意这里库名后缀改成了so,此外还多加了-shared):

接下来我们就去链接了:

但是生成的可执行程序p不能运行?

下面我们来查看一下可执行程序的动态链接情况:

这里发现所要动态链接的动态库无法找到,为什么呢?
GCC!=系统;静态库,系统可以从EXE中找到但是动态库找不到 。

这是因为动态库并没有像静态库那样拷贝进p文件;而是动态连接;链接的时候只是告诉gcc了这个库的位置;而运行的时候是系统干的,它不知道动态库位詈。

那就引出了我们下面的工作,就是去帮助系统运行可执行文件的时候找到动态库。

二·系统如何查找动态库 :
下面我们分四中方法来完成帮助系统寻找工作:

2.1.拷贝到系统lib库:
这里我们首先要知道,系统在运行可执行文件的时候先去lib库内看看有没有这个库:

下面我们就查看一下系统的lib库:

找到后我们把当前路径的动态库文件拷贝进去:

然后我们再次运行:

这里一般我们安装程序等,系统都会采用这种方法把动态库装到lib库内。

2.2建立软链接:
之前博主出了一片Ext2文件系统的文章里面会对软硬链接有所介绍,不懂的朋友们可以去看一下,传送门:Ext2 文件系统:数字世界的基石,深度解码超时空存储魔法-CSDN博客

这里需要注意的是我们软链接的文件(没有就生成)必须与我们的库名一样,因为此刻系统在lib库找个库名;这样我们通过软链接的性质就得到了这个动态库。

2.3安置环境变量:
这里系统还会在它自己的环境变量:LD_LIBRARY_PATH中查找是否有有关动态库的路径;因此我们可以把此路径导入进去即可。

这样就能跑了;为了不干扰后面,我们在unlink掉:

2.4 ldconfig⽅案:
系统一开始还会往这里面的.conf文件里找看是否存在动态库的路径,并沿着路径找动态库 。

因此我们只需要加入一个.conf结尾的配置文件加入动态库的路径即可。

完成添加.conf配置文件并写入路径:

此时程序还是不能跑的,因为我们没有进行刷新配置文件;此刻调用ldconfig刷新一下:

三·一些有关小指令:
ldd +可执行文件 :查看可执行文件的动态链接情况

size +可执行文件:显示目标文件(包括可执行文件)中各个段(section)的大小,以及总的大小。这些段通常包括代码段(text)、数据段(data)、BSS 段(未初始化数据)等。

file+文件:file命令可以用于确定文件类型。它通过检查文件的内容(如文件头、魔数等)来判断文件是何种类型的可执行文件(例如是 ELF 格式的可执行文件、脚本文件还是其他格式)。

四·动静态库同时存在系统行为:
因此大家肯定有个疑问,如果动静态库同时存在且名字相同,那么系统默认会怎么做呢?下面演示一下:

这里报错是无法找到动态链接,故看来系统是默认动态链接了;因此系统优先考虑的是动态库;那么当我们安装程序等的时候系统也会优先对它进行动态库安装以及链接等。

如果我们就是想用动态的话;可以-static 强转一下:

这里就是告诉系统要用静态链接了。

五·目标文件分步编译和链接 :
肯定大家有个疑问,为什么把它们俩分开呢?

假设我们有大量.c文件都编译成了.o文件然后有个.c错了,我们只需要修改其中一个然后再搞成.o与其他大量.o文件进行链接就好;但是如果这两个过程在一起就麻烦了。

六·简单实现库的打包安装及使用:
下面我们以静态库为例演示压下(动态库只需要稍微变动一下即可):

Makefile文件:

libmy.a:print.o print2.o
@ar -rc $@ $^
%.o:%.c
@gcc -c $<
.PHONY:output
output:
@mkdir -p ku/head
@mkdir -p ku/lib
@cp -f .a ku/lib
@cp -f
.h ku/head
@tar -czf lib.tgz ku
@rm -rf ku
@rm -rf .a
.PHONY:clean
clean:
@rm -rf
.a *.o lib.tgz d/ku p

此时的我们:

下面我们来把静态库生成并且解压运行一下:

形成静态库:

打包成压缩包:

把它解压到d目录内:

静态库链接并执行:

清理工作:

本期分享结束了,但是动静态库系列并没有,下面我们就期待博主更新动静态库第二讲吧;欢迎大家阅读!!!

相关文章
|
Java
编程中最难的就是命名?这几招教你快速上手(4)
编程中最难的就是命名?这几招教你快速上手
107 0
编程中最难的就是命名?这几招教你快速上手(4)
|
1月前
|
存储 缓存 编译器
解锁动静态库的神秘力量2:从代码片段到高效程序的蜕变(续篇
解锁动静态库的神秘力量2:从代码片段到高效程序的蜕变(续篇
|
4月前
|
编译器 Linux C++
《C++跨平台编译:打破系统边界,释放代码潜能》
C++作为一门强大的编程语言,在多元化软件开发环境中面临跨平台编译的挑战。本文探讨了跨平台编译的重要性,包括拓宽用户群体和资源利用,以及面临的操作系统差异、编译器差异和依赖库问题。通过使用跨平台构建系统、抽象平台相关代码和管理依赖库等策略,可以有效应对这些挑战,提升软件的市场竞争力和资源利用效率。
125 0
|
6月前
|
存储 Java 开发者
【Java新纪元启航】JDK 22:解锁未命名变量与模式,让代码更简洁,思维更自由!
【9月更文挑战第7天】JDK 22带来的未命名变量与模式匹配的结合,是Java编程语言发展历程中的一个重要里程碑。它不仅简化了代码,提高了开发效率,更重要的是,它激发了我们对Java编程的新思考,让我们有机会以更加自由、更加创造性的方式解决问题。随着Java生态系统的不断演进,我们有理由相信,未来的Java将更加灵活、更加强大,为开发者们提供更加广阔的舞台。让我们携手并进,共同迎接Java新纪元的到来!
119 11
|
7月前
|
Rust 开发者
揭秘Rust编程:模块与包的终极对决,谁将主宰代码组织的新秩序?
【8月更文挑战第31天】在软件工程中,模块化设计能显著提升代码的可读性、可维护性和可重用性。Rust 作为现代系统编程语言,其模块和包管理机制为开发者提供了强有力的工具来组织代码。本文通过对比模块和包的概念及使用场景,探讨了 Rust 中的最佳实践。
86 2
|
7月前
|
调度 Android开发 开发者
【颠覆传统!】Kotlin协程魔法:解锁Android应用极速体验,带你领略多线程优化的无限魅力!
【8月更文挑战第12天】多线程对现代Android应用至关重要,能显著提升性能与体验。本文探讨Kotlin中的高效多线程实践。首先,理解主线程(UI线程)的角色,避免阻塞它。Kotlin协程作为轻量级线程,简化异步编程。示例展示了如何使用`kotlinx.coroutines`库创建协程,执行后台任务而不影响UI。此外,通过协程与Retrofit结合,实现了网络数据的异步加载,并安全地更新UI。协程不仅提高代码可读性,还能确保程序高效运行,不阻塞主线程,是构建高性能Android应用的关键。
99 4
|
7月前
|
编译器 开发工具 C语言
解锁QtCreator跨界神技!Windows下轻松驾驭OpenCV动态库,让你的跨平台开发如虎添翼,秒变视觉编程大师!
【8月更文挑战第4天】QtCreator是一款强大的跨平台IDE,便于创建多平台应用。本教程教你如何在Windows环境下集成OpenCV库至Qt项目。首先,下载匹配MinGW的OpenCV预编译版并解压。接着,在QtCreator中新建或打开项目,并在.pro文件中添加OpenCV的头文件和库文件路径。确保编译器设置正确。随后编写测试代码,例如加载和显示图片,并进行编译运行。完成这些步骤后,你就能在QtCreator中利用OpenCV进行图像处理开发了。
353 6
|
7月前
|
安全 Java Android开发
Kotlin字符串秘籍:解锁高效处理与创意应用,让你的代码闪耀不凡!
【8月更文挑战第2天】Kotlin是一门现代化的静态类型语言,以简洁、安全及强互操作性著称,在Android及服务器端开发中广受好评。本文通过与其他语言对比,深入解析Kotlin中字符串的基础和高级用法。Kotlin简化了字符串拼接,支持直接使用`+`操作符,并引入了直观的字符串模板。它提供了丰富的字符串操作函数,如使用索引范围进行子字符串提取,增强了代码的可读性。Kotlin字符串的不可变性提升了程序稳定性。利用扩展函数特性,可以轻松定制字符串行为,提高代码的模块化和重用性。掌握这些技巧能显著提升开发效率和代码质量。
78 1
|
7月前
|
数据处理 Python
解锁Python多线程编程魔法,告别漫长等待!让数据下载如飞,感受科技带来的速度与激情!
【8月更文挑战第22天】Python以简洁的语法和强大的库支持在多个领域大放异彩。尽管存在全局解释器锁(GIL),Python仍提供多线程支持,尤其适用于I/O密集型任务。通过一个多线程下载数据的例子,展示了如何使用`threading`模块创建多线程程序,并与单线程版本进行了性能对比。实验表明,多线程能显著减少总等待时间,但在CPU密集型任务上GIL可能会限制其性能提升。此案例帮助理解Python多线程的优势及其适用场景。
82 0
|
7月前
|
JavaScript 前端开发 安全
TypeScript:解锁JavaScript的超级英雄模式!类型系统如何化身守护神,拯救你的代码免于崩溃与混乱,戏剧性变革开发体验!
【8月更文挑战第22天】TypeScript作为JavaScript的超集,引入了强大的类型系统,提升了编程的安全性和效率。本文通过案例展示TypeScript如何增强JavaScript:1) 显式类型声明确保函数参数与返回值的准确性;2) 接口和类加强类型检查,保证对象结构符合预期;3) 泛型编程提高代码复用性和灵活性。这些特性共同推动了前端开发的标准化和规模化。
86 0