Gcc编译总结

梦里伊人 posted @ 2007年8月17日 04:04 in c语言笔记 , 2501 阅读

                                      Gcc编译总结

                     (参考http://blog.chinaunix.net/u/18537/showart_139343.html

      前一段时间在学习C语言编程时,程序编写完成后用Gcc进行编译,当时编写的程序比较简单,例如程序:

//test.c
#include <stdio.h>

int main(void)
{
  printf("Hello World!\n");
  return 0;
}

只要在终端输入

gcc test.c -o test

即可完成编译,如果没有错误和警告,再输入

./test

即可执行程序并输出结果。

       实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和连接(Linking)。

1.1 预处理

  运行预处理命令: 

gcc -E test.c -o test.i 或 gcc -E test.c

 

可 以输出test.i文件中存放着test.c经预处理之后的代码。打开test.i文件,看一看,就明白了。后面那条指令,是直接在命令行窗口中输出预处 理后的代码,而不是以文件作为输出设备。gcc的-E选项,可以让编译器在预处理后停止,并输出预处理结果。在本例中,预处理结果就是将stdio.h 文件中的内容插入到test.c中了。gcc的-o选项,用于输出处理结果到文件中。

1.2 编译为汇编代码

  预处理之后,可直接对生成的test.i文件编译,生成汇编代码:

gcc -S test.i -o test.s

  gcc的-S选项,表示在程序编译期间,在生成汇编代码后,停止,-o输出汇编代码文件。 

  生成的汇编代码如下:

.file    "test.c"
    .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汇编器负责将其编译为目标文件,如下:

gcc -c test.s -o test.o

1.4 连接

  gcc连接器是gas提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。附加的目标文件包括静态连接库和动态连接库。 

  对于上一小节中生成的test.o,将其与C标准输入输出库进行连接,最终生成程序test:

gcc test.o -o 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选项

  1. gcc foo.c -I /home/xiaowp/include -o foo
,如果使用了不在准位置的文件,那可以通-L选项Gcc文件搜索路径中添加新的目。例如,如果在/home/xiaowp/lib/下有所需要的文件libfoo.soGCC够顺利地找到它,可以使用下面的命令:
  1. gcc foo.c -L /home/xiaowp/lib -lfoo -o foo
得好好解一下的是-l选项,它指示Gcc文件libfoo.soLinux下的文件在命名有一个定,那就是应该lib三个字母开头,由于所有的文件都遵循了同范,因此在用-l选项指定接的文件名可以省去lib三个字母,也就是GCC-lfoo,会自接名libfoo.so的文件。
       Linux下的文件分两大动态链(通常以.so尾)和静态链(通常以.a尾),两者的别仅在程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。默认情况下,Gcc时优先使用动态链,只有当动态链接库不存在时才考使用静态链接库,如果需要的话可以编译时加上-static选项制使用静态链接库。例如,如果在/home/xiaowp/lib/目录下有所需要的文件libfoo.solibfoo.aGcc只用到静态链接库,可以使用下面的命令:
  1. gcc foo.c -L /home/xiaowp/lib -static -lfoo -o foo

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter