6.1 gcc(GNU Compiler Collection)编译系统
6.1.1 文件名后缀
文件名后缀 | 文件类型 |
---|---|
.c | C源文件 |
.i | 预处理后的C源文件 |
.ii | 预处理后的c++源文件 |
.m | Objective—C 源文件 |
.mi | 预处理后的Objective—C源文件 |
.h | 头文件 |
.C .cc .cp .cpp .c++ .cxx | C++源文件 |
.F .fpp .FPP | FORTRAN源文件 |
.s | 汇编程序文件 |
.S | 必须预处理的汇编程序文件 |
.o | 目标文件 |
.a | 静态链接库 |
.so | 动态链接库 |
6.1.2 C语言编译过程
注:一个完整的C语言程序可以存放在多个文件中,包括C语言源文件(.c)、头文件(.h)及库文件(.a/.so)。
1.预处理阶段
主要步骤:读取C语言源文件,对“#”开头的指令(伪指令)和特殊字符进行处理。*伪指令主要包括文件包含、宏定义和条件编译指令。
/*文件包含的两种形式*/
#include<文件名> //预处理程序在“/usr/include”寻找该文件
#include"文件名"//预处理程序在当前工作目录寻找该文件
指令的一般格式
gcc [选项] 要编译的文件 [选项] [目标文件]
//例
gcc –E hello.c –o hello.i//预处理后的C源文件
//-E的作用是让gcc在预处理结束后停止编译过程
2.编译阶段
主要步骤:对预处理后的输出文件进行词法分析和语法分析;
指令的一般格式
gcc [选项] 要编译的文件 [选项] [目标文件]
//例
gcc –S hello.i –o hello.s//编译后的编译代码
//-S的作用是只进行编译而不进行汇编
3.汇编过程
主要步骤:汇编程序把汇编语言代码翻译成目标机器代码;
指令的一般格式
gcc [选项] 要编译的文件 [选项] [目标文件]
//例
gcc –c hello.s –o hello.o //汇编后的目标代码
//-c的作用将汇编代码转化为目标代码
4.连接过程
主要步骤:将文件中引用的符号(如变量或函数调用)与该符号在另一个文件中的定义连接起来;
连接过程主要解决外部符号访问地址的问题;
连接模式 | 功能 |
---|---|
静态连接 | 在编译时把函数代码从其所在目标的静态链接库(.a)或归档库文件中复制到可执行文件中; |
动态连接 | 将函数代码放入动态链接库(.so)或共享对象的某个目标文件中,在可执行文件中只是记录共享对象的名字及其他少量相关信息; |
注:gcc在连接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库;
指令的一般格式
gcc [选项] 要编译的文件 [选项] [目标文件]
//例
gcc hello.o –o hello//连接后的可执行文件
//-c的作用将汇编代码转化为目标代码
6.1.3 gcc 命令行选项
1.预处理选项
选项格式 | 功能 |
---|---|
-C | 在预处理后的输出中保留源文件中的注释 |
-D name 或 -D name=definition | 定义一个宏name,其值为1 或 定义一个宏,并指定其值为definition |
-U name | 取消先前对name的定义,不管是内置还是-D选项提供的 |
-I dir | 指定搜索头文件的路径dir;若找不到在标准路径(/usr/include)上搜 |
-o file | 将输出写到file文件中 |
-E | 只对指定的文件进行预处理,不进行编译 |
2.编译程序选项
选项格式 | 功能 |
---|---|
-C | 只生成目标文件,不进行连接。用于对源文件的分别编译 |
-S | 只进行编译,不做汇编,生成汇编代码文件格式,其名与源文件相同,但扩展名为.s |
-o file | 将输出放在文件file中。如果未使用该选项,则可执行文件放在a.out中 |
-g | 指示编译程序在目标代码中加入供调试程序gdb使用的附加信息 |
-v | 在标准出错输出上显示编译阶段所执行的命令,即编译驱动程序及预处理程序的版本号 |
3.优化程序选项
优化分对中间代码的优化和针对目标代码生成的优化。
中间代码优化:与计算机无关
目标代码生成的优化:与机器硬件结构紧密相关
“-O”主要进行线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化
选项格式 | 功能 |
---|---|
-O -O1 | 试图减少代码大小和执行时间,但并不执行需要花费大量编译时间的任何优化 |
-O2 | 在-O1级别的优化之上,还进行一些额外调整工作——除不做循环展开、函数内联和寄存器重新命名外,几乎进行所有可选优化 |
-O3 | 除了完成所有-O2级别的优化之外,还进行包括循环展开和其他一些与处理器特性相关的优化工作 |
-O0 | 不执行优化 |
-Os | 具有-O2级别的优化,同时不特别增加代码大小 |
注:虽然优化选项可以加速代码的运行速度,但对于调试而言将是一个很大的挑战;
原先源程序中声明和使用的变量很可能不再使用,控制流可能会突然跳转到意外的地方,循环语句也可能因为循环展开而变得到处都有;
建议在调试的时候最好不使用任何优化选项,发行的时候才考虑;
4.连接程序选项
注:当编译程序将目标文件链成一个可执行文件时,用于连接的选项才起作用;
选项格式 | 功能 |
---|---|
object-file-name | 不用专用后续结尾的文件名就认为时是目标文件名或库名;连接程序可以根据文件内容来区分目标文件和库文件; |
-llibrary | 连接时搜索由library命名的库;(实际上库名为liblibrary.a/*.so) |
-static | 强制使用静态链接库,并阻止连接动态库; |
-Ldir | 把目录dir加到链接程序搜索库文件的路径表中,搜索时优先搜索dir路径,若不存在再到标准位置下搜索; |
-Bpredix | 规定在什么地方查找可执行文件、库文件、包含文件和编译程序本身的数据文件 |
Linux系统下库文件的命名:都以lib开头,文件后缀名为.a(静态库)或.so(动态库);
生成静态库的方法实际上可分为两步:
① 将各函数的源文件编译成目标文件 ;
② 使用ar工具将目标文件收集起来,放到一个归档文件中 ;