Loading AI tools
支援各種程式語言的編譯器系統 来自维基百科,自由的百科全书
GNU编译器套裝(英語:GNU Compiler Collection,縮寫為GCC)是GNU計劃制作的一种优化编译器,支持各种编程語言、操作系统、计算机系统结构。该编译器是以GPL及LGPL許可證所發行的自由軟體,也是GNU計劃的关键部分,还是GNU工具链的主要組成部份之一。GCC(特别是其中的C语言编译器)也常被认为是跨平台编译器的事实标准。1985年由理查德·马修·斯托曼開始發展,現在由自由軟體基金會負責維護工作。截至2019年,GCC大约有1500万行代码,是现存最大的自由程序之一。[2] 它在自由软件的发展中发挥了重要作用,不仅是一个工具,还是一个典例。
原名為GNU C語言編譯器(GNU C Compiler),因為它原本只能處理C語言。同年12月,新的GCC编译器可以编译C++语言。后来又为Fortran、Pascal、Objective-C、Java、Ada,Go等其他語言开发了前端。C和C++编译器也支持OpenMP和OpenACC规范。
GCC编译器已经被移植到比其他编译器更多的平台和指令集架构上,并被广泛部署在开发自由和专有软件的工具中。GCC还可用于许多嵌入式系统,包括基于ARM和Power ISA的芯片。
GCC不仅是GNU操作系统的官方编译器,还是许多类UNIX系统和Linux发行版的标准编译器。BSD家族中的大部分操作系统也在GCC发布之后转用GCC;不过FreeBSD、OpenBSD和Apple macOS已经转向了Clang编译器[3],主要是因为许可问题。[4][5][6]GCC也可以编译Windows、Android、iOS、Solaris、HP-UX、IBM AIX和DOS系统的代码。GCC原本用C開發,後來因為LLVM、Clang的崛起,它更快地將開發語言轉換為C++。許多C的愛好者在對C++一知半解的情況下主觀認定C++的性能一定會輸給C,但是Ian Lance Taylor給出了不同的意見,並表明C++不但性能不輸給C,而且能設計出更好,更容易維護的程式[7][8]。
1983年底,为了引导GNU操作系统,理查德·马修·斯托曼向阿姆斯特丹编译器套件(自由大学编译器套件)的作者安德鲁·塔能鲍姆请求在GNU上允许使用该编译器;但是作者告知他该编译器仅对大学免费。因此,他打算开发一个不同的编译器。[9]一开始他打算与Len Tower和其他人将勞倫斯利佛摩國家實驗室的一个现有编译器从Pastel改写成C。[10][11]但是他在给利弗莫尔编译器写了一个新的C前端后,发现它需要数兆字节的堆栈空间,只有64KB的68000 Unix系统上无法运行。因此,他打算自己从头写一个编译器。[10]总而言之,尽管斯托曼确实使用了他自己写的C前端,他并没有将任何Pastel编译器的代码放在GCC中。[10][12]
GCC于1987年3月22日在麻省理工学院的文件传输协议上发布[13],斯托曼被列为作者,也提及了其他人并感谢他们的贡献:Jack Davidson和Christopher Fraser给出了使用暫存器傳遞語言作为中间语言的思路;Paul Rubin为预处理器贡献良多;以及Leonard Tower写了“部分解析器、RTL生成器、RTL定义和Vax机器描述”。[14]被Peter H. Salus誉为“自由软件第一击”的GNU编译器发布正值太阳微系统将其操作系统与其开发工具解绑,并提价单独出售。这使得许多客户购买或下载GCC而非供应商的工具。[15]尽管斯托曼认为GNU Emacs是他的主要工程,但截至1990年,GCC支持13种电脑架构,性能比其他编译器优越并为商业所用。[16]
由于GCC是在GPL许可下授权的,其他为C以外语言编写接口的程序员可以自由的开发其自己的编译器分支,只要他们遵守GPL许可条款。但是,多分叉在日后体现出低效和不便的特点;而且人们很难使热爱稳定性胜过新特性的GCC官方项目接受他们的分支。[17]FSF对添加到GCC 2.x官方版本(1992年开始开发)中的内容进行了相当严格的控制,以至于被Eric S. Raymond在《大教堂与集市》中形容为 "大教堂 "开发模式。
在1997年,一群不滿GCC緩慢且封閉的創作環境者,組織了一個名為实验性/增强型GNU编译器系统(Experimental/Enhanced GNU Compiler System)的專案[17][12],将几个实验性分叉合并为一个项目。其基础是GCC的开发快照(大概取自2.7.2,后来跟进到2.8.1)。合并内容包括g77(Fortran)、PGCC(P5 Pentium优化的GCC)[12],许多C++的改进,以及许多新的架构和操作系统变种。[18]
这两个项目都密切观察着彼此的动态,但是EGCS的发展明显更活跃,因此FSF正式停止他们对GCC 2.x编译器的开发并希望EGCS成为GCC的官方版本。在1999年4月EGCS项目被任命为为GCC的维护者。随着1999年7月GCC 2.95的发布,这两个项目再次联合起来。[19][12]此后,GCC在一个指导委员会的指导下,来自各国的程序员小组会对其进行维护。[20]
由于缺乏维护,GCC 3 (2002)移除了CHILL的前端支持。[21]在版本4.0之前,GCC 3中的Fortran前端是g77
,只支持FORTRAN 77。该前端后来被废弃,取而代之的是新GNU Fortran前端,支持Fortran 95和Fortran 2003及Fortran 2008的大部分内容 。[22][23]从GCC 4.8版开始,GCC由C++语言编写。[24]从GCC 5到GCC 7都保留了对Cilk Plus的支持。[25][26]
GCC已经被移植到各种指令集架构上,并被广泛部署为开发自由或专有软件的工具。GCC还可用于许多嵌入式系统,包括Symbian(称为gcce)[27]、基于ARM和基于Power ISA的芯片。[28]该编译器可以在各种平台上输出,包括游戏控制器中的PS2[29]、Cell微处理器架构的PS3[30]以及Dreamcast。[31]相比于其他编译器,GCC编译器被部署在更多的操作系统和处理器上。[32]
截至2022年9月,GCC 12.2版内含C(gcc
)、C++(g++
)、Objective-C、Fortran(gfortran
)、Ada(GNAT)、Go (gccgo
)以及D (gdc
,从9.1版开始)[33]编程语言的前端。[34]OpenMP和OpenACC并行语言拓展从GCC 5.1开始支持。[35][36]GCC 7之前的版本也支持Java(gcj
),允许将java编译为机器语言。[37]
有关C++和C的语言版本支持,从GCC 11.1开始默认为gnu++17,C++17的超集;以及gnu11,C11的超集,还提供严格的标准支持。GCC也对C++20和即将到来的C++23标准提供实验性部分支持。[38]
有许多为其它语言编写的第三方前端,比如Pascal(gpc
)、Modula-2、Modula-3、Mercury语言以及VHDL(GHDL
)。[34]一些实验性分支可支持更多语言,比如GCC UPC编译器还支持UPC[39]和Rust。[40]
GCC 11.1版本支持的处理器包括:[41]
标准版本支持的少见处理器如下:
非FSF维护的GCC版本支持的处理器如下:
GCJ Java编译器可以输出机器语言或者Java虚拟机的Java字节码。[44]当重定向GCC到新的平台上,经常会用到自举。 Motorola 68000,Zilog Z80以及其他处理器也可在为德州仪器、惠普、夏普以及卡西欧可编程图形计算器设计的GCC编译器上输出。[45]
GCC的外部介面遵循UNIX使用惯例。用户输入特定语言的驱动程序码(C语言为gcc
,C++为g++
,如此不一而足),该程序解释命令语句,调用实际编译器,在输出界面上运行汇编器,然后选择性地运行链接器,产生一个完整的可执行二进制文件。
每种语言的编译器都是一个独立的程序,可读取源代码并输出机器码。所有語言的編譯器都擁有共通的中介架構:各语言前端解析符合此語言的原始碼,並產生一抽象語法樹。如有必要,这些代码会被转换为中介端的输入表示,即所谓的 GENERIC 形式;然后中介端会逐渐将程序转换为最终形式。编译器优化和静态代码分析技术(例如FORTIFY_SOURCE[46],一种尝试发现緩衝區溢位的编译器指令)也会在源代码编译时应用。这些操作都是在多种表示法上工作,其中主要是独立于架构的GIMPLE表示法和独立于架构的RTL表示法。最终,机器码由傑克·戴維森與克里斯·弗雷澤發明的算法产生。
除了Ada前端主要以Ada寫成,GCC大部分是用C语言编写的。GCC发行版包含主要以各自语言编写的Ada和C++标准库。[47]在一些平台上,GCC发行版还包括一个低级运行库libgcc
该运行库由独立于机器的C语言和特定处理器的机器码组合编写,可处理目标处理器不能直接执行的复杂算术运算。[48]
GCC使用了许多额外的工具。虽然这些工具在UNIX和Linux发行版中基本为默认安装的,但是Windows系统通常没有。这些工具包括Perl、Flex、Bison和其他常用工具;还需要额外的依赖库GMP、MPC和MPFR。[49]
2010年5月,GCC指导委员会决定允许使用C++编译器来编译GCC。[50] 编译器计划主要用C语言编写,并加上C++的一个子集特性。之所以这样做是为了了让GCC的开发者能够使用C++的析构器和泛型功能。[51]2012年8月,GCC指导委员会宣布,GCC将以C++为源语言。[52]这意味着,要从源代码编写GCC编译器,需要一个能够理解ISO/IEC C++03标准的C++编译器。2020年5月18日,GCC从ISO/IEC C++03标准转向ISO/IEC C++11标准(即需要改写编译器本身;默认情况下可编译C++早期版本)。[53]
每个前端都使用一个分析器来产生给定的源代码的一个抽象语法树。由于语法树的抽象性,不同语言的源代码都可以被同一个后端处理。GCC一开始使用bison生成的LALR语法分析器,但在2004年逐渐转向用于C++的递归下降解析器[54],并在 2006 年用于C和Objective-C[55]。2021年开始,所有前端都使用递归下降解析器。
在 GCC 4.0 之前,程序的语法树结构不完全独立于输出的目标处理器架构。对于不同语言的前端来说,语法树的含义可能不同;而且前端可以提供它們特別的語法樹規則。随着 GENERIC 和 GIMPLE 的引入,这种情况得以避免。这是两种新的独立于语言的语法树形式,随GCC 4.0引入编译器前端。GENERIC更复杂,是一种基于 GCC 3.x Java 前端的中介表示。 GIMPLE 是一个简化的 GENERIC,其中各种结构被简化为多个 GIMPLE 指令。 C、C++ 和 Java 前端直接在前端生成 GENERIC。 相反,其他前端在解析后会有不同的中介表示,这些中介表示将转换为 GENERIC。前端生成GENERIC之後再使用「gimplifier」技術简化GENERIC的複雜結構,成為一較簡單的以SSA为基礎的GIMPLE形式,一种强大的,独立于语言和体系结构的全局(函数范围)优化的通用语言。
GENERIC 是一种中间表示语言,在将源代码编译成可执行二进制文件时用作“中介端”。GCC的所有前端都指向GENERIC的子集GIMPLE。GCC 的中间阶段进行所有的独立于编译语言和目标架构的代码分析和优化,从 GENERIC 表示法开始[56]将其转译为暫存器傳遞語言(RTL)。GENERIC 表示只包含中介端优化后的指令式编程结构的子集。
在将源代码转译为GIMPLE表示时[57],会使用临时变量将复杂表达式拆分为三位址碼。这种表示法的灵感来自于 Laurie J. Hendren[58] 在 McCAT 编译器[59]中提出的 SIMPLE 表示法,用于简化指令式程序的分析和优化。
一般編譯器作者會將語法樹的最佳化放在前端,但其實此步驟並不看語言的種類而有不同,且不需要用到語法解析器。因此GCC作者們將此步驟歸入通稱為中介階段的部分裡。此類的最佳化包括消解死碼、消解重複運算與全域數值重編碼等。許多最佳化技巧也正在實作中。
GCC的后端部分是由预处理器宏和目标架构特有的函数指定的,例如定义其字节序、字大小和调用约定。后端的前半部分使用这些来决定RTL的生成形式,因此雖然GCC的RTL理論上不受處理器影響,但在此階段其抽象指令已被轉換成目標架構的格式。在任何时候,构成程序的实际RTL指令都必须符合目标架构的机器描述标准。
机器描述文件包含了RTL模式、操作数约束和输出最终汇编的代码片段。这些约束条件表明,一个特定的RTL模式可能只适用于某些硬件寄存器,或者某些只允许有限大小的即时操作数偏移(例如12、16、24、...位偏移,等等)的架构。在RTL生成过程中,给定目标架构的约束条件会被检查。为了发布一个给定的RTL片段,它必须与机器描述文件中的一个或多个RTL模式相匹配,并满足该模式的约束条件;否则,就无法将最终的RTL转换成机器代码。
在编译结束时,有效RTL会被简化为严格的形式,其中每条指令都指向真实的机器寄存器、和目标机器描述文件中的一种模式。严格化RTL是个相当复杂的工作:首先是寄存器分配,选择真实的硬件寄存器来取代最初分配的伪寄存器;还有重载,未分配实际硬件寄存器的伪寄存器都会被溢出到堆栈中,并生成执行此溢出的 RTL。过大的偏移量无法适合实际指令,故会被分解成服从偏移量约束的RTL序列。
後端在最后通过调用与每个模式相关联的一小段代码来构建机器代码,以使用在重载时选择的最终寄存器、偏移量和地址从目标指令集中生成真正的指令。当汇编生成片段只是一个字符串时,就会执行寄存器、偏移量和/或地址到字符串的简单字符串替换。汇编生成片段也可以是一个简短的C代码块,但最终也会返回一个包含有效汇编代码的字符串。
GNU除錯器是一個為GCC除錯的程式。其他特殊用途的除錯工具是Valgrind,用以發現内存泄漏(memory leak)。而GNU測量器(gprof)可以得知程式中某些函式花費多少時間,以及其呼叫頻率;此功能需要使用者在編譯時選定測量(profiling)選項。
内嵌汇编也称行内汇编,是把汇编语言代码块插在C语言语句之间。详情参见GCC-Inline-Assembly-HOWTO.html(页面存档备份,存于互联网档案馆)
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.