本文为L_Ares个人写作,以任何形式转载请表明原文出处。
先不说LLVM
是什么,概念性的资料其实去某度百科(如果可以的话,建议还是去看维基百科
或者LLVM官网)都可以找到这四个英文字母组合起来是意思,先说一下为什么要探索这个东西。
对于从事C++
和iOS
开发的童鞋们一定听说过这个东西,哪怕你不了解,但是听总归是听过的,抛开C++
不说,为什么从事iOS
开发的童鞋要知道这东西?
什么是编译器,在扩展6特意摘出来写了一下,如果还不知道计算机语言的简要分类和编译器的概念的童鞋,可以看一下。
一、简述什么是LLVM
前言
概念
这里的概念全部引自LLVM官网。
所谓工具链技术
,举个栗子 :
概述
LLVM
现在是一个项目体系是一套框架系统,在之前,它曾是Low Level Virtual Machine
的缩写。
LLVM
项目包括了非常多的子项目,包括iOS
开发者常见的Clang
,LLDB
,libc++
和libc++ ABI
,这都是LLVM
的主要子项目。
LLVM
虽然包含了这么多编译器作为子项目,但是它本身并不是编译器,也不是编译器后端。
对于LLVM核心(LLVM Core)
来说,它是一个编译器基础设施框架。
它提供的是编写编译器所需的一系列的库,例如程序分析、代码优化、机器代码生成等。并且提供了调用这些库的相关工具。也为这些库提供了方便简单的、具备类型的、与平台无关的统一中间代码语言——LLVM IR
。
LLVM
以C++
编写而成,用于优化以任意程序语言编写的 :
编译时间 (
compile-time
)链接时间 (
link-time
)运行时间 (
run-time
)空闲时间 (
idle-time
)
LLVM
对开发者保持开放,并且兼容现有的脚本。
二、编译器的设计
在探索LLVM
的设计之前,先看一下传统的编译器设计,来比较两者的区别,以及探索LLVM
的优势。
1. 传统编译器的设计
如图2.1.0所示
传统的编译器整体流程是 :
1.1 编译器前端(Frontend)
1.2 优化器(Optimizer)
1.3 编译器后端(Backend)/代码生成器(CodeGenerator)
2. iOS的编译器架构
所谓iOS
的编译器架构其实就是LLVM
编译器架构中的一部分。包括Objective-C
、C
、C++
在内,它们使用的编译器前端
都是Clang
。而Swift
的编译器前端
就是Swift
。它们的编译器后端
则全部都是LLVM Code Generator
。
而Clang
也只是整个LLVM
架构中的一个子项目,属于编译器前端
,这个在上面说过。
来看iOS
的编译器架构图 :
很明显,iOS
的编译器是通过Clang
或者Swift
来完成词法分析、语法分析、语义分析的步骤,来完成对源代码的错误排查,然后生成抽象语法树(AST)
。
这里利用的就是LLVM
的前端,和传统编译器的不同点是,Clang
不止做完了上述的排查,还会生成一个非常重要的东西——IR
。
什么是IR
?
那么用语言来描述iOS
的编译器架构设计流程就是 :
3. LLVM的设计
LLVM
的设计重点和优势 : 面对多种源语言(编译器前端来做),或者多种硬件架构(编译器后端来做)的情况时,对比传统的编译器例如GCC
,优势就是LLVM
的IR
设计。
由于GCC
是以一个整体应用程序设计的,也就是说,如果你的前端源语言或者后端硬件架构,任一一个发生了变化的话,你需要重新设计一整套前端--优化器--后端
的编译器。
LLVM
的设计图 :
优势 :
如果前端出现了新的源语言类型,
LLVM
只需要针对新语言适配一个IR
转换器即可,优化器和后端都不需要进行大的改变,甚至不用改变。如果后端出现了新的硬件架构,
LLVM
只需要针对新的硬件架构适配一个IR
转换器即可,优化器和前端则不需要进行大的改变,甚至不用改变。
三、关于Clang
1. 什么是Clang
内容引自LLVM官网,个人翻译,如有不准确的地方,还请不吝赐教。
2. Clang的概述
3. 一些LLVM或Clang中的名词解释
3.1 词法分析
3.2 语法分析
3.3 语义分析
3.4 抽象语法树
4. iOS中可能遇到的Clang常用指令
这里只说一些iOS中可能常用的Clang
指令,如果想要全部的Clang
指令集,可以在terminal
终端中输入clang --help
查看。
如果认为上面的命令查看不方便的,这里还有github版本,内容就是copy的clang --help
。
或者可以直接在LLVM
官网的Clang Document查询。
Clang命令 | 释义 |
---|---|
-ccc-print-phases | 打印源码的编译阶段,得到的打印结果就是整个源码到机器代码的整体流程步骤。 |
-rewrite-objc | 将OC源码编译成C++源码 |
-E | 查看预处理阶段详细步骤(在terminal 中查看,也可以生成一个新文件 : clang -E main.m >> new_main.m) 。>> 就是文件重定向。 |
-c | 必须在-E 之后才可以使用,例如clang -E main.m -c 。只进行预处理,编译,汇编步骤,不进行链接步骤。执行完成后生成的是.o 链接文件。 |
-S | 只进行预处理和编译步骤,不进行汇编,链接等后续步骤。执行完成后,生成的是.s 汇编代码文件。 |
-o <file> | 完成预编译-->编译-->汇编-->链接 后,生成可执行文件到<file> 文件。 |
-g | 在生成的可执行文件中,包含标准的调试信息。 |
-i <路径>(应该是大写i 最标准) |
在头文件中的搜索路径中添加<路径> 。 |
-fmodules | 启用模块化语言特性。 |
-fsyntax-only | 编译器并不生成代码,后续的操作只是语法级别的修改。 |
-Xclang <arg> | 向clang 编译器传递参数<arg> 。 |
-dump-tokens | 运行预处理器,将源码内部拆分成各种单词(Token)。 |
-ast-dump | 构建抽象语法树AST,然后对其进行拆解和调试。 |
-fobjc-arc | 生成Objective-C指针的retain 和release 的调用。 |
-emit-llvm | 对汇编文件和目标文件生成LLVM IR 代码。 |