详解三大编译器:gcc、llvm 和 clang( 二 )


【详解三大编译器:gcc、llvm 和 clang】兼容性好:Clang 从一开始就被设计为一个API , 允许它被源代码分析工具和 IDE 集成 。 GCC 被构建成一个单一的静态编译器 , 这使得它非常难以被作为 API 并集成到其他工具中 。
Clang有静态分析 , GCC没有 。
Clang使用BSD许可证 , GCC使用GPL许可证 。
详解三大编译器:gcc、llvm 和 clang文章插图

  • GCC 优势
支持 JAVA/ADA/FORTRAN
GCC 支持更多平台
GCC 更流行 , 广泛使用 , 支持完备
GCC 基于 C , 不需要 C++ 编译器即可编译
GCC、LLVM 和 Clang 如何选择?目前不推荐使用老的GCC4.2 , 因为苹果不会维持它了 , 而且LLVM-GCC看起来会更好 。 在项目中途改编译选项可是一个大变动 , 需要慎重 。
对新的项目而言 , LLVM-GCC 看起來应该是个安全的选择 , 苹果公司认为它够稳定够成熟 , 所以才把它当做Xcode 4的预设选项 。 而且 , 既然选项使用的是GCC parser , 向后兼容性应该没问题 。
LLVM-GCC是个安全的选项 , 但并不是指Clang/LLVM比较不安全 , 只是成熟度还沒那么高效了 。
总结 - 再探LLVM回顾GCC的历史 , 虽然它取得了巨大的成功 , 但开发GCC的初衷是提供一款免费的开源编译器 , 仅此而已 。 可后来随着GCC支持了越来越多的语言 , GCC架构的问题也逐渐暴露出来 。 但GCC到底有什么问题呢?LLVM的优点也正是GCC的缺点 。 传统编译器工作的时候前端负责解析源代码 , 检查语法错误 , 并将其翻译为抽象的语法树(Abstract Syntax Tree) 。 优化器对这一中间代码进行优化 , 试图使代码更高效 。 后端则负责将优化器优化后的中间代码转换为目标机器的代码 , 这一过程后端会最大化的利用目标机器的特殊指令 , 以提高代码的性能 。 事实上 , 不光静态语言如此 , 动态语言也符合上面这个模型 , 例如Java 。 JVM也利用上面这个模型 , 将Java代码翻译为Java bytecode 。 这一模型的好处是 , 当我们要支持多种语言时 , 只需要添加多个前端就可以了 。 当需要支持多种目标机器时 , 只需要添加多个后端就可以了 。 对于中间的优化器 , 我们可以使用通用的中间代码 。 这种三段式的结构还有一个好处 , 开发前端的人只需要知道如何将源代码转换为优化器能够理解的中间代码就可以了 , 他不需要知道优化器的工作原理 , 也不需要了解目标机器的知识 。 这大大降低了编译器的开发难度 , 使更多的开发人员可以参与进来 。 虽然这种三段式的编译器有很多优点 , 并且被写到了教科书上 , 但是在实际中这一结构却从来没有被完美实现过 。 做的比较好的应该属Java和.NET虚拟机 。 虚拟机可以将目标语言翻译为bytecode , 所以理论上讲我们可以将任何语言翻译为bytecode , 然后输入虚拟机中运行 。 但是这一动态语言的模型并不太适合C语言 , 所以硬将C语言翻译为bytecode并实现垃圾回收机制的效率是非常低的 。 GCC也将三段式做的比较好 , 并且实现了很多前端 , 支持了很多语言 。 但是上述这些编译器的致命缺陷是 , 他们是一个完整的可执行文件 , 没有给其它语言的开发者提供代码重用的接口 。 即使GCC是开源的 , 但是源代码重用的难度也比较大 。
LLVM最初的定位是比较底层的虚拟机 。 它的出现正是为了解决编译器代码重用的问题 , LLVM一上来就站在比较高的角度 , 制定了LLVM IR这一中间代码表示语言 。 LLVM IR充分考虑了各种应用场景 , 例如在IDE中调用LLVM进行实时的代码语法检查 , 对静态语言、动态语言的编译、优化等 。 从上面这个图中我们发现LLVM与GCC在三段式架构上并没有本质区别 。 LLVM与其它编译器最大的差别是 , 它不仅仅是Compiler Collection , 也是Libraries Collection 。 举个例子 , 假如说我要写一个X语言的优化器 , 我自己实现了PassX算法 , 用以处理X语言与其它语言差别最大的地方 。 而LLVM优化器提供的PassA和PassB算法则提供了X语言与其它语言共性的优化算法 。 那么我可以选择X优化器在链接的时候把LLVM提供的算法链接进来 。 LLVM不仅仅是编译器 , 也是一个SDK 。 Apple LLVM compiler 4.2是一个真正的LLVM编译器 , 前端使用的是Clang , 基于最新的LLVM 3.2编译的 。 LLVM GCC 4.2编译器的核心仍然是LLVM , 但是前端使用的是GCC 4.2编译器 。 从LLVM的下载页面可以看出 , LLVM从1.0到2.5使用的都是GCC作为前端 , 直到2.6开始才提供了Clang前端 。
如果你下载 LLVM 的代码 , 那么它就是一个IR到ARM/机器码的编译器 。 比如bin/opt就是对IR的优化器 , bin/llc就是IR->ASM的翻译 , bin/llvm-mc就是汇编器 。 如果你再从下载Clang , 那么就有了C->IR的翻译以及完整的编译器Driver 。 GDB是GNU的调试器 。 只要编译器支持DWARF格式 , 就可以用GDB调试 。