文章目录
- 动静态库的基本原理
- 认识动静态库
- 动静态库的特性
- 手动安装静态库
动静态库的基本原理
首先,文件和头文件最终变成一个可执行程序需要经历以下四个步骤:
1)预处理:预处理所要完成的有,头文件展开、去注释、宏替换、条件编译。C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令“#include”、宏定义命令“#define”、条件编译命令“#if”、“#ifdef”等。预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些东西输出到.i文件中等待进一步处理,最终形成xxx.i
文件。
2)编译:完成词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,最终形成xxx.s
文件。
3)汇编:汇编代码转为二进制目标代码(机器语言),形成.obj
的文件。
4)链接:将汇编过程产生的二进制代码进行链接,即上述过程产生的.obj文件和系统库的obj文件链接起来,最终生成了可以在特定平台运行的可执行文件。
例如,用test1.c以及main1.c形成可执行文件,我们需要先得到各个文件的目标文件test1.o、以及main1.o,然后再将这写目标文件链接起来,最终形成一个可执行程序。而实际上,对于可能频繁用到的源文件,像test1.c、test2.c、test3.c,我们可以将它们的目标文件test1.o、test2.o、test3.o进行打包,之后需要用到这四个目标文件时就可以直接链接这个包当中的目标文件了,而这个包实际上就可以称之为一个库。
总结:实际上,所有库本质都是一堆目标文件(xxx.o)的集合,动静态库的本质是可执行程序的“半成品”。
认识动静态库
问题:我们为什么能在Linux下完成C/C++代码的编译呢?
答:因为Linux已经默认携带了语言级别的头文件和语言对应的库。
在命令行输入如下命令,我们就可以看到Linux中的很多库:
在这里涉及到一个重要的概念:函数库
- 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?
- 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。
函数库一般分为静态库和动态库两种。
接下里我进行演示,首先,我们先touch创建一个测试文件,我暂且将其命名为test.c,然后我们利用vim编辑器命令,编辑文件,我在test.c文件写入了以下代码:vim的使用详解请点击这里
这是最简单的代码,默认生成a.out执行程序,运行结果大家也都知道,就是hello world。
接下来我们就通过这份简单的代码踏入动静态库的大门
在Linux下我们通过ldd 文件名
来查看一个可执行程序所依赖的库
其中libc.so.6就是该可执行程序所依赖的库文件,通过命令ll -a,不难发现libc.so.6实际上是一个软链接。
gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。
通过上述的file 文件名
命令,我们可以看到a.out这个可执行程序是动态链接的,用的是一个共享库,准确来说,还是一个动态库。
补充说明:
- 在Linux中,以
.so
为后缀的是动态库,以.a
为后缀的是静态库。 - 在Windows中,以
.dll
为后缀的是动态库,以.lib
为后缀的是静态库。
这里的可执行程序所依赖的lib.so.6实际上就是C动态库,当我们去掉一个动静态库的前缀lib,再去掉后缀,剩下的就是这个库的名字,即c库。
注意Linux下gcc/g++编译器默认都是动态链接,若我们向静态链接,就要加上一个-static
选项,命令以及运行结果如下图:
此时生成的可执行程序就是静态链接的,从命令的运行结果可以发现,静态链接生成的可执行程序大小比动态链接生成的可执行程序大小大很多。
我们用ldd mytest-s 想查看这个静态链接的程序所依赖的库,结果是无。所以静态链接所生成的可执行程序不依赖库,并且我们用file查看文件信息,结果显示它是静态链接的。
动静态库的特性
1.库分为静态库(专门让编译器,对用户程序进行静态链接的) 和 动态库(专门让编译器,对用户程序进行动态链接的)。
2.静态库和静态链接:链接的时候,如果是静态链接,找到静态库,拷贝静态库中我所需要的代码到我的可执行程序中。
3.动态库和动态链接:链接的时候,如果是动态链接,找到动态库,拷贝动态库中我所需要的代码的地址到我们自己的可执行程序中相关的位置。
4.静态链接成功:我们的程序,不依赖任何库,自己就可以独立运行。
5.动态链接成功:我们的程序,还是依赖动态库,一旦动态库缺失,我们的程序便无法运行!
6.静态库:因为自身的拷贝问题,比较浪费空间。
7.动态库:因为可以做到被大家共享方法,所以真正的函数实现永远都是在库中,程序内部只有地址,当程序需要时,在链接阶段直接通过地址进行跳转,跳转到动态库进行执行,执行完再回来,所以比较节省空间。
8.静态库vs动态库:Linux默认使用的是动态链接和动态库。
手动安装静态库
查看libc.a是否已经安装:
sudo find / -name 'libc.a'
安装静态库:
sudo yum install -y glibc-static
安装g++:
sudo yum install -y gcc-g++
安装c++静态库:
sudo yum install -y libstdc++-static