提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
国立西北农林专科学校的大一新生的笔记,希望有大佬能够指点指点
一、GCC是什么?
GCC(the GNU Compiler Collection)GCC是GNU编译器集合,它包括了C/C++、Objective-C、Fortran、Ada和Go语言的前端和对应的库(libstdc++)GCC初衷是为完全免费的GNU系统编写的编译器。
二、程序编译到运行的过程(CISO)
- 预处理(进行宏替换)
源代码_*.c/_*.cpp => 已预处理文件 __*.i
- 编译(生成汇编)
已预处理文件 __*.i => 汇编文件_*.s
- 汇编(生成机器可识别代码)
汇编文件_*.s => 目标文件_*.o
- 连接(生成可执行文件或库文件)
目标文件_*.o => 可执行或者库文件_*.exe/_*.so/_*.a
- 载入内存并链接依赖库(程序执行)
三、gcc如何完成
1|gcc [选项] [要编译的文件] [选项] [目标文件]
1.预处理 -E
预处理会做三件事情,为编译做准备:
- 宏变量替换
- 头文件展开
- 注释去除
1|gcc -E hello.c -o hello.i
执行完上面的预处理指令后,当前路径下就会多一个hello.i文件,我们进入并查看hello.i文件的内容。
预处理完后头文件被展开,所以文件多了800多行代码,并且注释被删除,宏被替换,条件编译已完成。
2.编译 -s
2|gcc -S hello.i -o hello.s
查看hello.s 仍然是个普通的文本文件,不过语言是汇编:
1 .file "hello.c"
2 .section .rodata
3 .LC0:
4 .string "hello world!"
5 .text
6 .globl main
7 .type main, @function
8 main:
9 .LFB0:
10 .cfi_startproc
11 pushq %rbp
12 .cfi_def_cfa_offset 16
13 .cfi_offset 6, -16
14 movq %rsp, %rbp
15 .cfi_def_cfa_register 6
16 movl $.LC0, %edi
17 call puts
18 movl $0, %eax
19 popq %rbp
20 .cfi_def_cfa 7, 8
21 ret
22 .cfi_endproc
23 .LFE0:
24 .size main, .-main
25 .ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
26 .section .note.GNU-stack,"",@progbits
~
3.汇编 -c
3|gcc -c hello.s -o hello.o
执行完上面的汇编指令后,当前路径下就会多一个hello.o文件(叫做 可重定向目标文件 ),我们进入并查看hello.o文件的内容。
这时,所有的代码就已经变成了二进制目标代码:
4.连接
4|gcc hello.o -o hello
执行完上面的链接指令后,当前路径下就会多一个hello文件(可执行程序),这时我们就可以运行此文件了
四. gcc 选项
option | meaning |
---|---|
-o | 指定生成的文件名 |
-E | 仅执行编译预处理 |
-S | 编译到汇编语言不进行汇编和链接。 |
-wall | 显示警告信息 |
-c | 仅执行编译操作,不进行连接操作 |
-g | 生成调试信息,不加选项 不能 进行 gdb调试 |
其他选项
-O0 | 不做任何优化,这是默认的编译选项。 |
-O1~3 | 使用编译优化级别1~3编译程序。 级别为1~3,级别越大优化效果越好,但编译时间越长 |
-w | 不生成任何警告信息。 |
-shared | 编译动态库时要用到 比如gcc -shared test.c -o libtest.so |
-l | -l选项(小写的 L)可以让我们手动添加链接库,-l参数紧接着就是库名。 如数学库的库文件名是libm.so,去掉库文件名的头lib和尾.so就是库名 ,即m。 |
-L | 该参数表示选择链接库的目录。 |
-I (大写的i) | -I参数是用来指定头文件目录,/usr/include目录一般是不用指定的,gcc知道去那里找,但是如果头文件不在/usr/include里我们就要用-I(大写的i)参数指定了。比如头文件放在/myinclude目录里,那编译命令行就要加上-I/myinclude参数了,如果不加你会得到一个”xxxx.h: No such file or directory”的错误。 |