详解三大编译器: gcc、llvm 和 clang (icc/icpc/ifort)
最佳答案 问答题库818位专家为你答疑解惑
目录
- 1. 详解三大编译器: gcc、llvm 和 clang (icc/icpc/ifort)
- 1.1. 编译器一般构成
- 1.2. GCC
- 1.3. LLVM
- 1.4. 编译器大神 Chris Lattner 横空出世
- 1.5. LLVM2.0 - Clang
- 1.6. GCC 和 Clang 对比
- 1.6.1. Clang 特性
- 1.6.2. GCC 优势
- 1.7. GCC、LLVM 和 Clang 如何选择?
- 1.8. 总结 - 再探 LLVM
- 1.9. icc icpc ifort
- 1.9.1. 什么是 ICC/GCC?
1. 详解三大编译器: gcc、llvm 和 clang (icc/icpc/ifort)
clang+llvm 构成一个完整的编译器。题主大概是这个意思。clang 是前端, llvm 是后端, 它们统称为 LLVM。
1.1. 编译器一般构成
传统的编译器通常分为三个部分, 前端 (frontEnd), 优化器 (Optimizer) 和后端 (backEnd). 在编译过程中, 前端主要负责词法和语法分析, 将源代码转化为抽象语法树; 优化器则是在前端的基础上, 对得到的中间代码进行优化, 使代码更加高效; 后端则是将已经优化的中间代码转化为针对各自平台的机器代码。
1.2. GCC
GCC(GNU Compiler Collection, GNU 编译器套装), 是一套由 GNU 开发的编程语言编译器。GCC 原名为 GNU C 语言编译器, 因为它原本只能处理 C 语言。GCC 快速演进, 变得可处理 C++、Fortran、Pascal、Objective-C、Java 以及 Ada 等他语言。
1.3. LLVM
LLVM (Low Level Virtual Machine, 底层虚拟机)) 提供了与编译器相关的支持, 能够进行程序语言的编译期优化、链接优化、在线编译优化、代码生成。简而言之, 可以作为多种编译器的后台来使用。
苹果公司一直使用 GCC 作为官方的编译器。GCC 作为一款开源的编译器, 一直做得不错, 但 Apple 对编译工具会提出更高的要求。原因主要有以下两点:
其一, 是 Apple 对 Objective-C 语言(包括后来对 C 语言)新增很多特性, 但 GCC 开发者并不买 Apple 的账——不给实现, 因此索性后来两者分成两条分支分别开发, 这也造成 Apple 的编译器版本远落后于 GCC 的官方版本。
其二, GCC 的代码耦合度太高, 很难独立, 而且越是后期的版本, 代码质量越差, 但 Apple 想做的很多功能(比如更好的 IDE 支持), 需要模块化的方式来调用 GCC, 但 GCC 一直不给做。
1.4. 编译器大神 Chris Lattner 横空出世
2000 年, 本科毕业的 Chris Lattner 像中国多数大学生一样, 按部就班地考了 GRE, 最终前往 UIUC(伊利诺伊大学厄巴纳香槟分校), 开始了艰苦读计算机硕士和博士的生涯。在这阶段, 他不仅周游美国各大景点, 更是翻烂了《Compilers: Principles, Techniques, and Tools》, 成了 GPA 满分 (4.0) 牛人, 并不断地研究探索关于编译器的未知领域, 发表了一篇又一篇的论文。他在硕士毕业论文里提出了一套完整的在编译时、链接时、运行时甚至是在闲置时优化程序的编译思想, 直接奠定了 LLVM 的基础。LLVM 在他念博士时更加成熟, 使用 GCC 作为前端来对用户程序进行语义分析产生 IF(Intermidiate Format), 然后 LLVM 使用分析结果完成代码优化和生成。这项研究让他在 2005 年毕业时就成为了业界小有名气的编译器专家, 他也因此早早地被 Apple 盯上, 最终成为其编译器项目的骨干。
刚进入 Apple, Chris Lattner 就大展身手: 首先在 OpenGL 小组做代码优化, 把 LLVM 运行时的编译架在 OpenGL 栈上, 这样 OpenGL 栈能够产出更高效率的图形代码。如果显卡足够高级, 这些代码会直接扔入 GPU 执行。但对于一些不支持全部 OpenGL 特性的显卡(比如当时的 Intel GMA 卡), LLVM 则能够把这些指令优化成高效的 CPU 指令, 使程序依然能够正常运行。这个强大的 OpenGL 实现被用在了后来发布的 Mac OS X 10.5 上。同时, LLVM 的链接优化被直接加入到 Apple 的代码链接器上, 而 LLVM-GCC 也被同步到使用 GCC4.0 代码。
1.5. LLVM2.0 - Clang
Apple 吸收 Chris Lattner 的目的要比改进 GCC 代码更具野心 – Apple 打算从零开始写 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++ 在后来也得到了支持。
1.6. GCC 和 Clang 对比
1.6.1. Clang 特性
速度快: 通过编译 OS X 上几乎包含了所有 C 头文件的 carbon.h 的测试, 包括预处理 (Preprocess), 语法 (lex), 解析 (parse), 语义分析 (Semantic Analysis), 抽象语法树生成 (Abstract Syntax Tree) 的时间, Clang 比 GCC 快 2 倍多。
内存占用小: Clang 内存占用是源码的 130%, Apple GCC 则超过 10 倍。
诊断信息可读性强: 其中错误的语法不但有源码提示, 还会在错误的调用和相关上下文的下方有~~~~~和^的提示, 相比之下 GCC 的提示很天书。
兼容性好: Clang 从一开始就被设计为一个 API, 允许它被源代码分析工具和 IDE 集成。GCC 被构建成一个单一的静态编译器, 这使得它非常难以被作为 API 并集成到其他工具中。
Clang 有静态分析, GCC 没有。
Clang 使用 BSD 许可证, GCC 使用 GPL 许可证。
1.6.2. GCC 优势
支持 JAVA/ADA/FORTRAN
GCC 支持更多平台
GCC 更流行, 广泛使用, 支持完备
GCC 基于 C, 不需要 C++ 编译器即可编译
1.7. GCC、LLVM 和 Clang 如何选择?
目前不推荐使用老的 GCC 4.2, 因为苹果不会维持它了, 而且 LLVM-GCC 看起来会更好。在项目中途改编译选项可是一个大变动, 需要慎重。
对新的项目而言, LLVM-GCC 看起來应该是个安全的选择, 苹果公司认为它够稳定够成熟, 所以才把它当做 Xcode 4 的预设选项。而且, 既然选项使用的是 GCC parser, 向后兼容性应该没问题。
LLVM-GCC 是个安全的选项, 但并不是指 Clang/LLVM 比较不安全, 只是成熟度还沒那么高效了。
1.8. 总结 - 再探 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 就是汇编器。如果你再从 http://llvm.org 下载 Clang, 那么就有了 C->IR 的翻译以及完整的编译器 Driver。GDB 是 GNU 的调试器。只要编译器支持 DWARF 格式, 就可以用 GDB 调试。
1.9. icc icpc ifort
- Intel 编译器编译 C 和 C++源程序的编译命令分别为
icc
和icpc
; - 编译 Fortran 源程序的命令为
ifort
。
icpc 命令使用与 icc 命令相同的编译器选项, 利用 icpc 编译时将后缀为 .c
和 .i
的文件看作为 C++文件; 而利用 icc 编译时将后缀为 .c
和 .i
的文件则看作为 C 文件。用 icpc 编译时, 总会链接 C++ 库; 而用 icc 编译时, 只有在编译命令行中包含 C++源文件时才链接 C++ 库。
在 Intel 数学库 (Intelmath) 中的许多函数针对 Intel 微处理器相比针对非 Intel 微处理器做了非常大的优化处理。
1.9.1. 什么是 ICC/GCC?
CPU 这东西, 大家除了关注工艺、主频、核心数量等规格信息之外, 更在意的应该就是性能表现了。反应 CPU 性能的测试可谓是相当多样, 但要说起最权威的, 那就不得不提 SPEC CPU 测试了。
SPEC 的全称是 Standard Performance Evaluation Corporation, 翻译过来是标准性能评估组织, 它是一个全球性的第三方非营利性组织, 由计算机厂商、系统集成商、大学、研究机构、咨询等多家公司组成, 目标是建立、维护一套用于评估计算机系统的标准。
在 CPU 性能测试上, SPEC CPU 2006 是 SPEC 组织推出的最新版的软件(上一个版本 SPEC CPU 2000 已经基本没有人用了), 同时也是最受行业认可的测试软件。SPEC CPU 2006 包括了 CINT2006 和 CFP2006 两个子项目, 前者用于测量和对比整数性能, 而后者则用于测量和对比浮点性能。在各种处理器的 SPEC CPU 2006 测试结果上, 我们往往会看到 ICC 或是 GCC 的字样, 那么 ICC 和 GCC 又分别代表什么呢?
什么是 ICC/GCC?
ICC: 全称 Intel C++ Compiler, 是 Intel 开发的 C/C++/Fortran 编译器套装, 适用于 Linux、Microsoft 和 Mac OS X 操作系统, 没有非 IA 指令集版本(就是说仅供 x86 架构 CPU 使用)。ICC 广泛应用于高性能计算、分布式计算等商业计算领域, 其向量化和并行化性能是业界的标杆, 能够充分发挥现代处理器的特性。
Parallel Studio XE 和 System Studio
▲ICC 编译器套装提供两个版本, 针对高性能计算机测试采用前者, 而后者面向嵌入式及移动设备。
GCC: 全称 GNU Compiler Collection, GNU 编译器套装, 是广泛应用的 Linux 系统的默认编译器(特别是用于编译 Linux 内核)。GCC 能够支持多种架构的处理器, 跨平台特性相对出色。不过, GNU 组织要求全部的代码由自己完成(防止版权问题), 所以 GCC 虽然有广泛的硬件支持, 但是在各硬件平台上却并不是性能最优的编译器。
▲GCC 官方 LOGO
到底啥是编译器?
所谓编译器, 就是将"一种语言(通常为高级语言)"翻译为"另一种语言(通常为低级语言→汇编语言)"的程序。它的主要工作流程:
高级语言源代码→预处理器→编译器→汇编语言, 汇编语言再经过汇编器→目标文件→链接器生成可执行程序。
在这个流程中, 高级语言指的就是源代码, 如 Pascal、C、C++、fortran、Java 等, 而目标文件指的是包含 CPU 可以执行的二进制指令的集合。也就是说, 编译器起到的作用就是将程序源代码"翻译"成汇编语言, 既然是"翻译"工作, 往往就有 Good 和 Better 的区别, 而从上面的介绍我们能够看出, 不同的操作系统, 能够使用的编译器是不同的, 那这个编译效率自然也就存在差异。
同时, CPU 也是区分不同架构的, 比如 x86、MIPS、ARM、Power 等等, 不同架构的 CPU 往往运行不同的操作系统, 如 x86 架构 CPU 可以运行 Windows、Linux(Android)和 Mac OS X, 而 MIPS 等其他架构 CPU 往往只能运行基于 Linux 开发的操作系统。
所以, 不同架构的 CPU, 根据适合的操作系统, 在 SPEC CPU 测试过程中编译器的选择上是不一定是唯一的, 而选择哪一种编译器, 站在 CPU 研发者的角度上, 无疑会选择能让 CPU 性能发挥到最大的编译器。
通过前面对 ICC 和 GCC 的解读, 不难看出两者的区别。ICC 和 GCC 都可以运行在 Windows 和 Linux 下, Intel 是 x86 架构 CPU 的老大, 配合 x86 架构 CPU 开发了 ICC, 能够最大程度的发挥出 x86 架构 CPU 的真实性能。GCC 能够配合更多种类架构的 CPU 加以使用, 适用平台更广, 但从 CPU 性能发挥的角度上看, 大而广很难和专而精比拼。
但是, 综合 x86 CPU 和 Windows 系统的市场占有率这两个因素来看, 在 CPU 测试过程中, ICC 和 GCC 的采用率又是怎样呢?
第三方商业机构更多采用 ICC, GCC 寥寥无几
SPEC 官网(http://spec.org/)上公布着大量的专业机构测试结果供大家研究分析, 笔者选定了全部的整数单笔者选定了全部的整数单任务测试结果进行分析, 通过爬虫抓取了约 8600 个测试结果, 并对测试中使用的编译器进行了数据统计:
结果是使用 ICC 编译器的测试结果高达 95%, 而 GCC 不足 0.1%。这些测试结果基本都是独立的第三方商业机构的测试结果, 具有很高的参考价值。数据显示, ICC 编译器的使用在 SPEC CPU 2006 测试中具有压倒性的优势, 而 GCC 则几乎没有商业机构使用。
上述统计还反映了一个事实, 就是 Intel 和 AMD 的 x86 架构处理器在桌面及服务器领域的垄断性优势。而从其中非 x86 架构 CPU 的测试结果来看, 仅剩的数个测试成绩, Power、Sparc 全部使用的是针对自家指令集优化过的编译器, 而非 GCC, 这也侧面反映了 GCC"大而广"的一些问题。
产生这个现象的原因要从 SPEC CPU 测试成绩产生方法来说起: SPEC 组织使用一台 1997 年的 Ultra Enterprise 2 主机(处理器为 296MHz UltraSPARC II Processor)作为参考对象, 在其上运行了全部的 SPEC CPU 2006 子测试, 并把每一项的测试结果的用时(中间数)定位系数 1。
实际测试中, 假定被测试的 CPU 运行某项子测试的用时为 A, 而 Ultra Enterprise 2 主机同一项子测试用时为 B, 则用 B/A, 即可得到被测试 CPU 该项子测试的成绩, 而各子测试成绩的几何平均值记为总成绩。
即 SPEC 各子项成绩是相对于 Ultra Enterprise 2 计算出来的(Ultra Enterprise 2 各项成绩计为 1, 总分也是 1)。
参考机器(Ultra Enterprise 2 主机)的测试结果也公布在 spec.org 网站上面:
https://www.spec.org/cpu2006/results/res2006q3/cpu2006-20060513-00001.html
从中可以看出的是, 作为参考成绩的测试结果也并没有使用 GCC, 而是 Sparc 自家的编译器。
ICC GCC 哪个更好?
实际上, SPEC CPU 测试的是应用程序的运行时间, 这个是被测机器处理器、缓存、内存、编译器、操作系统等等部分性能的综合体现, 并不是某个编译器或者某个 CPU 的单独测试结果, 而且软硬件平台综合体现的结果, 即按照官方规则正确跑出来的分都是可比的。SPEC CPU 测试结果追求的是程序运行用时越短越好, 测试成绩的优劣固然重要, 但是编译器的真正的用途是"翻译语言", 在同样的硬件平台(CPU)下, "翻译"的越快就可以理解为应用启动或进行某种运算的用时更少, 这就是选择编译器的重要性, 也是现代应用优化的方向。
拿 ICC 和 GCC 相比, ICC 是针对 x86 架构 CPU 使用的编译器, ICC 在现代高性能计算领域广泛使用的向量化、并行化能力较强, 而 GCC 作为跨平台性的编译器, 在这方面性能较差, 但是针对某些偏门的 CPU 指令集而言, GCC 是唯一的选择。
ICC、GCC 两者广泛应用于商业环境中、都会被应用于处理器、OS 及编译器开发、测试之中。有些爱好者担心 ICC 过度优化, 结果不准确, 其实这大可不必。SPEC CPU 是有严格的测试标准的, 每一项测试都要求严格和参考结果一致, 任何过度优化导致的程序计算错误都不会被计算在结果之中。实际上, ICC 在多年的高性能计算领域已经证明了自己的可靠性, 而 GCC 在过往版本中, 也会有编译出错、计算结果不正确等现象。
Closed Source 和 Open Source.
▲ICC GCC 区别好比如此, 懂得人自然懂
最后笔者想要强调的是, 硬件平台性能发挥需要合适的编译器来加以配合, 合适的才是最好的, 如果编译器不能合理使用, 那又有何意义呢?
99%的人还看了
相似问题
- 编译器安全
- Linux——编译器gcc/g++、调试器gdb以及自动化构建工具makefilemake详解
- AI 引擎系列 5 - 以 AI 引擎模型为目标运行 AI 引擎编译器(2022.1 更新)
- 基于Google Colaboratory安装Go语言编译器操作流程
- AI 引擎系列 4 - 首次运行 AI 引擎编译器和 x86simulator(2022.1 更新)
- [C++ 中]:6.类和对象下(static成员 + explicit +友元函数 + 内部类 + 编译器优化)
- 【Linux系统学习】系统编程开发工具编译器gcc/g++使用
- 详解三大编译器: gcc、llvm 和 clang (icc/icpc/ifort)
- 【C/C++】使用 g++ 编译器编译 C++ 程序的完全指南
- Linux开发工具之文本编译器vim
猜你感兴趣
版权申明
本文"详解三大编译器: gcc、llvm 和 clang (icc/icpc/ifort)":http://eshow365.cn/6-29982-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!
- 上一篇: 8. 一文快速学懂常用工具——Linux命令(上)
- 下一篇: Redis常见的全局命令