目录
一. GCC的执行过程
GCC(GNU Compiler Collection)是一个开源的编译器套件,用于将高级编程语言(如C、C++等)的源代码转换为可执行的机器码。下面是GCC的执行过程简要描述:
预处理(Preprocessing):首先,GCC会对源代码进行预处理。在这个阶段,预处理器会处理以"#"开头的预处理指令,如#include、#define等,并将它们展开或替换为相应的内容。同时,还会去除注释、处理条件编译等。此阶段产生 .i文件
gcc -E hello.c -o hello.i
编译(Compilation):在编译阶段,GCC会将预处理后的源代码翻译成汇编代码。这个过程包括了词法分析、语法分析、语义分析等步骤,将代码转化为中间表示形式(如抽象语法树)。此阶段产生 .s文件
gcc -S hello.i -o hello.s
汇编(Assembly):在汇编阶段,GCC将汇编代码转换为机器码。它会将每条汇编指令翻译为对应的机器指令,并生成与目标平台相关的目标文件。此阶段产生 .o文件
gcc -c hello.s -o hello.o
链接(Linking):最后,GCC会将生成的目标文件与所需的库文件进行链接,生成最终的可执行文件。链接器会解析并处理函数调用、全局变量等符号引用,将各个目标文件和库文件组合在一起,生成可执行文件。此阶段产生可执行文件
gcc hello.o -o hello
二. 静态库
静态库是一种在编译链接阶段将库的代码直接嵌入到可执行文件中的库文件形式。它包含了预编译的对象文件,其中包括函数、类和其他可重用的代码片段。在程序运行时,不再需要额外加载静态库,因为所有需要的功能模块已经被链接到了可执行文件中。在Linux系统中,静态库以.a为后缀。在Window系统,静态库以.lib为后缀。
2.1 静态库的制作和使用
编写源代码:编写需要被打包为静态库的源代码,并将其编译成目标文件(.o文件)。
gcc -c test.c -o test.o
打包目标文件:将需要被打包的目标文件打包成一个静态库文件(.a文件)。
名字要求:libxxxx.a(需要这样的形式)
ar rcs libteststatic.a test.o
使用静态库:在其他程序中使用静态库时,需要在编译时链接静态库并包含相应的头文件。
gcc demo.c -I ./ -L ./ -lteststatic -o test
-I(i的大写): 用于指定头文件的搜索路径
-L: 用于指定静态库文件的搜索路径
-l(L的小写):用于指定需要链接的库文件,后面紧跟库文件名不需要包含文件扩展名.a 和 前缀"lib"。
-o: 用于指定生成的可执行文件的名称
三. 动态库
动态库是一种在运行时加载并链接的库文件形式。它包含了预编译的对象代码,其中包括函数、类和其他可重用的代码片段。动态库在程序运行时并不直接嵌入到可执行文件中,而是在程序运行时被动态加载到内存中。这意味着动态库可以被多个程序共享,从而减少了内存占用和磁盘空间的浪费。在Linux系统中,动态库以.so为后缀。在Windows系统中,动态库以.dll为后缀。
3.1 动态库的制作和使用
编写源代码:编写需要被打包为动态库的源代码,并将其编译成目标文件(.o文件)。
gcc -c -fPIC example.c -o example.o
打包目标文件:将需要被打包的目标文件打包成一个动态库文件(.so文件)。
名字要求:libxxxx.so(需要这样的形式)
gcc -shared example.o -o libexample.so
设置库路径:将生成的动态库所在的路径添加到系统的库搜索路径中。可以通过以下方式之一实现:
将动态库文件复制到系统的标准库目录(如
/usr/lib
或/usr/local/lib
)下。将动态库所在路径添加到
LD_LIBRARY_PATH
环境变量中,例如:export LD_LIBRARY_PATH=/path/to/library:$LD_LIBRARY_PATH
使用动态库:
gcc example.c -I ./ -L ./ -lexample -o program
四. 动态库与静态区的区别
动态库(Dynamic Library)和 静态库(Static Library)是两种不同的库文件形式,它们在使用和链接方式上有一些区别。
文件大小和内存占用:
- 动态库:动态库是一个独立的二进制文件,它在编译时生成,并在运行时被程序动态加载。因此,动态库不会被直接包含在可执行文件中,而是在运行时从磁盘加载到内存中。这意味着多个程序可以共享同一个动态库文件,从而减少了磁盘空间和内存的占用。
- 静态库:静态库是在编译时将库的目标代码与程序的目标代码合并成一个可执行文件。这意味着每个使用该静态库的程序都会包含一份完整的库代码,导致可执行文件的大小较大,并且每个程序都需要独立占用内存。
链接方式:
- 动态库:动态库在程序运行时才进行链接,也称为运行时链接。程序在启动时只会加载动态库的链接信息,当需要使用库中的函数或符号时,才会在内存中动态加载并链接动态库。这使得程序可以在运行时动态地加载、卸载和更新动态库。
- 静态库:静态库在程序编译时进行链接,也称为编译时链接。库的目标代码会被直接合并到可执行文件中,使得程序与静态库的代码成为一个整体。因此,静态库在程序运行之前就已经完成了链接,不需要依赖外部的库文件。
可移植性:
- 动态库:动态库提供了更好的可移植性,因为它们可以在不同的系统上共享使用。只要动态库文件的接口保持一致,程序可以在不同的操作系统和硬件平台上运行,而无需重新编译。
- 静态库:静态库的可移植性较差,因为它们与特定的编译环境和目标平台紧密相关。如果要在不同的系统上使用静态库,可能需要重新编译库文件以适应目标系统。