一、编译流程
一个C程序从源代码到可执行程序一共有四个过程:预处理->编译->汇编->链接
| 次序 | 执行流程 | 功能 | GCC命令 |
|---|---|---|---|
| 1 | 预处理 | 展开头文件、宏替换、去掉注释、条件编译 | gcc - E main.c - o main.i |
| 2 | 编译 | 检查语法,生成汇编程序 | gcc - S main.i - o main.s |
| 3 | 汇编 | 汇编代码转换为机器码 | gcc - c hello.s - o main.o |
| 4 | 链接 | 链接各个文件一起生成可执行文件 | gcc main.o - o main |
1. 预处理
预处理就是在C语言源文件和头文件中的所有以#开始的行,都属于预处理的范畴,预处理命令一般有一下几种:
| 类别 | 符号 | 主要作用 |
|---|---|---|
| 宏定义 | #define,#undef,#include | 基本上即使做字符替换 |
| 条件编译 | #if,#else,#elif,#endif,#ifdef,#ifndef | 和C语言的分支语句一样,不过这个告知编译器的 |
| 信息输出 | #error,#warning | 分别输出错误级别信息和警告级别信息 |
| 设置 | #line,#pragma | 向编译器发送一些指令 |
二、命令选项
o小写
指定生成(输出)文件名称,如: gcc -o helloworld helloworld.c.
O大写
编译器的优化选项,格式为-On(n=0,1,2,3),默认为1,0表示不优化,3表示最高优化级别
I
指定源文件所需要引用的头文件 目录(可以是相对路径), 如:gcc -I./include test.c*
l小写
指定需要链接的库文件(去掉前缀lib和文件名后缀.so,.a)。
如:
root@seven:~/projects/test# ls
hello.c hello.o liblog.so liblog.a libtest.so
libtest.a
root@seven:~/projects/test# gcc -o helo -llog -ltest -L./ hello.o
注:
当同一目录同时存在静态库和动态库时,GCC默认链接动态库;
当静态库和动态库在不同目录下时,先检索到哪个库就链接哪个库。
L大写
指定非系统库文件路径之外的库路径。
D
指定通过命令行定义宏:-D<maro> | -D<maro>=value,可以用来在不修改源码的情况下编译不同版本的固件。
如:
root@seven:~/projects/gcc# ls
gcc_test.c
root@seven:~/projects/gcc#
root@seven:~/projects/gcc# cat gcc_test.c
#include <stdio.h>
#if defined(Debug)
#define clog(format, ...) printf(format, ##__VA_ARGS__)
#else
#define clog(format, ...)
#endif // defined(Debug)#ifndef Num
#define Num 100
#endif // !Numint main(int argc, char **argv)
{printf("gcc test %d\n", Num);clog("Debug bin\n");return 0;
}
root@seven:~/projects/gcc# gcc -o gcc_rc gcc_test.c
root@seven:~/projects/gcc# gcc -DNum=1 -o gcc_rc1 gcc_test.c
root@seven:~/projects/gcc# gcc -DDebug -o gcc_dbg gcc_test.c
root@seven:~/projects/gcc# ./gcc_rc
gcc test 100
root@seven:~/projects/gcc# ./gcc_rc1
gcc test 1
root@seven:~/projects/gcc# ./gcc_dbg
gcc test 100
Debug bin
X
指明使用的编程语言。允许的语言包括:c c++ assembler none 。 none意味着恢复默认行为,即根据文件的扩展名猜测源文件的语言。
E
仅进行预处理,不生成文档,会将信息直接打印到终端。
S
只进行预处理和编译,把文档编译成汇编代码,并生成"*.s"文件。
c小写
进行预处理,编译和汇编,生成Object文件。
C大写
在预处理时,不删除注释信息,一般和E一起使用,用于分析源码
w小写
禁止显示所有警告信息。
W大写
显示指定警告信息
格式为: -W<option1>,<option2>
| options | 说明 |
|---|---|
| all | 打开一些默认的警告项 |
| error | 将警告视为错误 |
| extra | 打印一些额外的警告信息 |
| pointer-arith | 对函数指针或void *类型指针进行算术操作时,发出警告 |
| shadow | 当一个局部变量遮盖住另一个局部变量,或者全局变量时,发出警告 |
| undef | 当一个没有定义的符号出现在 #if 后时,发出警告 |
| redundant-decls | 同一作用域内某定义多次声明,发出警告 |
| … | … |
ansi
支持符合ANSI标准的C程序。这样就会关闭GNU C中某些不兼容ANSI C的特性。
std
指定遵守的语言标准
| 标准 |
|---|
| c89 |
| c99 |
| c11 |
| gnu99 |
| gnu11 |
| c++98 |
| c++11 |
| c++14 |
| c++17 |
| gnu11 ++98 |
| gnu11 ++11 |
| gnu11 ++14 |
| … |
使用示例
生成可执行文件
最基础的就是直接使用命令gcc 然后将所有的C文件名作为参数输入
root@seven:~/projects/test# gcc -o test test_1.c test_2.c test_3.c
生成库文件
库的生成和可执行文件的生成基本一致,只是最后的链接阶段有些许差异。
动态库的生成
root@seven:~/projects/test# gcc -c hello.c -o hello.o
root@seven:~/projects/test# gcc -fPIC -shared -o libtest.so test.c
静态库的生成
root@seven:~/projects/test# gcc -c hello.c -o hello.o
root@seven:~/projects/test# ar cqs libhello.a hello.o