您的位置:首页 > 运维架构 > Linux

linux gcc编译C程序

2014-01-14 09:39 197 查看
一个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 gcc test.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 -o a.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@dbbak tmp]# gcc -S a.i -o a1.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 Linux 3.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 Linux 3.2.3-42)"

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

[root@dbbak tmp]# gcc -c a.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), not stripped

[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 -o a1.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 -E test.c,而直接进入编译环节gcc -S test.c -o test.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 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 -o a.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.sql b.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 the gcc program will exit with the code of 1 if any phase of the compiler returns a non-success return code. If you specify -pass-exit-codes, the gcc program will instead return with numeri-cally highest error produced by any phase that returned
an error indication.

通常如果编译器遇到错误,返回值1;如果你想返回具体的错误代码,请用它。



-o file

Place output in file file. This applies regardless to whatever sort of output is being produced, whether it be an executable file,an object file, an assembler file or preprocessed C code.

Since only one output file can be specified, it does not make sense to use -o when compiling more than one input file, unless you are producing an executable file as output.

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



-v

Print (on standard error output) the commands executed to run the stages of compilation. Also print the version number of the com-piler driver program and of the preprocessor and the compiler proper.

这个选项的作用是把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 Linux 3.2.3-42).

ignoring nonexistent directory "/usr/i386-redhat-linux/include"

#include "..." search starts here:

#include <...> search starts here:

/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 assembler version 2.14.90.0.4 (i386-redhat-linux) using BFD version 2.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 -v except the commands are not executed and all command argu-ments are quoted. This is useful for shell scripts to capture the driver-generated command lines.

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

-pipe

Use pipes rather than temporary files for communication between the various stages of compilation. This fails to work on some systems where the assembler is unable to read from a pipe; but the GNU assembler has no trouble.

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

[root@dbbak tmp]# gcc -### -pipe 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" "-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 (on the standard output) a description of the command line options understood by gcc. If the -v option is also specified then --help will also be passed on to the various processes invoked by gcc, so that they can display the command line options
they accept. If the -W option is also specified then command line options which have no documentation associated with them will also be displayed.

--target-help

Print (on the standard output) a description of target specific command line options for each tool.

--version

Display the version number and copyrights of the invoked GCC.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: