来自于《后台开发: 核心技术与应用实践》
1.1 预处理
g++ -E helloworld.cpp -o helloworld.i
-E
: 只进行预处理
1.1.1 删除 #define
- 第一步 删除所有#define, 展开所有宏定义;
1.1.2 处理所有条件预编译指令
- 比如
#if , #ifdef, #elif, #else, #endif
1.1.3 处理#include指令
- 将被包含的文件插入到该预编译指令的位置;
- 递归进行的;
1.1.4 过滤所有的注释 //,/**/
1.1.5 添加行号和文件名标识
- 以便于编译时编译器产生调试用的行的信息以及编译时产生编译错误或警告是能够显示行号
1.1.6 保留所有的#pragma 编译指令
- 因为编译器需要使用它们
1.2 编译
g++ -S helloworld.i -o helloworld.s
-S
(大写): 只执行到源代码到汇编代码的转换编译过程为六步:
- 词法分析
- 语法分析
- 语义分析
- 源代码优化
- 代码生成
- 目标代码优化
1.3 链接
- 重定位入口
1.3.1 静态链接
- 编译时期完成的链接;
g++ -c add.cpp
g++ -c sub.cpp
-c
: 只执行到编译,输出目标文件- 生成
add.o ,sub.o
文件
静态链接库:
ar cr libmy.a sub.o add.o
- 生成libmy.a 文件
ar
: 显示库文件 中的.o 文件ar 选项 c
: 在库中插入模块(替换),当库中的模块存在,就替换同名的模块;如果插入的模块不存在,ar显示错误信息;默认新的成员添加库的末尾;ar 选项 r
:创建一个库,不管库是否存在;ar 选项 tv
:ar tv xx.a
,可以查看库中包含哪些目标文件模块;
将静态库连接到程序中,
g++ -o main main.cpp -L. -lmylib
-L.
: 标记告诉G++函数库可能位于当前目录-lmylib
:连接库 mylib
最终生成main文件
1.3.2 动态链接
- 程序运行时的链接;
- 扩展名为
.so
;
例子:
四个文件:
add.h add.cpp, sub.h , sub.cpp, main.cpp
生成动态库文件:
g++ -fPIC -o add.o -c add.cpp
g++ -fPIC -o sub.o -c sub.cpp
g++ -shared -o libmymath.so add.o sub.o
fPIC
: 表示编译为位置独立的代码:不用此选项编译后的代码是位置相关的,所以动态载入时通过代码复制的方式来满足不用进程的需要,不能达到真正代码段共享的目的;Lpath
: 表示在path目标中搜索库文件,如-L.
:表示在当前目标Ipath
: 表示在path目标搜索头文件Itest
: 编译器查找动态链接库时隐含的命名规则,即在给出的名字前面加上lib, 后面加上.so来确定库的名称;链接库找不到问题
- 动态库与静态库重名问题
- 静态库和动态库的特点
- 动态库有利于进程间资源共享;
- 程序升级变得简单;静态库需要重新编译
- 链接载入完成有程序员在程序代码中控制;
- 静态库速度快
1.4 g++ 和gcc的区别
1.4.1 后缀 .c
和cpp
- gcc: 当做c程序
- g++ : 当做c++程序
cpp
:都当做c++程序,并且语法规则检查严格;
1.4.2 编译阶段
- g++ 调用gcc : 对于c++代码,两个等价,但是 gcc不过自动和c++程序使用的库连接,所有使用g++完成链接;