一、编译流程
一个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