GCC编译流程
#include<stdio.h> int main() { printf("Hello world !\n"); return 0; }
1.预处理阶段
[ht@localhost hello]$ gcc -E hello.c -o hello.i
Gcc进行预处理,把“stdio.h”的内容插入到hello.i文件中。
2.编译阶段
[ht@localhost hello]$ gcc -S hello.i -o hello.s
.file "hello.c" .section .rodata .LC0: .string "Hello world !" .text .globl main .type main, @function main: .LFB0: .cfi_startproc leal 4(%esp), %ecx .cfi_def_cfa 1, 0 andl $-16, %esp pushl -4(%ecx) pushl %ebp .cfi_escape 0x10,0x5,0x2,0x75,0 movl %esp, %ebp pushl %ecx .cfi_escape 0xf,0x3,0x75,0x7c,0x6 subl $4, %esp subl $12, %esp pushl $.LC0 call puts addl $16, %esp movl $0, %eax movl -4(%ebp), %ecx .cfi_def_cfa 1, 0 leave .cfi_restore 5 leal -4(%ecx), %esp .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (GNU) 4.9.2 20141101 (Red Hat 4.9.2-1)" .section .note.GNU-stack,"",@progbits
3.汇编阶段
[ht@localhost hello]$ gcc -c hello.s -o hello.o
4.链接阶段
[ht@localhost hello]$ gcc hello.o -o hello
[ht@localhost hello]$ ls
hello hello.c hello.i hello.o hello.s
[ht@localhost hello]$ ./hello
Hello world !
系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,Gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。函数库一般分为静态库和动态库两种。静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的libc.so.6就是动态库。Gcc在编译时默认使用动态库。
比如 -I dir
/*hello.h*/ #ifndef _HELLO_H #define _HELLO_H #include <stdio.h> #endif
/*hello.c*/ #include<hello.h> int main() { printf("Hello world !\n"); return 0; }
[ht@localhost hello]$ gcc hello.c -I /home/ht/MYCODE/hello/ -o hello
在include语句中,“<>”表示在标准路径中搜索头文件,““””表示在本目录中搜索。故在上例中,可把hello.c的“#include<hello.h>”改为“#include “hello.h””,就不需要加上“-I”选项了。