C-C++编译器-GCC
2010-12-28 16:16:53 阿炯

GCC(GNU Compiler Collection,GNU编译器套装),是一套由GNU开发的编程语言编译器。它是一套以GPLLGPL许可证所发行的自由软件,也是GNU计划的关键部分,亦是自由的类Unix 及苹果计算机 Mac OS X 操作系统的标准编译器。GCC(特别是其中的C语言编译器)也常被认为是跨平台编译器的事实标准。

GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C语言。GCC 很快地扩展,变得可处理 C++。之后也变得可处理 Fortran、Pascal、Objective-C、Java, 以及 Ada 与其他语言。



The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Java, Ada, and Go, as well as libraries for these languages (libstdc++, libgcj,...). GCC was originally written as the compiler for the GNU operating system.

当 RMS 重返自由软件基金会(FSF,Free Software Foundation)董事会时,FSF 董事会并未考虑其他人会如何看待他的回归。鉴于这一事件引发的风波,GCC 指导委员会(GCC Steering Committee)此前已将 RMS 从 GCC 的最初创建者成员中移除,GCC 指导委员会在2021年5月宣布,他们还将放弃长期以来要求所有代码贡献的版权转让给 FSF 的政策。

长期以来,GCC 要求任何代码贡献都要向自由软件基金会转让版权,这对一些开发者或企业而言是个问题。尤其是最近随着自由软件基金会不断受到抨击,反对者中有很多人在倡议要 fork 一个 GNU Compiler Collection(GCC) 并基于此进行开发,抑或是将这个开源编译器完全从自由软件基金会中剥离出来。基于这些原因,GCC 指导委员会决定不再要求有争议的版权转让。GCC 指导委员会表示,GCC 将继续在 GPLv3 下开发,但不再需要 FSF 的版权转让。相反,贡献者可以在他们的 Git 信息中使用带有 Signed-off-by 标签的 Developer Certificate of Origin(开发者起源证书)。

公告全文如下(点击查看原文):
GCC 起初是作为 GNU 项目的一部分创建的,但如今已经发展成一个独立的项目了。

GCC 指导委员会已经决定放宽对所有经过修改的软件的版权都要转让给自由软件基金会的要求。GCC 将继续在 GNU-General Public License v3.0 下开发、分发和授权。GCC 现在将接受包含或不包含 FSF 版权转让的代码贡献。这一变化与许多其他主要的自由软件项目的做法是一致的,例如 Linux 内核。

有 FSF 版权转让的贡献者不需要改变任何东西。希望使用 Developer Certificate of Origin(开发者起源证书)的贡献者应该在他们的提交信息中添加一个 Signed-off-by 信息。有提交权限的开发者可以将他们的名字添加到 MAINTAINERS 文件中的 DCO 列表,以便为所有未来的提交提供 DCO 认证,而不是为每个提交单独提供一个 Signed-off-by 信息。GCC 指导委员会继续肯定自由软件的原则,这一点将永远不会改变。

GCC由一系列阶段组成,并由一个驱动程序将其紧密结合在一起。它们是:预处理器、解析器、代码生成器、汇编器和链接器。前三个阶段都接受可读文本格式的输入,然后输出可读的文件格式(汇编器必须输出而链接器必须输入二进制格式,这一点从定义便可理解)。运用gcc驱动程序的没命令行选项不仅可以看到C处理之后、汇编生成之后和目标码生成之后的各个结果,而且可以监控解析进程和代码生成进程中的许多中间步骤的结果。这种组织有很多好处,其中对GCC特别重要的一个好处体现在回归测试中。

GCC 有超过100个的编译选项可用. 这些选项中的许多你可能永远都不会用到, 但一些主要的选项将会频繁用到. 很多的 GCC 选项包括一个以上的字符. 因此你必须为每个选项指定各自的连字符, 并且就象大多数 Linux 命令一样不能在一个单独的连字符后跟一组选项.例如下面的两个命令是不同的:
gcc -p -g test.c
gcc -pg test.c

第一条命令告诉 GCC 编译 test.c 时为 prof 命令建立剖析(profile)信息并且把调试信息加入到可执行的文件里. 第二条命令只告诉 GCC 为 gprof 命令建立剖析信息.当不用任何选项编译一个程序时, GCC 将会建立(假定编译成功)一个名为 a.out 的可执行文件,能用 -o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out. 例如,将一个叫 count.c 的 C 程序编译为名叫 count 的可执行文件, 可输入下面的命令:
gcc -o count count.c

注意当使用 -o 选项时, -o 后面必须跟一个文件名。  

GCC 同样有指定编译器处理多少的编译选项. -c 选项告诉 GCC 仅把源代码编译为目标代码而跳过汇编和连接的步骤. 这个选项使用的非常频繁因为它使得编译多个 C 程序时速度更快并且更易于管理.缺省时 GCC 建立的目标代码文件有一个 .o 的扩展名.

-S 编译选项告诉 GCC 在为 C 代码产生了汇编语言文件后停止编译. GCC 产生的汇编语言文件的缺省扩展名是 .s . -E 选项指示编译器仅对输入文件进行预处理. 当这个选项被使用时, 预处理器的输出被送到标准输出而不是储存在文件里.

优化选项
当用 GCC 编译 C 代码时, 它会试着用最少的时间完成编译并且使编译后的代码易于调试. 易于调试意味着编译后的代码与源代码有同样的执行次序, 编译后的代码没有经过优化. 有很多选项可用于告诉 GCC 在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件. 这些选项中最典型的是-O 和 -O2 选项.

-O 选项告诉 GCC 对源代码进行基本优化. 这些优化在大多数情况下都会使程序执行的更快. -O2 选项告诉 GCC 产生尽可能小和尽可能快的代码. -O2 选项将使编译的速度比使用 -O 时慢. 但通常产生的代码执行速度会更快.除了 -O 和 -O2 优化选项外, 还有一些低级选项用于产生更快的代码. 这些选项非常的特殊, 而且最好只有当你完全理解这些选项将会对编译后的代码产生什么样的效果时再去使用. 这些选项的详细描述, 请参考 GCC 的指南页, 在命令行上键入 man gcc .

调试和剖析选项
GCC 支持数种调试和剖析选项,在这些选项里你会最常用到的是 -g 和 -pg 选项.

-g 选项告诉 GCC 产生能被 GNU 调试器使用的调试信息以便调试你的程序. GCC 提供了一个很多其他 C 编译器里没有的特性, 在 GCC 里你能使 -g 和 -O (产生优化代码)联用. 这一点非常有用因为你能在与最终产品尽可能相近的情况下调试你的代码. 在你同时使用这两个选项时你必须清楚你所写的某些代码已经在优化时被 GCC 作了改动.

-pg 选项告诉 GCC 在你的程序里加入额外的代码, 执行时, 产生 gprof 用的剖析信息以显示你的程序的耗时情况.
 
另外提供了一个叫 gdb 的 GNU 调试程序用来调试 C 和 C++ 程序的强力调试器. 它能在程序运行时观察程序的内部结构和内存的使用情况,以下是 gdb 所提供的一些功能:
它使你能监视你程序中变量的值.
它使你能设置断点以使程序在指定的代码行上停止执行.
它使你能一行行的执行代码.

为了使 gdb 正常工作, 必须使你的程序在编译时包含调试信息. 调试信息包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号.  gdb 利用这些信息使源代码和机器码相关联.在编译时用 -g 选项打开调试选项。它支持很多的命令来实现不同的功能.这些命令从简单的文件装入到允许检查所调用的堆栈内容的复杂命令,下面列出了在用 gdb 调试时会用到的一些命令.

命令     描 述
file     装入想要调试的可执行文件.
kill     终止正在调试的程序.
list     列出产生执行文件的源代码的一部分.
next     执行一行源代码但不进入函数内部.
step     执行一行源代码而且进入函数内部.
run     执行当前被调试的程序
quit     终止 gdb
watch     使你能监视一个变量的值而不管它何时被改变.
break     在代码里设置断点, 这将使程序执行到这里时被挂起.
make     使你能不退出 gdb 就可以重新产生可执行文件.
shell     使你能不离开 gdb 就执行 UNIX shell 命令.
 
gdb 支持很多与 UNIX shell 程序一样的命令编辑特征. 你能象在 bash 或 tcsh里那样按 Tab 键让 gdb 帮你补齐一个唯一的命令, 如果不唯一的话 gdb 会列出所有匹配的命令. 也能用光标键上下翻动历史命令.

xxgdb 是 gdb 的一个基于 X Window 系统的图形界面.  xxgdb 包括了命令行版的 gdb 上的所有特性.  xxgdb 使你能通过按按钮来执行常用的命令. 设置了断点的地方也用图形来显示.

cproto 读入 C 源程序文件并自动为每个函数产生原型申明,用它可以在写程序时为你节省大量用来定义函数原型的时间.

indent 实用程序是 Linux 里包含的另一个编程实用工具. 这个工具简单的说就为你的代码产生美观的缩进的格式. indent 也有很多选项来指定如何格式化你的源代码.indent 并不改变代码的实质内容, 而只是改变代码的外观. 使它变得更可读,这永远是一件好事。

gprof 是安装在你的 Linux 系统的 /usr/bin 目录下的一个程序. 它使你能剖析你的程序从而知道程序的哪一个部分在执行时最费时间.将告诉程序里每个函数被调用的次数和每个函数执行时所占时间的百分比.如果想提高程序性能的话这些信息非常有用.

为了在程序上使用 gprof, 必须在编译程序时加上 -pg 选项. 这将使程序在每次执行时产生一个叫 gmon.out 的文件. gprof 用这个文件产生剖析信息.在运行了你的程序并产生了 gmon.out 文件后你能用下面的命令获得剖析信息:
gprof <program_name>

参数 program_name 是产生 gmon.out 文件的程序的名字.

技巧: gprof 产生的剖析数据很大, 如果想检查这些数据的话最好把输出重定向到一个文件里.  

f2c 和 p2c 是两个源代码转换程序. f2c 把 FORTRAN 代码转换为 C 代码, p2c 把 Pascal 代码转换为 C 代码. 当你安装 GCC 时这两个程序都会被安装上去.

如果有一些用 FORTRAN 或 Pascal 写的代码要用 C 重写的话, f2c 和 p2c 对你非常有用. 这两个程序产生的 C 代码一般不用修改就直接能被 GCC 编译.如果要转换的 FORTRAN 或 Pascal 程序比较小的话可以直接使用 f2c 或 p2c 不用加任何选项. 如果要转换的程序比较庞大, 包含很多文件的话你可能要用到一些命令行选项.


GCC Rust 得到批准将被纳入主线代码库

GCC Front-End For Rust(也称为 GCC Rust)是 Rust 语言在 GCC 之上的一个完整替代性实现,目标是成为 GNU 工具链的完全上游。由于这是一个前端项目,该编译器将获得对所有 GCC 内部中端优化通道的完全访问权,这与 LLVM 不同。这个编译器的用户可以使用熟悉的 -O2 标志来调整 GCC 的优化器。与 GCC 的紧密结合将对一些项目很有帮助,这些项目也将能够从 GCC 插件中受益。当然 GCC 也会带来对更多目标架构的支持,基于 GCC 的 Rust 编译器将使 GCC Rust 在新的平台上更加容易启动。


在该项目创立时,Rust 还处于 0.9 版本,随着 Rust 语言已经足够稳定,这是创建替代性编译器的绝佳时机。从 2020 年 11 月开始,开发者 Philip Herron 就已全职从事 GCC Rust 的开发工作,在他和整个社区的共同努力下,GCC 指导委员会于2022年7月中旬正式宣布接受 GCC Rust 对 GCC 的贡献,GCC Rust 将被纳入其主线代码库,由 GCC 提供 Rust 编程语言支持。这个 Rust 前端可能会在2023年的 GCC 13 发布之前被合并,而 GCC 13 将在2023年4月左右作为稳定版发布。

该项目仍处于早期阶段,目标是率先实现编译官方的 Rust 测试套件,目前也暂时不会支持 proc_macro crate 和 Rust 借用检查器这样的功能。开发者希望 GCC Rust 在 GCC 13 中对 Rust 编程语言至少有 "测试" 级别的支持。Rust 的设计准则为“安全、并发、实用”,在确保性能和原生编译语言一样的同时,能够实现内存安全。这样的特性也促使如今有越来越多的公司开始使用 Rust 编程语言,支持 Rust 项目。Rust for Linux 也有望在 Linux 5.20 中实现。

GCC版本更新录(202x)


项目主页:http://gcc.gnu.org/

该文章最后由 阿炯 于 2023-04-27 15:41:05 更新,目前是第 3 版。