后缀名的说明:
.i 已经过预处理的C原始程序 .ii 已经过预处理的C++原始程序 .s/.S 汇编语言原始程序 .h 预处理文件(头文件) .o 目标文件 .a/.so 编译后的库文件 |
GCC编译流程分为4个步骤
1.
预处理(Preprocessing)
2.
编译(Compiling)
3.
汇编(Assembling)
4.
链接(Linking)
test.c
1 2 3 6 |
1.
预处理(Preprocessing):在这个阶段GCC将头文件包含进test.c文件,并生成文件test.i。
执行下面命令生成test.i:
[root@localhost gccinfo]# gcc -E test.c |
test.i的文件内容:
1 2 3 4 5 6 7 8 9 10 …………. 750 # 2 "test.c" 2 751 int main(void) 752 { 753 754 755 } |
2.
编译(Compiling):在这个阶段GCC检查test.i代码的规范性,确定有没有语法错误。确认无误后,则把test.i转化为汇编代码文件test.s。
执行下面命令生成test.s:
[root@localhost gccinfo]# gcc -S test.i |
test.s的文件内容:
1 .file "test.c" 3 6 8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
3.
汇编阶段(Assembling):在这个阶段GCC把test.s文件中的汇编代码转化为目标机器的机器代码文件test.o,为二进制文件。
执行下面命令生成test.o:
[root@localhost gccinfo]# gcc -c test.s |
执行以下命令产看test.o
[root@localhost gccinfo]# od -t c test.o |
test.o文件内容:
0000000 177 E 0000020 001 /0 003 0000040 354 /0 0000060 0000100 345 Q 203 354 004 307 004 $ 0000120 377 270 /0 0000140 0000160 C : 0000200 0000220 4 0000240 a b 0000260 0000300 0000320 a /0 0000340 0000360 * 0000420 0000440 0000460 0000500 0000520 020 /0 0000540 0000560 0000600 0000620 0000640 0000660 0000700 0000720 0000740 001 /0 0000760 0001000 0001020 0001040 0001060 003 /0 0001100 0001120 0001140 0001160 0001200 003 /0 0001220 022 /0 0001240 0001260 0001300 004 /0 361 377 0001320 003 /0 001 0001340 003 /0 003 0001360 003 /0 004 0001400 003 /0 005 0001420 003 /0 0001440 003 /0 006 0001460 022 /0 001 0001500 020 /0 0001520 0001540 031 /0 0001551 |
4.
链接(Linking):在成功编译之后,就进入了链接阶段。在这里涉及到一个重要的概念:函数库。重新查看这个小程序时,在这个程序中并没有定义“printf”的函数实现,且在预编译中包含进的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,Gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。
函数库一般分为静态库和动态库两种。静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a” 。动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。GCC 在编译时默认使用动态库。完成了链接之后,GCC 就可以生成可执行文件。
执行以下命令生成可执行文件test
[root@localhost gccinfo]# gcc test.o -o |
同时也可以通过od命令产看其内容。
以上4个编译步骤可以一次完成,执行下面命令即可:
[root@localhost gccinfo]# gcc test.c -o |
编译程序时,gcc会自动帮你连接所有编译的文件名及标准函数库. 首先GCC会把所有的原始文件都转成目标文件,然后会自动调用linker 来连接相关文件名(事实上linker是个文件名为ld的程序,而不是gcc 本身提供的功能,我们可以说gcc和ld的关系是相当密切的),GG同样 也知道标准函数库的位置,并且在调用ld时传入相关信息。