一、gcc,即 GNU C Compile
gcc 仅仅是一个编译器,没有界面,必须在命令行模式下使用。通过 gcc 命令可以将源文件编译成可执行文件。
gcc 既可以一次性完成C语言源文件的编译,也可以分步骤完成。看一个gcc编译的完整例子:
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
在Centos中编译运行,如下图所示:
$ gcc main.c #在 gcc 命令后面紧跟源文件名
打开 demo 目录,会看到多了一个名为 a.out 的文件,这就是最终生成的可执行文件, ./a.out 执行。
这样就一次性完成了编译和链接的全部过程,非常方便。
如果不想使用默认输出的文件名(a.out),那么可以通过-o
选项来自定义文件名。(注意不像 Windows,linux 不以文件后缀来区分可执行文件,Linux 下的可执行文件后缀理论上可以是任意的,这里的.out
只是用来表明它是 GCC 的输出文件。不管源文件的名字是什么,GCC 生成的可执行文件的默认名字始终是a.out
)
例如:$ gcc main.c -o main.out
这样生成的可执行程序的名字就是main.out
。
因为 Linux 下可执行文件的后缀仅仅是一种形式上的,所以可执行文件也可以不带后缀,例如:
$ gcc main.c -o main
这样生成的可执行程序的名字就是main
。
通过-o
选项也可以将可执行文件输出到其他目录,并不一定非得在当前目录下,例如:
$ gcc main.c -o ./out/main.out
或者
$ gcc main.c -o out/main.out
表示将可执行文件输出到当前目录下的out
目录,并命名为main.out
。./
表示当前目录,如果不写,默认也是当前目录。
运行可执行程序非常简单,只需通过命令:$ ./a.out
./
表示当前目录,整条命令的意思是运行当前目录下的 a.out 程序。如果不写./
,Linux 会到系统路径下查找 a.out,而系统路径下显然不存在这个程序,所以会运行失败。
所谓系统路径,就是环境变量指定的路径,我们可以通过修改环境变量添加自己的路径,或者删除某个路径。很多时候,一条 Linux命令对应一个可执行程序,如果执行命令时没有指明路径,那么就会到系统路径下查找对应的程序。
注意,如果程序没有执行权限,可以使用sudo
命令来增加权限,例如:
$ sudo chmod 777 a.out
二、分步编译 C 程序
之前我们是通过gcc
命令一次性完成编译和链接的整个过程,这样比较方便,但是gcc
命令也可以将编译和链接分开,每次只完成一项任务。
1. 编译(Compile)
将源文件编译成目标文件需要使用-c
选项,例如:
gcc -c main.c
就将 main.c 编译为 main.o。打开 demo 目录,就会看到 main.o:
一个源文件会生成一个目标文件,多个源文件会生成多个目标文件,源文件数目和目标文件数目是一样的。通常情况下,默认的目标文件名字和源文件名字是一样的。对于 gcc编译器,目标文件的后缀为.o
。
如果希望自定义目标文件的名字,那么可以使用-o
选项,例如:
gcc -c main.c -o a.o
这样生成的目标文件的名字就是 a.o。
2. 链接(Link)
在gcc
命令后面紧跟目标文件的名字,就可以将目标文件链接成为可执行文件,例如:
gcc main.o
就将 main.o 链接为 a.out。打开 demo 目录,就会看到 a.out。
在gcc
命令后面紧跟源文件名字或者目标文件名字都是可以的,gcc
命令能够自动识别到底是源文件还是目标文件:如果是源文件,那么要经过编译和链接两个步骤才能生成可执行文件;如果是目标文件,只需要链接就可以了。
使用-o
选项仍然能够自定义可执行文件的名字,例如:
gcc main.o -o main.out
这样生成的可执行文件的名字就是 main.out。
三、gcc编译流程
gcc编译器在编译一个C语言程序时需要经过以下 4 步:
- 将C语言源程序预处理,生成
.i
文件。 - 预处理后的 .i 文件编译成为汇编语言文件,生成
.s
文件。 - 将汇编语言文件经过汇编,生成目标文件
.o
文件。 - 将各个模块的
.o
文件链接起来生成一个可执行程序文件。
gcc编译流程如下图所示:
.i
文件、.s
文件、.o
文件可以认为是中间文件或临时文件,如果使用 GCC 一次性完成C语言程序的编译,那么只能看到最终的可执行文件,这些中间文件都是看不到的,因为 GCC 已经经它们删除了。
四、gcc 常用选项
gcc 是一个功能强大的编译器,其编译选项非常多。有些选项一般不会用到。下面只对一些 gcc 编译器的常用选项进行描述,这些选项在实际编程过程中非常实用。gcc 的常用选项如下所示:
gcc编译选项 | 选项的意义 |
---|---|
-c | 编译、汇编指定的源文件,但是不进行链接 |
-S | 编译指定的源文件,但是不进行汇编 |
-E | 预处理指定的源文件,不进行编译 |
-o [file1] [file2] | 将文件 file2 编译成可执行文件 file1 |
-I directory | 指定 include 包含文件的搜索目录 |
-g | 生成调试信息,该程序可以被调试器调试 |
注意:gcc 编译选项会区分大小写。因此-o
选项和-O
选项的效果是不一样的。前者表示源文件编译成为可执行文件,后者表示将源文件编译成为可执行文件并且进行一级优化。
-S
将C语言源文件编译为汇编语言,但是并不汇编该程序。使用该选项,我们可以查看C语言代码对应的汇编代码。
-E 选项
-E
选项将C语言源文件进行预处理,但是并不编译该程序。对于一般的预处理问题,可以使用这个选项进行查看,例如,宏的展开问题、文件的包含问题等。
-I 选项
由于指定包含的头文件的目录,这一点对于大型的代码组织来说是很有用的。
-g 选项
-g
选项可生成能被 gdb 调试器所使用的调试信息。只有使用了该选项后生成的可执行文件,才带有程序中引用的符号表。这时 gdb 调试程序才能对该可执行程序进行调试。
还有另一个 GCC 选项,可以方便地一次获得全部的中间输出文件,这就是-save-temps。当使用该选项时,GCC 会正常地编译和链接,但是会把预处理器输出、汇编语言和对象文件全部存储在当前目录下。使用 -save-temps 选项所生成的中间文件,与对应的源文件具有相同的文件名,但文件扩展名分别为.i、.s和.o,分别表示为预处理输出、汇编语言输出和对象文件。
五、常用选项详细介绍
gcc -c选项:只编译不链接,仅生成目标文件
-c
选项表示编译、汇编指定的源文件(也就是编译源文件),但是不进行链接。使用-c
选项可以将每一个源文件编译成对应的目标文件。
目标文件是一种中间文件或者临时文件,如果不设置该选项,gcc 一般不会保留目标文件,可执行文件生成完成后就自动删除了。
如果不使用-c
选项,则仅仅生成一个可执行文件,没有目标文件。
注意,使用-c
选项表示只编译源文件,而不进行链接,因此,对于链接中的错误是无法发现的。
gcc -o选项:指定输出文件
gcc -o
选项用来指定输出文件,它的用法为:
[infile] -o [outfile]
[infile] 表示输入文件(也即要处理的文件),它可以是源文件,也可以是汇编文件或者是目标文件;[outfile] 表示输出文件(也即处理的结果),它可以是预处理文件、目标文件、可执行文件等。
[infile] 和 [outfile] 可以是一个文件,也可以是一组文件:
- 如果 [infile] 是一组文件,那么就表示有多个输入文件;
- 如果 [outfile] 是一组文件,那么就表示有多个输出文件。
如果不使用 -o 选项,那么将采用默认的输出文件,例如,把可执行文件作为输出文件,它的名字默认为 a.out。
1) 将源文件作为输入文件,将可执行文件作为输出文件,也即完整地编译整个程序:
$ gcc main.c func.c -o app.out
将 main.c 和 func.c 两个源文件编译成一个可执行文件,其名字为 app.out。如果不使用 -o 选项,那么将生成名字为 a.out 的可执行文件。
2) 将源文件作为输入文件,将目标文件作为输出文件,也即只编译不链接:
$ gcc -c main.c -o a.o
将源文件 main.c 编译为目标文件 a.o。如果不使用 -o 选项,那么将生成名为 main.o 的目标文件。
3) 将源文件作为输入文件,将预处理文件作为输出文件,也即只进行预处理操作:
$ gcc -E main.c -o demo.i
对源文件 main.c 进行预处理操作,并将结果放在 demo.i 文件中。如果不使用 -o 选项,那么将生成名为 main.i 的预处理文件。
4) 将目标文件作为输入文件,将可执行文件作为输出文件:
$ gcc -c func.c main.c
$ gcc func.o main.o -o app.out
第一条命令只编译不链接,将生成 func.o 和 main.o 两个目标文件。第二条命令将生成的两个目标文件生成最终的可执行文件 app.out。如果不使用 -o 选项,那么将生成名字为 a.out 的可执行文件。
gcc -E 选项,生成预处理文件
C语言代码在交给编译器之前,会先由预处理器进行一些文本替换方面的操作,例如宏展开、文件包含、删除部分代码等。
在正常的情况下,gcc 不会保留预处理阶段的输出文件,也即.i
文件。然而,可以利用-E
选项保留预处理器的输出文件,以用于诊断代码。-E
选项指示 GCC 在预处理完毕之后即可停止。
默认情况下,预处理器的输出会被导入到标准输出流(也就是显示器),可以利用-o
选项把它导入到某个输出文件:
$ gcc -E circle.c -o circle.i
表示把预处理的结果导出到 circle.i 文件。
因为头文件可能相当大,如果源文件包括了多个头文件,那么它的预处理器输出可能会庞杂难读。使用-C
选项会很有帮助,这个选项可以阻止预处理器删除源文件和头文件中的注释:
$ gcc -E -C circle.c -o circle.c
注意,这里是大写的 -C,不是小写的 -c。小写的 -c 表示只编译不链接。
gcc -S 选项,生成汇编文件
编译器的核心任务是把C程序翻译成机器的汇编语言(assembly language)。汇编语言是人类可以阅读的编程语言,也是相当接近实际机器码的语言。由此导致每种 CPU 架构都有不同的汇编语言。
(注意,gcc是一个适合多种 CPU 架构的编译器,不会把C程序语句直接翻译成目标机器的汇编语言,而是在输入语言和输出汇编语言之间,利用一个中间语言,称为 RegisterTransfer Language(简称 RTL,寄存器传输语言)。借助于这个抽象层,在任何背景下,编译器可以选择最经济的方式对给定的操作编码。)
常情况下,GCC 把汇编语言输出存储到临时文件中,并且在汇编器执行完后立刻删除它们。但是可以使用-S
选项,让编译程序在生成汇编语言输出之后立刻停止。
如果没有指定输出文件名,那么采用-S
选项的 GCC 编译过程会为每个被编译的输入文件生成以.s
作为后缀的汇编语言文件。如下例所示:
$ gcc -S circle.c
编译器预处理 circle.c,将其翻译成汇编语言,并将结果存储在 circle.s 文件中。
如果想把C语言变量的名称作为汇编语言语句中的注释,可以加上-fverbose-asm
选项:
$ gcc -S -fverbose-asm circle.c
未完待续
标签:选项,文件,gcc,源文件,编译,编译器,main From: https://www.cnblogs.com/fuqiangblog/p/16612425.html