linux gcc编译C程序

一个c语言程序从源文件到生成可执行文件,编译器需要共经历4个步骤:
1)预处理:把c文件中预处理命令扫描处理完毕,即对源代码文件中的文件包含(#include)、预编译语句(如宏定义#define等)进行分析,此时生成的文件仍然是可读的。
2) 编译:把预处理后的结果编译成汇编或者目标模块,即生成汇编语言文件,此时生成的文件仍然是可读的汇编文件。
3)汇编:把编译出来的结果汇编成具体CPU上的目标代码模块,也即此时转换成具体的机器语言代码,此时生成的文件是不可读的非文本文件。
4)连接:把多个目标代码模块连接生成一个大的目标模块,即将多个上面产生的机器代码文件(与其它的机器代码文件和库文件)汇集成一个可执行的二进制代码文件。

   gcc作为c语言在linux下很著名的编译软件,分别有如下option来支持4个步骤:

  名称 gcc选项 英文名称        gcc调用的程序  示例
预处理 
-E      Pre-Processing  cpp           gcc -E test.c -o test.i
 
编译 -S      Compiling       ccl           gcc -S test.i -o test.s 
 
汇编 -c       Assembling     as            gcc -c test.s -o test.o
 
连接 无       Linking        ld             gcctest.o -o test

说明:

  gcc在编译c语言文件时,首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(#include)、预编译语句(如宏定义#define等)进行分析;其次调用ccl进行编译工作,将文件编译成汇编语言文件,此时文件依旧是可读的;之后调用as进行汇编工作,将具体的汇编语言文件编译成cpu可执行的目标代码,此时文件不可读了;当所有的目标文件都生成之后,gcc就调用ld来完成最后的关键性工作,链接。在链接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的库中链接到合适的地方。下面对上面4个过程做下分别的说明:

1、在预处理阶段,如果不用“-o”指定文件名,那么会默认将预处理结果输出到标准终端设备。

[root@dbbak tmp]# cat a.c
int main()
{
       printf("shengtong test!\n");
}

[root@dbbak tmp]# gcc -E a.c
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.c"
int main()
{
       printf("shengtong test!\n");
}
[root@dbbak tmp]# gcc -E a.c -oa.i
[root@dbbak tmp]# cat a.i
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.c"
int main()
{
       printf("shengtong test!\n");
}

2、在编译阶段,如果不用“-o”指定文件名,那么默认会生成一个“*.s”的汇编语言文件。

[root@dbbak tmp]# gcc -S a.i
[root@dbbak tmp]# ls
a.c  a.i 
a.s
[root@dbbaktmp]#
gcc -S a.i -oa1.s
[root@dbbak tmp]# ls
a.c  a.i  a.s a1.s

[root@dbbak tmp]#
[root@dbbak tmp]# cat a.s
       .file   "a.c"
       .section       .rodata
.LC0:
       .string "shengtong test!\n"
       .text
.globl main
       .type   main,@function
main:
       pushl   %ebp
       movl    %esp,%ebp
       subl    $8,%esp
       andl    $-16,%esp
       movl    $0,%eax
       subl    %eax,%esp
       subl    $12,%esp
       pushl   $.LC0
       call   printf
       addl    $16,%esp
       leave
       ret
.Lfe1:
       .size   main,.Lfe1-main
       .section       .note.GNU-stack,"",@progbits
       .ident  "GCC: (GNU) 3.2.3 20030502 (Red Hat Linux3.2.3-42)"
[root@dbbak tmp]# cat a1.s
       .file   "a.c"
       .section       .rodata
.LC0:
       .string "shengtong test!\n"
       .text
.globl main
       .type   main,@function
main:
       pushl   %ebp
       movl    %esp,%ebp
       subl    $8,%esp
       andl    $-16,%esp
       movl    $0,%eax
       subl    %eax,%esp
       subl    $12,%esp
       pushl   $.LC0
       call   printf
       addl    $16,%esp
       leave
       ret
.Lfe1:
       .size   main,.Lfe1-main
       .section       .note.GNU-stack,"",@progbits
       .ident  "GCC: (GNU) 3.2.3 20030502 (Red Hat Linux3.2.3-42)"

3、在汇编阶段,如果不用“-o”指定文件名,那么默认会生成一个“*.o”的机器语言代码文件。

[root@dbbak tmp]# gcc -ca.s
[root@dbbak tmp]# ls
a.c  a.i  a.o  a.s a1.s
[root@dbbak tmp]#
gcc -c a1.s -o a1.o
[root@dbbak tmp]#ls
a.c  a.i  a.o a.s  a1.o  a1.s
[root@dbbak tmp]#
[root@dbbak tmp]# file a.o
a.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), notstripped
[root@dbbak tmp]# file a1.o
a1.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV),not stripped

4、在连接阶段,不指定前面3个选项就是默认进入这个阶段,如果不用“-o”指定文件名,那么默认会生产一个“a.out”的可执行文件。

[root@dbbak tmp]# gcc a.o
[root@dbbak tmp]# ls
a.c  a.i  a.o a.out  a.s a1.o  a1.s  -- 可执行文件
[root@dbbak tmp]# gcc a1.o -oa1.out
[root@dbbak tmp]# ls
a.c  a.i  a.o a.out a.s  a1.o  a1.out a1.s
[root@dbbak tmp]#
[root@dbbak tmp]# ./a.out
shengtong test!
[root@dbbak tmp]# ./a1.out
shengtong test!

5、编译c文件的时候,可以跳过前面阶段而直接进入后面阶段,如可以不分开执行预处理命令gcc -Etest.c,而直接进入编译环节gcc -S test.c -otest.s,gcc会在执行“编译”环节(后面阶段)的时候发现没有“预编译”环节(前面阶段),它会自动补上。

 

   gcc能够编译的语言文件有很多(常见的如c语言和c++语言等),它默认情况下依据文件的后缀名执行相应的编译,下面列出c和c++的:
.c 为后缀的文件,C语言源代码文件;
.i 为后缀的文件,是已经预处理过的C源代码文件;
.s 为后缀的文件,是汇编语言源代码文件;
.o 为后缀的文件,是编译后的目标文件;
.h 为后缀的文件,是程序所包含的头文件;
.a 为后缀的文件,是由目标文件构成的库文件;

.C .cc .cp .cpp .c++ .cxx 为后缀的文件,是C++源代码文件;
.ii 为后缀的文件,是已经预处理过的C++源代码文件;
.m 为后缀的文件,是Objective-C源代码文件;
.mi 是已经预处理过的Objective-C源代码文件;
.S 为后缀的文件,是经过预编译的汇编语言源代码文件。

   当然,你可以乱写自己的文件名后缀,如将c文件以.cpp结尾或者以.eng结尾,那么gcc就无法根据后缀名来做正确的编译了,此时怎么办?gcc提供了“-x”选项来指定文件类型,“-x”选项内容有(只列出c和c++的):

c-header  cpp-output
c++ 
c++-cpp-output
objective-c 
objc-cpp-output
assembler 
assembler-with-cpp

   当使用了“-x”选项后,那么其后面所有的文件都默认是其指定的文件类型,直到用“-x none”来指定结束。

[root@dbbak tmp]# gcc -x c -E a.sql -oa.i
[root@dbbak tmp]# cat a.i
# 1 "a.sql"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.sql"
int main()
{
       printf("shengtong test!\n");
}
[root@dbbak tmp]# mv c.sql c.c
[root@dbbak tmp]#
[root@dbbak tmp]# gcc -x c -S a.sqlb.sql -x none  -S c.c
[root@dbbak tmp]# ls
a.i  a.s  a.sql b.s b.sql  c.c  c.s

  

    下面再介绍下gcc的其他常用选项:

   -pass-exit-codes
 
   Normally thegcc program will exit with the code of 1 if any phase of thecompiler returns a non-success return code.  Ifyou specify -pass-exit-codes, the gcc program will instead returnwith numeri-cally highest error produced by any phase that returnedan error indication.
通常如果编译器遇到错误,返回值1;如果你想返回具体的错误代码,请用它。

    

    -ofile
 
   Place outputin file file.  This applies regardless to whateversort of output is being produced, whether it be an executablefile,an object file, an assembler file or preprocessed C code.

    Sinceonly one output file can be specified, it does not make sense touse -o when compiling more than one input file, unless you areproducing an executable file as output.

    If -o isnot specified, the default is to put an executable file in a.out,the object file for source.suffix in source.o, its assembler filein source.s, and all preprocessed C source on standardoutput.  -- 这段话我在上面的1/2/3/4/5中已经介绍了

    

    -v 

    Print (onstandard error output) the commands executed to run the stages ofcompilation.  Also print the version number of thecom-piler driver program and of the preprocessor and the compilerproper.

    这个选项的作用是把gcc编译c文件的过程给打印出来,如下面这个例子:

[root@dbbak tmp]# gcc -v a.c
Reading specs from/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man--infodir=/usr/share/info --enable-shared --enable-threads=posix--disable-checking --with-system-zlib --enable-__cxa_atexit--host=i386-redhat-linux
Thread model: posix
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-42)
 /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/cc1-lang-c -v -D__GNUC__=3 -D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=3-D__GXX_ABI_VERSION=102 -D__ELF__ -Dunix -D__gnu_linux__ -Dlinux-D__ELF__ -D__unix__ -D__gnu_linux__ -D__linux__ -D__unix -D__linux-Asystem=posix -D__NO_INLINE__ -D__STDC_HOSTED__=1 -Acpu=i386-Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i386__ a.c-quiet -dumpbase a.c -version -o /tmp/cclLW8Ji.s
GNU CPP version 3.2.3 20030502 (Red Hat Linux 3.2.3-42) (cpplib)(i386 Linux/ELF)
GNU C version 3.2.3 20030502 (Red Hat Linux 3.2.3-42)(i386-redhat-linux)
       compiled by GNU C version 3.2.3 20030502 (Red Hat Linux3.2.3-42).
ignoring nonexistent directory"/usr/i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search startshere:
 /usr/local/include
 /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/include
 /usr/include
End of search list.
 as-V -Qy -o /tmp/ccRCof2i.o
/tmp/cclLW8Ji.s
GNU assemblerversion 2.14.90.0.4 (i386-redhat-linux) using BFD version2.14.90.0.4 20030523
 /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/collect2--eh-frame-hdr -m elf_i386 -dynamic-linker/lib/ld-linux.so.2/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crt1.o/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crti.o/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/crtbegin.o-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.3-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../.. /tmp/ccRCof2i.o-lgcc -lgcc_eh -lc -lgcc -lgcc_eh/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/crtend.o/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crtn.o

    上面的调用堆栈,充分反应了gcc编译过程,首先调用ccl执行预处理和编译,并且在/tmp目录下生成一个临时文件/tmp/cclLW8Ji.s文件;接着调用as执行汇编功能,也生成了临时文件/tmp/ccRCof2i.o;最后执行连接工作。

    如果你只想看gcc的调用堆栈过程而不真正执行编译工作,怎么办?用“-###”选项:

   -###
 
   Like -vexcept the commands are not executed and all command argu-ments arequoted.  This is useful for shell scripts tocapture the driver-generated command lines.

    从上面的过程中,我们可以看到,在各个步骤中gcc生成了中间临时文件,而如果你不想生成这些临时文件,而取而代之用管道,该怎么办?用“-pipe”选项:

   -pipe
 
   Use pipesrather than temporary files for communication between the variousstages of compilation.  This fails to work on somesystems where the assembler is unable to read from a pipe; but theGNU assembler has no trouble.

    举个例子如下,请看红色部分的管道:

[root@dbbak tmp]# gcc -### -pipea.c
Reading specs from/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man--infodir=/usr/share/info --enable-shared --enable-threads=posix--disable-checking --with-system-zlib --enable-__cxa_atexit--host=i386-redhat-linux
Thread model: posix
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-42)
 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/cc1""-lang-c" "-D__GNUC__=3" "-D__GNUC_MINOR__=2""-D__GNUC_PATCHLEVEL__=3" "-D__GXX_ABI_VERSION=102" "-D__ELF__""-Dunix" "-D__gnu_linux__" "-Dlinux" "-D__ELF__" "-D__unix__""-D__gnu_linux__" "-D__linux__" "-D__unix" "-D__linux""-Asystem=posix" "-D__NO_INLINE__" "-D__STDC_HOSTED__=1""-Acpu=i386" "-Amachine=i386" "-Di386" "-D__i386" "-D__i386__""-D__tune_i386__" "a.c" "-quiet" "-dumpbase" "a.c" "-o" "-" |
 "as" "-Qy" "-o""/tmp/cc8lJo7Z.o" "-"
 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/collect2""--eh-frame-hdr" "-m" "elf_i386" "-dynamic-linker""/lib/ld-linux.so.2""/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crt1.o""/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crti.o""/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/crtbegin.o""-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.3""-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../..""/tmp/cc8lJo7Z.o" "-lgcc" "-lgcc_eh" "-lc" "-lgcc" "-lgcc_eh""/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/crtend.o""/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crtn.o"

 

   --help
 
   Print (onthe standard output) a description of the command line optionsunderstood by gcc.  If the -v option is alsospecified then --help will also be passed on to the variousprocesses invoked by gcc, so that they can display the command lineoptions they accept. If the -W option is also specified thencommand line options which have no documentation associated withthem will also be displayed.

   --target-help
 
   Print (onthe standard output) a description of target specific command lineoptions for each tool.

   --version
 
   Display theversion number and copyrights of the invoked GCC.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值