主要产品系列 
Microcontrollers

嵌入式学习指引--GCC编译器介绍

GCC是GNU项目的编译器组件之一,也是GNU最具有代表性的作品。在GCC设计之初仅仅作为一个C语言的编译器,可是经过十多年的发展,GCC已经不仅仅能支持C语言;它现在还支持Ada语言、C++语言、Java语言、Objective C语言,Pascal语言、COBOL语言,以及支持函数式编程和逻辑编程的Mercury语言,等等。而GCC也不再单是GNU C Compiler的意思,而是GNU Compiler Collection也即是GNU编译器家族的意思了,目前已经成为Linux下最重要的编译工具之一。

GCC是一个交叉平台的编译器,目前支持几乎所有主流CPU处理器平台,它可以完成从C、C++、Objective C等源文件向运行在特定cpu硬件上的目标代码的转换,GCC不仅功能非常强大,结构也异常灵活,便携性(protable)与跨平台支持(cross-plantform. support)特性是GCC的显着优点,目前编译器所能支持的源程序的格式如下表所示。

GCC所支持的源程序格式

后缀格式 说明
.c C语言程序
.a 由目标文件构成的档案文件
.C、cc、cxx C++源程序
.h 源程序所包含的头文件
.i 经过预处理的C程序
.ii 经过预处理的C++程序
.m Objective-C源程序
.o 编译后的目标文件
.s 汇编语言源程序
.S 经过预编译的汇编程序

GCC是一组编译工具的总称,其软件包里包含众多的工具,按其类型,主要有以下的分类。

C编译器cc,cc1,cc1 plus,gcc

C++编译器c++,cc1 plus,g++

源代码预处理程序cpp,cpp0

库文件libgcc.a, libgcc_eh.a,libgcc_s.so,libiberty.a,libstdc++.[a,so],libsupc++.a

用GCC编译程序生成可执行文件有时候看起来似乎仅通过编译一步就完成了,但事实上,使用GCC编译工具由C语言源程序生成可执行文件的过程并不单单是一个编译的过程,而要经过下面的几个过程。

  • 预处理(Pre-Processing)
  • 编译(Compiling)
  • 汇编(Assembling)
  • 链接(Linking)

在实际编译的时候,GCC首先调用cpp命令进行预处理,主要实现对源代码编译前的预处理,比如将源代码中指定的头文件包含进来。接着调用cc1命令进行编译,作为整个编译过程的一个中间步骤,该过程会将源代码翻译生成汇编代码。汇编过程是针对汇编语言的步骤,调用as命令进行工作,生成扩展名为.o的目标文件,当所有的目标文件都生成之后,GCC就调用连接器ld来完成最后的关键性工作——链接。

GCC编译选项解析

GCC是Linux下基于命令行的C语言编译器,其基本的使用语法如下。

gcc [option |filename]…

对于编译C++的源程序,其基本语法如下:

g++ [option |filename]…

其中option为GCC使用时的选项,而filename为需要GCC做编译的处理的的文件名。就GCC来说,其本身是一个十分复杂的的命令,合理的使用其命令选项可以有效地提高程序的编译效率、优化代码,GCC拥有众多的命令选项,有超过100个的编译选项可用,按其应有如下的分类。

常用编译选项

  • -c选项:这是GCC命令的常用选项。-c选项告诉GCC仅把源程序编译为目标代码而不做链接工作,所以采用该选项的编译指令不会生成最终的可执行程序,而是生成一个与源程序文件名相同的以.o为后缀的目标文件。例如一个Test.c的源程序经过下面的编译之后会生成一个Test.o文件
  • # gcc –c Test.h
  • -S选项:使用该选项会生成一个后缀名为.s的汇编语言文件,但是同样不会生成可执行程序。
  • -e选项:-e选项只对文件进行预处理,预处理的输出结果被送到标准输出(比如显示器)。
  • -v选项:在Shell的提示符号下键入gcc –v,屏幕上就会显示出目前正在使用的gcc版本的信息
  • -x language:强制编译器指定的语言编译器来编译某个源程序。

例如下面的指令:

# gcc -x c++ p1.c

该指令表示强制采用C++编译器来编译C程序P1.c。

-I<DIR>选项:库依赖选项,指定库及头文件路径。

在Linux下开发程序的时候,统常来讲都需要借助一个或多个函数库的支持才能够完成相应的功能。一般情况下,Linux下的大多数函数都将头文件放到系统/usr/include目录下,而库文件则放到/usr/lib目录下。但在有些情况下并不是这样的,在这些情况下,使用GCC编译时必须指定所需要的头文件和库文件所在的路径。-I选项可以向GCC的头文件搜索路径中添加新的目录<DIR>。例如,一个源程序所依赖的头文件在用户/home/include/目录下,此时就应该使用-I选项来指定。

# gcc –I /home/include -o test test.c

-L<DIR>:类似于上面的情况,用来特别指定所依赖库所在的路径

如果使用不在标准位置的库,那么可以通过-L选项向GCC的库文件搜索路径中添加新的目录。例如,一个程序要用到的库libapp.so在/home/zxq/lib/目录下,为了能让GCC能够顺利地链接该库,可以使用下面的指令:

# gcc -Test.c -L /home/zxq/lib/ -lapp –o Test

这里的-L选项表示GCC去链接库文件libapp.so。在Linux下的库文件在命名时遵循了一个约定,那就是应该以lib三个字母开头,由于所有的库文件都遵循了同样的规范,因此在使用-L选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lapp进行处理的时候,会自动去链接名为libapp.so的文件

-static选项:GCC在默认情况下链接的是动态库,有时为了把一些函数静态编译到程序中,而无需链接动态库就采用-static选项,它会强制程序连接静态库。

-o选项:在默认的状态下,如果GCC指令没有指定编译选项的情况下会在当前目录下生成一个名为a.out的可执行程序,例如:执行# gcc Test.c命令后会生成一个名为a.out的可执行程序。因此,为了指定生成的可执行程序的文件名,就可以采用-o选项,比如下名的指令:

# gcc –o Test Test.c

执行该指令会在当前目录下生成一个名为Test的可执行文件。

出错检查和警告提示选项

GCC编译器包含完整的出错检查和警告提示功能,比如GCC提供了30多条警示信息和3个警告级别,使用这些选项有助于增强程序的稳定性和更加完善程序代码的设计,此类选项常用的如下。

-pedantic以ANSI/ISO C标准列出的所有警告

当GCC在编译不符合ANSI/ISO C语言标准的源代码时,如果在编译指令中加上了-pedantic选项,那么源程序中使用了扩展语法的地方将产生相应的警告信息。

-w禁止输出警告信息

-Werror将所有警告转换为错误

Werror选项要求GCC将所有的警告当成错误进行处理,这在使用自动编译工具(如Make等)时非常有用。如果编译时带上-Werror选项,那么GCC会在所有产生警告的地方停止编译,只有程序员对源代码进行修改并起相应的警告信息消除时,才能够继续完成后续的编译工作。

-Wall显示所有的警告信息

-Wall选项可以打开所有类型的语法警告,以便于确定程序源代码是否是正确的,并且尽可能实现可移植性。

对Linux开发人员来讲,GCC给出的警告信息是很有价值的,它们不仅可以帮助程序员写出更加健壮的程序,而且还是跟踪和调试程序的有力工具。建议在用GCC编译源代码时始终带上-Wall选项,养成良好的习惯。

代码优化选项

-O选项:编译时使用选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。

-O2选项:选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度

调试分析选项

-g选项:生成调试信息,GNU调试器可以利用该信息。GCC编译器使用该选项进行编译时,将调试信息加入到目标文件中,这样gdb调试器就可以根据这些调试信息来跟中程序的执行状态。

-pg选项:编译完成后,额外产生一个性能分析所需信息。

注意:使用调试选项都会使最终生成的二进制文件的大小急剧增加,同时增加程序在执行时的开销,因此调试选项统常推荐仅仅在程序开发和调试阶段中使用。

下面举一个简单的例子来说明GCC的编译过程。首先用vi编辑器来编辑一个简单的c程序test.c,程序清单如下。

  • #include
  • int main()
  • {
  • printf("Hello,this is a test!\n");
  • return 0;
  • }

根据上面的内容,使用gcc命令来编译该程序。

  • [root@localhost]# gcc –o test test.c
  • [root@localhost]# ./test
  • Hello,this is a test!

可以从上面的编译过程看到,编译一个这样的程序非常简单,一条指令即可完成,事实上,这条指令掩盖了很多细节。我们可以从编译器的角度来看上述编译过程,这对于更好理解GCC编译工作原理有很好的帮助。

GCC编译器首先做的工作是预处理:调用-E参数可以让GCC在预处理结束后停止编译过程。

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

编译器在这一步调用cpp工具来对源程序进行预处理,此时会生成test.i文件,下面部分列出了test.i文件中的内容。

声明:本站部分内容根据互联网资料整理而成,若侵犯您的权益,请联系我们,我们会尽快处理。


                                                  



© 2006 WeBoch.Com.cn 版权所有:深圳市伟博创科技有限公司
地址:深圳市福田区振华路苏发大厦305栋405 电话:0755-83240703 传真:0755-83240724