编译器的大致构成传统的编译器通常分为三部分,前端(frontEnd)、优化器(Optimizer)和后端(backEnd)。在编译过程中,前端主要负责词法和语法分析,将源代码转化为抽象语法树;优化器在前端的基础上对得到的中间代码进行优化,使代码更加高效;优化的中间代码被转换为相应平台的机器代码。GCCGCC(GNUCompilerCollection,GNUCompilerSuite),是由GNU开发的一套程序语言编译器。GCC以前被称为GNUC编译器,因为它最初只能处理C语言。GCC迅速发展以处理C++、Fortran、Pascal、Objective-C、Java和Ada等语言。LLVMLLVM(LowLevelVirtualMachine,底层虚拟机)提供编译器相关的支持,可以进行编译时优化,链接优化,在线编译优化,以及编程语言的代码生成。总之,可以作为各种编译器的后台。Apple一直使用GCC作为官方编译器。GCC作为一个开源的编译器,一直做的不错,但是Apple会对编译工具提出更高的要求。主要原因有以下几点:第一,苹果给Objective-C语言增加了很多特性(包括后来给C语言),但是GCC开发者不买苹果的帐——他们没有实现,所以干脆后来实现了二。分为两个分支,分别开发,这也导致苹果的编译器版本远远落后于GCC的正式版。第二,GCC的代码耦合度太高,很难独立,而且越晚的版本,代码质量越差,但是苹果要做的很多功能(比如更好的IDE支持)都需要在里面调用GCC的一种模块化方式,但是GCC没有给它。编译大师ChrisLattner出生于2000年,和中国大多数大学生一样,本科毕业的ChrisLattner一步步通过GRE考试,最终来到UIUC(伊利诺伊大学厄巴纳-香槟分校)开始了他的人生。努力攻读计算机科学硕士和博士学位。职业。这一阶段,他不仅走遍了美国各大景点,还变身了《Compilers: Principles, Techniques, and Tools》,成为了GPA满分(4.0)的大师,并不断研究和探索编译器的未知领域,发表了一篇又一篇论文,在他的硕士论文中,他提出了一整套在编译时、链接时、运行时甚至空闲时优化程序的编译思想,直接为LLVM奠定了基础。LLVM在他读博士的时候比较成熟,以GCC为前端对用户程序进行语义分析生成IF(IntermidiateFormat),然后LLVM利用分析结果完成代码优化和生成。这项研究使他在2005年毕业时成为业界知名的编译器专家。因此,他很早就被苹果盯上了,并最终成为其编译器项目的骨干。一进入苹果,ChrisLattner就大显身手:首先,他在OpenGL团队做了代码优化,将LLVM运行时编译放在了OpenGL栈上,让OpenGL栈可以产生更高效的图形代码。如果显卡够先进,这些代码直接扔进GPU执行。但是对于一些不支持所有OpenGL特性的显卡(比如当时的IntelGMA卡),LLVM可以将这些指令优化为高效的CPU指令,让程序依然可以正常运行。这个强大的OpenGL实现被用于后来的MacOSX10.5版本中。同时将LLVM的链接优化直接加入Apple的代码链接器,LLVM-GCC也同步使用GCC4.0代码。LLVM2.0——ClangApple吸纳ChrisLattner的目的比改进GCC代码更雄心勃勃——苹果打算从头开始编写C、C++、Objective-C语言的前端Clang,完全取代GCC。Clang是LLVM的前端,可以用来编译C、C++、ObjectiveC等语言。Clang是一个高效易用的编译前端,以LLVM为后端,与IDE结合得很好。Clang只支持三种语言:C、C++和Objective-C。2007年开始开发,最先完成C编译器。由于Objective-C只是C语言的简单扩展,所以比较简单。在很多情况下,它甚至可以等效地重写为从C语言到Objective-C运行时库的函数调用。2009年,全面具备投产条件。后来也支持C++。GCC和Clang比Clang更快的特点:通过在OSX上编译包含几乎所有C头文件的carbon.h,包括预处理(Preprocess)、语法(lex)、解析(parse)、语义分析(SemanticAnalysis)),抽象语法树(AbstractSyntaxTree)的生成时间,Clang比GCC快2倍以上。内存占用小:Clang的内存占用是源代码的130%,AppleGCC的是10倍以上。诊断信息可读性强:不仅有语法错误的源码提示,还有~~~~~和^在错误调用及相关上下文下方的提示。和GCC的提示比起来,就很莫名其妙了。良好的兼容性:Clang从一开始就是作为API设计的,允许它被源代码分析工具和IDE集成。GCC是作为单个静态编译器构建的,这使得API和集成到其他工具中变得非常困难。Clang有静态分析,GCC没有。Clang使用BSD许可证,GCC使用GPL许可证。GCC优势支持JAVA/ADA/FORTRANGCC支持更多平台GCC更流行,应用广泛,支持全面GCC基于C,无需C++编译器即可编译GCC、LLVM、Clang如何选择?旧的GCC4.2目前已被弃用,因为Apple将不再维护它,而LLVM-GCC看起来会更好。项目中途更改编译选项属于大改动,需谨慎。对于新项目,LLVM-GCC似乎是一个安全的选择。Apple认为它足够稳定和成熟,因此它是Xcode4的默认选项。另外,由于选项使用的是GCC解析器,因此向后兼容应该没问题。LLVM-GCC是一个安全的选择,但并不意味着Clang/LLVM不那么安全,只是成熟度没那么高效。总结——重温LLVM回顾GCC的历史,虽然取得了巨大的成功,但开发GCC的初衷只是提供一个免费的开源编译器,仅此而已。但是后来随着GCC支持的语言越来越多,GCC架构的问题也逐渐暴露出来。但是GCC究竟有什么问题呢?LLVM的优点也是GCC的缺点。传统编译器工作时,前端负责解析源代码,检查语法错误,并将其翻译成抽象语法树(AbstractSyntaxTree)。优化器优化这个中间代码,试图使代码更高效。后端负责将优化器优化后的中间代码转换为目标机器的代码。在这个过程中,后端会最大限度地利用目标机器的特殊指令来提高代码的性能。其实不仅是静态语言,动态语言也符合上述模型,比如Java。JVM也使用上述模型将Java代码翻译成Java字节码。这种模式的好处在于,当我们要支持多种语言时,只需要添加多个前端即可。当需要支持多台目标机时,只需添加多个后端即可。对于中间优化器,我们可以使用通用中间代码。这种三级结构还有另一个优点。开发前端的人只??需要知道如何将源代码转换成优化器可以理解的中间代码即可。他不需要知道优化器的工作原理,也不需要了解目标机器的知识。这大大降低了编译器开发的难度,让更多的开发者参与进来。虽然这种三段式编译器有很多优点,并且写在教科书上,但这种结构在实践中一直没有得到完美的实现。比较好的应该是Java和.NET虚拟机。虚拟机可以把目标语言翻译成字节码,所以理论上我们可以把任何语言翻译成字节码,然后输入到虚拟机中运行。但是这种动态语言模型不太适合C语言,所以强行将C语言翻译成字节码并实现垃圾回收机制的效率很低。GCC也让三阶段的方法变得更好,实现了很多前端,支持很多语言。但上述编译器的致命缺陷是它们是一个完整的可执行文件,没有为其他语言的开发者提供代码复用接口。尽管GCC是开源的,但很难重用源代码。LLVM最初的定位是一个比较底层的虚拟机。它的出现正是为了解决编译器代码重用的问题。LLVM一上来就站在比较高的角度,制定了中间代码表示语言LLVMIR。LLVMIR充分考虑了各种应用场景,比如在IDE中调用LLVM进行实时代码语法检查,编译优化静态和动态语言等。从上图我们发现LLVM和GCC没有本质区别在三级架构中。LLVM与其他编译器最大的区别在于它不仅是一个CompilerCollection,还是一个LibrariesCollection。比如我要为X语言写一个优化器,我自己实现PassX算法来处理X语言和其他语言最大的区别。LLVM优化器提供的PassA和PassB算法提供了X语言和其他语言通用的优化算法。然后我可以在链接的时候选择X优化器在LLVM提供的算法中进行链接。LLVM不仅仅是一个编译器,还是一个SDK。AppleLLVMcompiler4.2是真正的LLVM编译器,前端使用Clang,基于最新的LLVM3.2编译。LLVMGCC4.2Compiler核心依然是LLVM,但是前端使用了GCC4.2编译器。从LLVM下载页面可以看出,LLVM从1.0到2.5都是使用GCC作为前端,直到2.6才提供Clang前端。如果您下载LLVM的代码,它是一个IR到ARM/机器代码的编译器。比如bin/opt是IR的优化器,bin/llc是IR->ASM的翻译,bin/llvm-mc是汇编器。如果您从http://llvm.org下载Clang,那么您将拥有C->IR的翻译和完整的编译器驱动程序。GDB是GNU的调试器。只要编译器支持DWARF格式,就可以用GDB调试。
