GUN gcc

一、GCC的介绍


GCCGNUCompilerCollectionGNU编译器集合)是一套由GNU工程开发的支持多种编程语言的编译器。GCC是自由软件发展过程中的著名例子,由自由软件基金会以GPL协议发布。GCC是大多数类Unix操作系统(如LinuxBSDMacOS X等)的标准的编译器,GCC同样适用于微软的WindowsGCC支持多种计算机体系芯片,如x86ARM,并已移植到其他多种硬件平台。GCC原名为GNU C编译器(GNU CCompiler),因为它原本只能处理C语言。GCC很快地扩展,并支持处理C++。后来又扩展能够支持更多编程语言,如FortranPascalObjective-CJavaAdaGo等。


二、GCC编译过程被分为四个阶段


gcc首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(incloude)、预编译语句进行分析。

接着调用ccl进行编译,这个阶段跟据输入文件生成以.o为后缀的目标文件。汇编过程就是针对汇编语言的步骤。

调用as进行工作,一般来讲,.S为后缀的汇编语言源代码文件和.s为后缀的汇编语言文件经过预编译和汇编之后会生成以.o为后缀的目标文件。

当所有的目标文件都生成以后,gcc就调用ld来完成最后关键性的工作,这个是阶段性的链接。在链接阶段,所有的目标文件被安排在可执行程序中的恰当位置,同时,该程序所调用到的库函数也从各自所在的库中连接到何时的地方。


三、GCC的基本用法


gcc的基本用法是:gcc [options] [filenames]

其中,options几十编译器所需要的参数,filenames给出相关的文件名称,最常用的有以下参数。

-c,只编译,不链接成为可执行文件。编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。

-ooutput_filename,确定输出文件的名称问output_filename。同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出默认的可执行文件a.out

-g,产生符号调试工具(GUNgdb)所必要的符号信息,要想对源代码进行调试,就必须加入这个选项。

-O,对程序进行优化编译、链接。采用这个选项,整个源代码会在编译、链接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是编译、链接的速度就会慢一些,而且对执行文件的调试会产生一些影响,造成一些执行效果对应源文件代码不一致等一些令人“困惑”的情况。因此,一般在编译输出软件发行版同时使用此选项。

-O2,比-O更好的优化编译、链接。当然整个编译。链接过程会更慢。

-Idirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。C程序中的头文件包含两种情况:

#incloud<stdio.h>

预处理程序cpp在系统默认包含文件目录(如/usr/incloud)中搜寻相应的文件。

#incloud”stdio.h”

cpp在当前目录中搜寻头文件,这个选项作用是告诉cpp,如果在当前目录中没有找到需要的文件,就到指定的dirname目录中去寻找。在程序设计中,如果需要的这种包含文件分别分布在不同的目录中,就需要逐个使用-I选项给出搜索路径。

-Ldirname,将dirname所指出的目录加入到程序函数库文件的目录列表中,是在链接过程中使用的参数,在默认情况下,链接程序ld在系统中的默认路径中(如/usr/lib)寻找所需要的库文件。这个选项告诉链接程序,首先到-L指定的目录中去寻找,然后到系统默认的路径中去需找,如果函数库存放在多个目录下,就需要依次使用这个选项,给出相应的存放目录。

-Iname,链接时装载名为libname.a的函数库。该函数库位于系统默认的目录或者由-L选项确定的目录下。

例如:

-Iname,链接时装载名为libname.a的函数库,该函数库位于系统默认的目录或者 -L选项确定的目录下,例如:-Im表示链接名为libm.a的数学函数库。

u例如:

cat test.c

#incloud < stidio.h >

int main(void)

{

printf("Hello Word,Linuxprogramming!\n");

return 0;

}

最简单的办法是:

gcc test.c –o test

首选需要调用预处理程序cpp,由它负责展开在源文件中定义的宏,并向其中插入“#incloud”语句包含的内容;接着,gcc调用cclas,将处理后的源代码编译成目标代码;最后,gcc调用链接程序ld,把生成的目标代码链接成一个可执行的程序,因此在默认情况下,预编译、编译链接一次完成。

四、编译过程分步执行

为了更好地理解gcc的工作过程,我们可以让在gcc工作的4个阶段中的任何一个阶段中停止下来。

-E 预编译后停止下来,生成后缀为.i的预编译文件;

-S 汇编后听下来,生成后缀为.s的汇编文件;

-c 编译后停下来,生成后缀为.o的目标文件;

可以把上述编译过程分为几个步骤单独进行,并观察每步的运行结果,第一步是进行预编译,使用–E参数可以让gcc在预处理结束后停止编译过程;

#gcc –E test.c –o test.i

gcc执行到预编译后停下来,生成test.i的预编译文件。此时若查看test.i文件中的内容,会发现stdio.h的内容却是都查到文件列表中去了,而其它应当被预处理的宏定义也都做了相应的处理,下一步是将test.i编译为目标代码,这样可以通过使用-c参数来完成:

#gcc –S test.c –o test.s

gcc执行到汇编后停止,生成test.s的汇编源文件,这是一个非常重要的中间件文件。因为在嵌入式系统中,受系统硬件自建的限制往往对目标文件的执行效率,文件大小都有要求,通过人工查看汇编文件有时往往可以找到问题所在进行人工优化。

最后一步是将生成的目标文件连接成可执行文件:

#gcc test.o –o test

对于稍微复杂的情况,比如有多个源码文件,需要链接库或者有其它比较特别的要求,就要给定调档的调用选项参数。