一文把c++的编译过程,以及动态库、静态库的来世今生讲清楚
两大编译主力
- GCC(GNU Compile Collection) 是一整套编译工具,包括了前端 (如gcc,g++) 和 后端工具
- 编译流程:C code —> GCC’s C frontend —> RTL —> GCC’s x86 backend —> x86 machine code
- clang + llvm 是 前端+后端的配,速度更快,性能更优,稳定性可能不如GCC
- 编译流程:Clang (C/C++ code —> LLVM IR) —> LLVM ( Optimization on IR —> LLVM’s x86 backend —> x86 machine code)
编译流程
讲的很好的知乎文章,包括了动态库如何使用
要把编译的四个流程和生成静态库、动态库分开考虑,这是三个不同的需求
预编译
处理#开头的代码
编译
编译是指把用高级语言编写的程序转换成相应处理器的汇编语言程序的过程。 从本质上讲,是一个文本翻译过程
1、词法分析:利用类似于“有限状态机”的算法,将源代码程序输入到扫描机中,将其中的字符序列分割成一系列的记号。
2、语法分析:语法分析器对由扫描器产生的记号,进行语法分析,产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树。
3、语义分析:语法分析器只是完成了对表达式语法层面的分析,语义分析器则对表达式是否有意义进行判断,其分析的语义是静态语义——在编译期能分期的语义,相对应的动态语义是在运行期才能确定的语义。
4、优化:源代码级别的一个优化过程。
5、目标代码生成:由代码生成器将中间代码转换成目标机器代码,生成一系列的代码序列——汇编语言表示。
6、目标代码优化:目标代码优化器对上述的目标机器代码进行优化:寻找合适的寻址方式、使用位移来替代乘法运算、删除多余的指令等。
汇编
把ASCII汇编代码文件*.s 汇编成可重定位目标文件*.o 本质上说,是把汇编代码生成二进制代码的过程
链接
- 通过编译和汇编,会把源文件变成一个个可重定位目标文件*.o
- 还可以加入之前已经生成好的静态库(.o文件的集合)和动态库
- 链接的作用就是把所有的这些目标文件链接起来,生成一个可执行文件
静态库与动态库
静态库和动态库都是目标文件,即都是二进制机器码文件
生成静态库
Step 1: 生成可重定位文件*.o, 不生成可执行文件
g++ -c func1.cpp
g++ -c func2.cpp
-c 参数:
Only run preprocess, compile, and assemble steps(即不生成可执行文件)
Step 2: 使用ar将可重定位文件打包成静态库*.a 注:静态库*.a其实是多个*.o文件的归档
ar crv libfunc.a func1.o func2.o # 静态库名称 lib[lib_name].a
生成动态库
g++ -fPIC -shared -o libmax.so max.c
- fPIC 是编译选项,PIC 是 Position Independent Code 的缩写,表示要生成位置无关的代码,这是动态库需要的特性
- shared 是链接选项,告诉gcc生成动态库而不是可执行文件。
静态库和动态库使用
静态库使用
使用静态链接,即在编译时链接静态库
动态库使用
两种使用方法
动态链接
在gcc编译参数中,要加上动态库
- 在生成可执行文件时,要静态完成一些链接
- 在程序加载时,完成整个动态链接过程
动态加载:
- 编译时无需加入动态库,在运行时要求动态链接器加载和链接
#include <dlfcn.h>
void *dlopen()
void *dlsym()
|