Gcc编译总结
Gcc编译总结
(参考http://blog.chinaunix.net/u/18537/showart_139343.html)
前一段时间在学习C语言编程时,程序编写完成后用Gcc进行编译,当时编写的程序比较简单,例如程序:
只要在终端输入
即可完成编译,如果没有错误和警告,再输入
即可执行程序并输出结果。
实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和连接(Linking)。
1.1 预处理
运行预处理命令:
可 以输出test.i文件中存放着test.c经预处理之后的代码。打开test.i文件,看一看,就明白了。后面那条指令,是直接在命令行窗口中输出预处 理后的代码,而不是以文件作为输出设备。gcc的-E选项,可以让编译器在预处理后停止,并输出预处理结果。在本例中,预处理结果就是将stdio.h 文件中的内容插入到test.c中了。gcc的-o选项,用于输出处理结果到文件中。
1.2 编译为汇编代码
预处理之后,可直接对生成的test.i文件编译,生成汇编代码:
gcc的-S选项,表示在程序编译期间,在生成汇编代码后,停止,-o输出汇编代码文件。
生成的汇编代码如下:
.section .rodata
.align 4
.LC0:
.string "Hello World,Linux programming!"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.0 20060304 (Red Hat 4.1.0-3)"
.section .note.GNU-stack,"",@progbits
1.3 汇编(Assembly)
如果你学过汇编语言,那么你就该知道程序编译到了这个地步,应当使用汇编器,将汇编语言翻译为机器代码了。这一步尤其重要,因为它决定了你生成的程序,能够运行在哪种机器上。gcc使用的汇编器是gas。
在Intel IA-32平台上,还有一些常用的汇编器有:
- 微软的MASM,这是Intel平台上所有汇编器的鼻祖了,它现在已不是微软的独立产品,只是与Visual Studio捆绑在一起。但微软允许其他组织免费分发MASM 6.0。
- NASM,最初是为UNIX环境开发的商业汇编器,最近成为开源的了,可生成UNIX、MS-DOS和32位Windows格式的可执行文件。
- HLA(high level assembler)是Randall Hyde教授创建的,可以在DOS、Windows和Linux操作系统上生成Intel指令码。但HLA设计的主要目的是向初级程序员讲授汇编语言,学院气太浓,不够实用。
与这些汇编器相比,gas可以在不同处理器平台上工作,通常它可以自动检测底层硬件平台并生成适合该平台的正确机器指令码。gas另一个特性是能够创建不同于程序设计所在平台的指令码,譬如我在Intel计算机上工作,但可以为MIPS计算机写程序。
对于上一小节中生成的汇编代码文件test.s,gas汇编器负责将其编译为目标文件,如下:
1.4 连接
gcc连接器是gas提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。附加的目标文件包括静态连接库和动态连接库。
对于上一小节中生成的test.o,将其与C标准输入输出库进行连接,最终生成程序test:
在命令行窗口中,运行test这个小程序,让它说HelloWorld吧!
后来看到师哥们在编译一些程序时使用了makefile文件(对于makefile文件我已经在我的“C语言笔记”中的《makefile文件》一文中总结过),其中的编译语句又是-l,-L,又是什么路径等等,向师哥请教后才知道他们的程序中用到了其它的头文件或库文件。
于是我进一步查阅了相关资料,原来在Linux下开发软件时,完全不使用第三方函数库的情况是比较少见的,通常来讲都需要借助一个或多个函数库的支持才能够完成相应的功能。从程序员的角度看,函数库实际上就是一些头文件(.h)和库文件(.so或者.a)的集合。虽然Linux下的大多数函数都默认将头文件放到/usr/include/目录下,而库文件则放到/usr/lib/目录下,但并不是所有的情况都是这样。正因如此,GCC在编译时必须有自己的办法来查找所需要的头文件和库文件。
Gcc采用搜索目录的办法来查找所需要的文件,-I选项可以向Gcc的头文件搜索路径中添加新的目录。例如,如果在/home/xiaowp/include/ 目录下有连接所需要的头文件,为了让Gcc能够顺利地找到它们,就可以使用-I选项:
-
gcc foo.c -I /home/xiaowp/include -o foo
-
gcc foo.c -L /home/xiaowp/lib -lfoo -o foo
-
gcc foo.c -L /home/xiaowp/lib -static -lfoo -o foo