常用C/C++编译器
文章目录
- 1、GCC
- 1.1 什么是gcc
- 1.2 gcc特点
- 1.3 gcc 编译程序的过程
- 1.4 gcc常用编译选项
- 2、LLVM与Clang
- 2.1 传统编译器架构
- 2.2 什么是LLVM
- 2.3 LLVM架构
- 2.4 什么是Clang
- 2.5 Clang与LLVM的关系
1、GCC
1.1 什么是gcc
gcc 的全称是 GNU Compiler Collection,它是一个能够编译多种语言的编译器。
最开始gcc是作为C语言的编译器(GNU C Compiler),现在除了c语言,还支持C++、java、Pascal等语言。gcc支持多种硬件平台。
1.2 gcc特点
- gcc是一个可移植的编译器,支持多种硬件平台。例如ARM、X86等等。
- gcc不仅是个本地编译器,它还能跨平台交叉编译。所谓的本地编译器,是指编译出来的程序只能够在本地环境进行运行。而gcc编译出来的程序能够在其他平台进行运行。例如嵌入式程序可在x86上编译,然后在arm上运行。
- gcc有多种语言前端,用于解析不同的语言。
- gcc是按模块化设计的,可以加入新语言和新CPU架构的支持。
- gcc是自由软件。任何人都可以使用或更改这个软件。
1.3 gcc 编译程序的过程
gcc编译程序主要经过四个过程:
- 预处理(Pre-Processing)
- 编译 (Compiling)
- 汇编 (Assembling)
- 链接 (Linking)

预处理 实际上是将头文件、宏进行展开。
编译阶段,gcc调用不同语言的编译器,例如c语言调用编译器ccl。gcc实际上是个工具链,在编译程序的过程中调用不同的工具。
汇编阶段,gcc调用汇编器进行汇编。
链接过程会将程序所需要的目标文件进行链接成可执行文件。
汇编器生成的是可重定位的目标文件,学过操作系统,我们知道,在源程序中地址是从0开始的,这是一个相对地址,而程序真正在内存中运行时的地址肯定不是从0开始的,而且在编写源代码的时候也不能知道程序的绝对地址,所以重定位能够将源代码的代码、变量等定位为内存具体地址。
上图表示了这个过程,注意过程中文件的后缀变化,编译选项和这些后缀有关。
这是GCC编译的四个步骤。
1.4 gcc常用编译选项
语法:
gcc [-c|-S|-E] [-std=standard][-g] [-pg] [-Olevel][-Wwarn...] [-Wpedantic][-Idir...] [-Ldir...][-Dmacro[=defn]...] [-Umacro][-foption...] [-mmachine-option...][-o outfile] [@file] infile...
命令格式:
gcc [选项][文件名]
常用编译选项
| 选项名 | 作用 |
|---|---|
| -E | 预处理后即停止,不进行编译,不生成文件,预处理后的代码送往标准输出。仅执行编译预处理 |
| -S | 编译后即停止,不进行汇编,生成.s的汇编代码。即将C代码转换为汇编代码,仅执行编译操作 |
| -c | 汇编后即停止,不进行链接,生成.o文件。即仅执行汇编操作,不进行链接操作 |
| -o | 产生目标(.i、.s、.o、可执行文件等),即指定生成的输出文件 |
| -Wall | 生成所有警告信息。 |
| -Idir | 将dir目录加入搜索头文件的目录路径 |
| -Ldir | 将dir目录加入搜索库的目录路径 |
| -llib | 连接lib库 |
| -g | 在目标文件中嵌入调试信息,以便gdb之类的调试程序调试 |
| -v | 查看整个程序编译的所有子过程执行的命令行 |
| -O0/-O1/-O2/-O3/ | 指定编译器优化级别,-O0 表示没有优化, -O1 为默认值,-O3 优化级别最高 |
假设有个源程序 hello.c,gcc 编译的四个阶段使用编译选项示例:
#对hello.c文件进行预处理,生成了hello.i 文件
gcc -E hello.c -o hello.i #对预处理文件进行编译,生成了汇编文件
gcc -S hello.i -o hello.s #对汇编文件进行编译,生成了目标文件
gcc -c hello.s -o hello.o #对目标文件进行链接,生成可执行文件
gcc hello.o -o hello #一步到位,直接编译链接成可执行目标文件
gcc hello.c -o hello #编译生成可重定位目标文件
gcc -c hello.c
#或
gcc -c hello.c -o hello.o
2、LLVM与Clang
2.1 传统编译器架构

传统的编译器架构(比如GCC)主要分为前端、优化器、后端(理论上优化器也是后端的一部分)。三者的作用分别如下:
- 前端:词法分析、语法分析、语义分析、生成中间代码。
- 优化器:中间代码作为输入,优化中间代码(与架构无关的代码优化),使代码运行更快,体积更小。
- 后端:生成机器码(根据不同架构x86、x64等生成不同架构的机器码)。
2.2 什么是LLVM
LLVM项目是一个模块化的、可重用的编译器和工具链集合。尽管它的名字-LLVM与传统虚拟机(low level virtual machine)名字相似,但“LLVM”这个名字本身不是一个缩略词,它就是这个项目的全称。所以不要再把LLVM叫做low level virtual machine。
在理解LLVM时,我们可以认为它包括了一个狭义的LLVM和一个广义的LLVM。
- 广义的LLVM其实就是指整个LLVM编译器架构,包括了前端、后端、优化器、众多的库函数以及很多的模块。
- 狭义的LLVM其实就是聚焦于编译器后端功能(代码生成、代码优化、JIT等)的一系列模块和库。
2.3 LLVM架构

由上图可知,LLVM架构下,不同的前端和后端使用统一的中间代码LLVM InterMediate Representation(LLVM IR)。
如果需要支持一门新的编程语言,只需要实现一个新的前端。如果需要支持一款新的硬件设备,只需要实现一个新的后端。优化阶段是一个通用的阶段,它针对的是统一的LLVM IR,不论是支持新的编程语言,还是支持新的硬件设备,都不需要对优化阶段做修改。
相比之下,GCC的前端后端没有实现分离,前端后端耦合在了一起,所以GCC为了支持一门新的编程语言,或者为了支持一个新的硬件设备,就变得特别困难。
2.4 什么是Clang

Clang是LLVM的项目的子项目,它是LLVM架构下的C/C++/Objective-C的编译器前端。Clang 对源程序进行预处理、词法分析、语法分析,并将分析结果转换为抽象语法树(Abstract Syntax Tree),最后使用 LLVM 作为编译器后端代码的生成器。
Clang 的开发目标是提供一个可以替代 GCC 的前端编译器。相比较于GCC,Clang具有如下优点:
- 编译速度快:在某些平台上,Clang的编译速度明显快过GCC。Debug模式下,Clang编译OC的速度比GCC快3倍。
- 占用内存少:Clang生成的抽象语法树(AST),所占用的内存是GCC的五分之一左右。
- 模块化设计:Clang作为LLVM项目下的一个子项目,采用基于库的模块化设计,易于IDE的集成及其他用途的重用。
- 诊断信息可读性强:在编译过程中,Clang 创建并保留了大量详细的元数据 (metadata),有利于调试和错误报告。
- 设计清晰简单,容易理解,易于扩展增强。
2.5 Clang与LLVM的关系

Clang作为LLVM的前端,负责词法分析、语法分析、语义分析,然后生成中间代码。接下来把中间代码转交给优化器,优化器会对中间代码进行与架构无关的代码优化,优化后的代码体积更小、运行速度更快。最终LLVM后端会把优化后的中间代码转化为机器码。流程如下:

虽然Clang是LLVM的前端,但是LLVM的前端不只是Clang。Clang只是为C、C++、Objective-C设计的LLVM的编译器前端。除此之外,还有为Swift设计的编译器前端Swift等。
原文:源代码编译介绍
相关参考:
- LLVM简介
- LLVM(clang)介绍
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
