gcc (GNU编译器套件)

GNU编译器套件(GNU Compiler Collection)包括 CC++Objective-CFortranJavaAdaGo语言的前端,也包括了这些语言的库(如libstdc++、libgcj等等)。GCC的初衷是为GNU操做系统专门编写的一款编译器。GNU系统是完全的 自由软件。此处,“自由”的含义是它尊重用户的自由。 [1]  
软件名称GNU Compiler Collection开发商Free Software Foundation (FSF)软件平台类Unix操做系统软件语言多国语言软件受权GNU通用公共许可证(GNU GPL)

创做背景 编辑

GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器。它是以 GPL许可证所发行的自由软件,也是 GNU计划的关键部分。GCC本来做为GNU操做系统的官方编译器,现已被大多数类 Unix操做系统(如 LinuxBSDMac OS X等)采纳为标准的 编译器,GCC一样适用于微软的 Windows[2]   GCC是自由软件过程发展中的著名例子,由自由软件基金会以 GPL协议发布。
GCC 原名为 GNU C 语言编译器(GNU C Compiler),由于它本来只能处理 C语言。GCC 很快地扩展,变得可处理 C++。后来又扩展可以支持更多编程语言,如 FortranPascalObjective-CJavaAdaGo以及各种 处理器架构上的 汇编语言等,因此更名GNU编译器套件(GNU Compiler Collection)。 [2]  

结构 编辑

GCC的外部接口长得像一个标准的Unix 编译器。使用者在命令列下键入gcc之程序名,以及一些命令参数,以便决定每一个输入档案使用的个别语言编译器,并为输出程序码使用适合此硬件平台的组合语言编译器,而且选择性地执行链接器以制造可执行的程序。
每一个语言编译器都是独立程序,此程序可处理输入的原始码,并输出组合语言码。所有的语言编译器都拥有共通的中介架构:一个前端解析符合此语言的原始码,并产生一 抽象语法树,以及一翻译此语法树成为GCC的 暂存器转换语言〈RTL〉的后端。编译器最佳化与静态程序码解析技术(例如FORTIFY_SOURCE,一个试图发现 缓冲区溢位〈buffer overflow〉的编译器)在此阶段应用于程序码上。最后,适用于此硬件架构的组合语言程序码以Jack Davidson与Chris Fraser发明的算法产出。
几乎所有的GCC都由C写成,除了Ada前端大部分以Ada写成。

前端接口

前端的功能在于产生一个可以让后端处理之语法树。此语法解析器是手写之 递归语法解析器。
直到2004年,程序的语法树结构尚没法与欲产出的处理器架构脱钩。而语法树的规则有时在不一样的语言前端也不同,有些前端会提供它们特别的语法树规则。
在2005年,两种与语言脱钩的新型态语法树归入GCC中。它们称为GENERIC与GIMPLE。语法解析变成产生与语言相关的暂时 语法树, 再将它们转成GENERIC。以后再使用"gimplifier"技术下降GENERIC的复杂结构,成为一较简单的静态惟一形式(Static Single Assignment form,SSA)基础的GIMPLE形式。此形式是一个与语言和处理器架构脱钩的全域最佳化通用语言,适用于大多数的现代编程语言。

中介接口

通常 编译器做者会将语法树的最佳化放在前端,但其实此步骤并不看语言的种类而有不一样,且不须要用到语法解析器。所以GCC做者们将此步骤纳入通称为中介阶段的部分里。此类的最佳化包括消解死码、消解重复运算与全域数值重编码等。许多最佳化技巧也正在实做中。

后端接口

GCC后端的行为因不一样的前处理器 和特定架构的功能而不一样,例如不一样的字符尺寸、呼叫方式与大小尾序等。后端接口的前半部利用这些讯息决定其RTL的生成形式,所以虽然GCC的RTL理论上不受 处理器影响,但在此阶段其抽象指令已被转换成目标架构的格式。
GCC的最佳化技巧依其释出版本而有很大不一样,但都包含了标准的最佳化算法,例如循环最佳化、执行绪跳跃、共通程序子句消减、指令排程等等。而RTL的最佳化因为可用的情形较少,且缺少较高阶的资讯,所以相比较起来,增长的GIMPLE语法树形式,便显得比较不重要。
后端经由一次重读取步骤后,利用描述目标处理器的 指令集时所取得的信息,将抽象 暂存器替换成 处理器的真实暂存器。此阶段很是复杂,由于它必须关注全部GCC可移植平台的处理器指令集的规格与技术细节。
后端的最后步骤至关公式化,仅仅将前一阶段获得的 汇编语言代码藉由简单的 子例程转换其暂存器与内存位置成相对应的 机器码

基本用法 编辑

在使用GCC 编译器的时候,咱们必须给出一系列必要的调用参数和文件名称。GCC编译器的调用参数大约有100多个,这里只介绍其中最基本、最经常使用的参数。具体可参考GCC Manual。
GCC最基本的用法是∶gcc [options] [filenames]
其中options就是编译器所须要的参数,filenames给出相关的文件名称。
-c,只 编译,不连接成为 可执行文件,编译器只是由输入的.c等 源代码文件生成.o为后缀的目标文件,一般用于编译不包含主程序的 子程序文件。
-o output_filename,肯定输出文件的名称为output_filename,同时这个名称不能和源文件同名。若是不给出这个选项,gcc就给出预设的可执行文件a.out。
-g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,咱们就必须加入这个选项。
-O,对程序进行优化 编译、连接,采用这个选项,整个 源代码会在编译、连接过程当中进行优化处理,这样产生的 可执行文件的执行效率能够提升,可是,编译、连接的速度就相应地要慢一些。
-O2,比-O更好的优化编译、连接,固然整个编译、连接过程会更慢。
-Idirname,将dirname所指出的目录加入到程序头文件目录列表中,是在 预编译过程当中使用的参数。C程序中的头文件包含两种状况∶
A)#include <myinc.h>
B)#include “myinc.h”
其中,A类使用尖括号(< >),B类使用双引号(“ ”)。对于A类, 预处理程序cpp在系统预设包含 文件目录(如/usr/include)中搜寻相应的文件,而B类,预处理程序在 目标文件的文件夹内搜索相应文件。
-v gcc执行时执行的详细过程,gcc及其相关程序的版本号
原版gcc manual该选项英文解释
Print (on standard error output) the commands executed to run the stages of compilation. Also print the version number of the compiler driver program and of the preprocessor and the compiler proper.
编译程序时加上该选项能够看到gcc搜索头文件/库文件时使用的搜索路径!

基本规则 编辑

gcc所遵循的部分约定规则:
.c为后缀的文件,C语言 源代码文件;
.a为后缀的文件,是由 目标文件构成的档案库文件;
.C,.cc或.cxx 为后缀的文件,是C++源代码文件且必需要通过 预处理
.h为后缀的文件,是程序所包含的 头文件
.i 为后缀的文件,是C源代码文件且不该该对其执行预处理;
.ii为后缀的文件,是C++源代码文件且不该该对其执行预处理;
.m为后缀的文件,是Objective-C源代码文件;
.mm为后缀的文件,是Objective-C++ 源代码文件;
.o为后缀的文件,是 编译后的 目标文件
.s为后缀的文件,是 汇编语言源代码文件;
.S为后缀的文件,是通过 预编译的汇编语言源代码文件。

语言支持 编辑

以2006年5月24日释出的4.1.1版为准,本 编译器版本可处理下列语言:
Ada 〈GNAT〉
C 〈GCC〉
C++(G++)
Fortran 〈Fortran 77: G77, Fortran 90: GFORTRAN〉
Java 〈编译器:GCJ; 解释器:GIJ〉
Objective-C 〈GOBJC〉
Objective-C++
先前版本归入的CHILL前端因为缺少维护而被废弃。
Fortran前端在4.0版以前是G77,此前端仅支援Fortran 77。在本版本中,G77被废弃而采用更新的GFortran,由于此前端支援Fortran 95。
下列前端依然存在:
Modula-2
Modula-3
PL/I
Mercury

执行过程 编辑

虽然咱们称GCC是 C语言编译器,但使用gcc由C语言 源代码文件生成 可执行文件的过程不只仅是编译的过程,而是要经历四个相互关联的步骤∶ 预处理(也称 预编译,Preprocessing)、 编译(Compilation)、 汇编(Assembly)和连接(Linking)。
命令gcc首先调用cpp进行预处理,在预处理过程当中,对源代码文件中的文件包含(include)、预编译语句(如 定义define等)进行分析。接着调用cc1进行编译,这个阶段根据输入文件生成以.i为后缀的目标文件。汇编过程是针对汇编语言的步骤,调用as进行工做,通常来说,.S为后缀的汇编语言 源代码文件和汇编、.s为后缀的汇编语言文件通过 预编译汇编以后都生成以.o为后缀的目标文件。当全部的 目标文件都生成以后,gcc就调用ld来完成最后的关键性工做,这个阶段就是链接。在链接阶段,全部的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的 库函数也从各自所在的档案库中连到合适的地方。

执行过程示例 编辑

  • 示例代码
1
2
3
4
5
6
7
#include<stdio.h>
 
int main(void)
{
    printf("hello\n");
    return 0;
}
这个过程处理 宏定义和include,并作语法检查。
能够看到 预编译后,代码从6行扩展到了910行。
1
2
3
4
5
gcc -E a.c -o a.i
cat a.c|wc -l
5
cat a.i|wc -l
910
  • 编译过程
这个阶段,生成 汇编代码。
1
2
3
gcc -S a.i -o a.s
cat a.s|wc-l
59
  • 汇编过程
这个阶段,生成 目标代码
此过程生成ELF格式的目标代码。
1
2
3
gcc -c a.s -o a.o
file a.o
a.o:ELF64-bitLSBrelocatable,AMDx86-64,version1(SYSV),notstripped
连接过程。生成 可执行代码。连接分为两种,一种是 静态连接,另一种是 动态连接。使用静态连接的好处是,依赖的动态连接库较少,对动态连接库的版本不会很敏感,具备较好的兼容性;缺点是生成的程序比较大。使用动态连接的好处是,生成的程序比较小,占用较少的内存。
1
gcc a.o -o a
程序运行:
1
2
./a
hello

处理器架构 编辑

GCC4.1支持下列处理器架构:
Alpha
ARM
Atmel AVR
Blackfin
H8/300
IA-32〈x86〉 与 x86-64
IA-64例如: Itanium
MorphoSys 家族
Motorola 68000
Motorola 88000
System/370,System/390
SuperH
HC12
VAX
Renesas R8C/M16C/M32C家族
较不知名的处理器架构也在官方释出版本中支援:
A29K
ARC
C4x
CRIS
D30V
DSP16xx
FR-30
FR-V
Intel i960
IP2000
M32R
68HC11
MCORE
MN10200
MN10300
NS32K
ROMP
Stormy16
V850
Xtensa
由FSF个别维护的GCC处理器架构:
D10V
MicroBlaze
PDP-10
MSP430
Z8000
当GCC须要移植到一个新平台上,一般使用此平台固有的语言来撰写其初始阶段。

程序除错 编辑

为 GCC 除错的首选工具固然是 GNU 除错器。其余特殊用途的除错工具是 Valgrind, 用以发现内存漏失 (Memory leak)。而 GNU 测量器 ( gprof) 能够得知程序中某些函式花费多少时间,以及其呼叫频率;此功能须要使用者在 编译时选定测量〈profiling〉选项。

使用技巧 编辑

首先检查是否在你的机器上安装了GCC,使用命令:
可用rpm -q gcc 检查。
若是没有安装,请依序检查并安装下面各RPM
libbinutils
binutils
make
glibc-devel
gcc-cpp
gcc
看下面的例子:test.c
1
2
3
4
5
6
7
8
#include<stdio.h>
 
int main()
{
    char *str="I like Linux!I advice you to join in the Linux World";
    printf("%s",str);
    return 0;
}
使用gcc 编译。输入gcc -c test.c获得目标文件test.o.-c命令表示对文件进行编译和 汇编。但并不链接。若是再键入gcc -o ../bin/test test.o,那么将获得名为test的 可执行文件。其实这两步能够一鼓作气,gcc ../bin/test test.c.若是程序没有错误就生成了可执行文件。也许你会以为基于命令行的 编译器比不上如VC之类的 集成开发环境,的确gcc的界面要改进,可是你一旦熟练了就会感到。gcc的效率如此之高。能够告诉你们的是Linux底下强大的C/C++集成开发环境 Kdevelop和Vc同样强大,使用了Gcc编译器。
GNU C 编译器 即gcc是一个功能强大的 ANSI C兼容编译器,你会操做其余操做系统下的一种C编译器,能很快掌握GCC.
一、使用Gcc,Gcc是基于命令行的,使用时一般后跟一些选项和文件名。Gcc的基本用法以下: gcc [options] [filenames] 命令行选项制定操做将对命令行上的每一个给出的文件执行。
二、GCC的经常使用选项
编译选项:gcc有超过100个的编译选项可用。具体的可使用命令man gcc察看
优化选项:用GCC 编译C/C++代码时,它会试着用最少的时间完成编译而且编译后的代码易于调试。易于调试意味着编译后的代码与 源代码有一样的执行顺序,编译后的代码没有通过优化。有不少的选项能够告诉GCC在耗费更多 编译时间和牺牲易调试性的基础上产生更小更快的 可执行文件。这些选项中最典型的就是-O和-O2。-O选项告诉gcc对源代码进行基本优化。-O2选项告诉GCC产生尽量小的和尽量快的代码。还有一些很特殊的选项能够经过man gcc察看。
调试和剖析选项:GCC支持数种调试剖析选项。在这些选项中最经常使用的是-g和-pg.-g选项告诉gcc产生能被GNU调试器(如gdb)使用的调试信息,以便调试用户的程序。-pg选项告诉gcc在用户的程序中加入额外的代码,执行时,产生 gprof用的剖析信息以显示程序的耗时状况。
三、使用gdb
使用方法:在命令行中键入gdb并按回车就能够运行gdb了,启动gdb 后,能在命令行上制定不少的选项,也能够下面的方式来运行gdb: gdb filename 用这种方式运行gdb时,能直接指定想要调试的程序。在命令行上健入gdb -h获得一个有关gdb的选项的说明简单列表。
编译代码以供调试,为了使gdb工做,必须使程序在编译时包含调试信息,调试信息包含程序里的每一个变量的类型,在 可执行文件里的 地址映射以及 源代码行号。gdb利用这些信息使源代码和 机器码相关联。
关于gcc的大致就写这么多吧,更多的信息能够查找帮助,记得学习Linux的一大武器man或者info命令,下次在介绍一下使用C/C++编写大型程序的 makefile文件和make命令。

版本发布 编辑

2012年03月23日,GCC 首个公开发布版本是在 1987 年由 Richard Stallman 发布的,到今天已经整整 25 年了。为了庆祝 25 周年,GCC 也相应发布了 GCC 4.7.0 版本,这是 GCC 一个全新的重要版本。
GCC 4.7.0 带来了一组关于连接时优化 (LTO) 框架可提高伸缩性和下降内存使用,据开发者称,在 64 位系统上须要 8G 内存来对 Firefox 进行优化,然而用了 LTO 后只需 3G。
此外就是体验的支持软件事务内存,支持更多 C++11 标准,包括原子性、C++11 内存模型,用户定义文字、别名声明、构造器委派和可扩展的语法等。
GCC 4.7.0 还改进对 Fortran 的支持,支持 Google Go 1 等等多项改进。 [3]  
2012年06月14日,GCC 4.7.1 发布了,这是一个 bug 修复版本,主要是 4.7.0 中的一些回归测试发现的问题修复。 [4]  
2013年04月11日,GCC 4.7.3 发布。
2013年03月22日,GCC 4.8.0发布,进一步增强了对已C++11的支持。而且G++开始支持-std=c++1y选项,用来支持计划于2014年发布的C++11修订版标准(C++14)。 [5]  
2013年10月16日,GCC 4.8.2发布。提供了对于OpenMP 4.0的支持。
2014年04月22日,GCC发布了4.9.0版本,提供了对 C11标准的Generic Selection语法特性(_Generic)的支持以及对多线程方面特性的支持。

linux中安装 编辑

RedHat中安装

用which gcc命令查看,假若有显示” /usr/bin/gcc”的话说明已经安装了,不然就是没有安装。
这里以redhat 64位 linux为例。首先将redhat的iso系统镜像挂在到/mnt/cdrom目录下:
  mount -o loop /data/rhel-server-5.4-x86_64-dvd.iso /mnt/cdrom
  进入/mnt/cdrom目录,就能够访问iso镜像中的内容了。
  cd /mnt/cdrom
  cd Server/
安装gcc的依赖包以及gcc,按如下命令依次执行:   rpm -ivh binutils-2.17.50.0.6-12.el5.x86_64.rpm   rpm -ivh cpp-4.1.2-46.el5.x86_64.rpm   rpm -ivh kernel-headers-2.6.18-164.el5.x86_64.rpm   rpm -ivh glibc-devel-2.5-42.x86_64.rpm   rpm -ivh glibc-headers-2.5-42.x86_64.rpm   rpm -ivh libgomp-4.4.0-6.el5.x86_64.rpm   rpm -ivh gcc-4.1.2-46.el5.x86_64.rpm   你们在安装rpm包时,因为依赖关系,在安装时会提示“此包依赖其余包xx”,让你先安装其余包,总之你们按照提示来,提示你先安装哪一个包就安装哪一个包。