【Linux】Linux动静态库链接:从原理到实战,彻底搞懂程序运行的“最后一公里“

欢迎来到 CILMY23 的博客

🏆本篇主题为:Linux动静态库链接:从原理到实战,彻底搞懂程序运行的"最后一公里"

🏆个人主页:CILMY23-CSDN博客

🏆系列专栏:C++ | C语言 | Linux | Python | 数据结构和算法 | 算法专题

🏆感谢观看,支持的可以给个一键三连,点赞收藏+评论。如果你觉得有帮助,还可以点点关注



库的"前世今生" —— 重新认识程序依赖

在C/C++编程中,链接(Linking) 是将多个目标文件(.o 或 .obj)和库文件(.a、.so、.lib、.dll 等)合并成一个可执行文件或共享库的过程。它是编译过程的最后一个阶段,由链接器(Linker) 完成,过去我们说编译链接,是在把我们的程序和库进行一个结合的过程,每个语言都有自己的标准库,一些函数在标准库中实现,我们可以在xshell上用 ldd 看到这个链接库。

 $ ldd hello.exe

在这里插入图片描述

通过这个指令,我们所链接形成的可执行文件所依赖的动态库就列出来了,我们重点关注第二项,这个libc.so.6就类似于快捷方式,是一个软链接,它指向了libc-2.17.so,这个库就包含了我们用的一些scanf,printf等等函数,我们称它为C标准库。

在这里插入图片描述
这个标准库的体积是非常大的,这是个纯二进制的文件。

在这里插入图片描述
所以平日里我们写程序时,就是把我们写的程序编译成可执行文件,和这个标准库进行链接,形成一个可执行程序。

我们可以把标准库比喻成图书馆,我们想去里面借书或者等等都得通过图书馆,然后实现自己的需求,但是我怎么知道图书馆里有啥呢?

所以头文件就是我们的使用手册,通过头文件我就知道图书馆里有什么。
所以就有了我们看到的头文件。

在这里插入图片描述

所以安装开发环境就是安装标准库和头文件,以及一个编译器。
如此,语言依赖我们的标准库,而标准库的使用得通过头文件进行阅读声明。

“链接的"量子纠缠” —— 运行时秘密

当你用gcc main.c -o app.exe 编译程序时,背后隐藏着怎样的魔法?为什么有些程序体积臃肿却运行稳定?为什么有些软件更新只需替换一个.so文件?这一切的答案,都藏在动静态库链接的奥秘中!

在Linux中,库又分为动态库和静态库,动态库的后缀是.so,静态库的后缀是.a,当然Linux和Windows是有差别的,Windows的动态库后缀是.dll,静态库是.lib。所以我们的链接方式又分为动态链接静态链接

动态链接(Dynamic Linking),把链接这个过程推迟到了运行时再进行,在可执行文件装载时或运行时,由操作系统的装载程序加载库,这里的库就是动态链接库。说白了,编译器只知道动态链接库的地址,当你需要用库的时候,你得找到动态库,才能进行链接,否则就没法链接。但是注意,动态库是共享的,一旦动态库缺失,所有动态链接这个库的程序都无法执行了。

那静态链接是由链接器在链接时将库的内容加入到可执行程序中的做法,在编译的时候,把库中的方法,拷贝到我自己的可执行程序中静态链接,不关心任何的库。

C动态库是默认提供的,gcc默认形成的可执行程序,默认采用动态链接。Linux当中的命令还是用C写的,除了ldd能看到链接库,file也能看到链接库。

 $ file hello.exe

hello.exe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=9abe2163acd325727cbcb29c4c1a0b4b77c6cd44, not stripped

我们可以看到,这是一个64位的执行文件,最重要的是dynamically linked (uses shared libs),动态链接,使用共享库。

庖丁解牛:动静态库的本质差异(表格对比)

特性静态库(.a)动态库(.so)
文件体积可执行文件体积大(库代码被完整复制)可执行文件体积小(仅存引用)
内存占用多进程重复加载库代码多进程共享同一份物理内存
更新维护需重新编译整个程序替换.so文件即刻生效
加载时机编译时链接运行时加载
典型应用场景嵌入式系统、独立工具大型软件、基础服务

所以对动态库最重要的就是不能丢失,它的最大优点就是节省资源,占用小,那静态库,就是一旦形成就和其他库无关了,但是会浪费资源。

库的"诞生仪式" —— 手把手创建实战

我们可以通过代码实现一下静态链接,输入以下指令我们会发现一些问题。

> $ gcc -o hello-static hello.c -static

/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status

当我们编译的时候发现,ld就是链接器,它表示找不到-lc,-l就表示要链接的,c就是指对应的库,默认情况上,Linux的静态库都是没安装的,所以我们要安装一下。

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

这两个都可以安装我们的静态库,第一条指令仅安装 glibc-static 一个软件包。它提供 GNU C 库(glibc)的静态链接库(.a 文件),用于编译完全静态的 C 程序。而第二条指令将同时安装 glibc-static 和 libstdc+±static 两个软件包。它额外提供 GNU C++ 标准库(libstdc++)的静态链接库(.a 文件),用于编译完全静态的 C++ 程序。

安装好后,我们就可以看到这里的静态链接库了。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值