-
Clang是LLVM项目中的一个子项目。它是基于LLVM架构的轻量级编译器,诞生之初是为了替代GCC,提供更快的编译速度。它负责C、C++、Objective-C语言的编译器,它属于整个LLVM框架中的编译器前端。 -
传统编译器的设计
3. 编译器就是将“一种语言(通常为高级语言)”翻译为“另一种语言(通常为低级语言)”的程序。
一个现代编译器的主要工作流程:源代码 (source code) → 预处理器(preprocessor) → 编译器 (compiler) → 目标代码 (object code)→ 链接器(Linker) → 可执行程序
编译的概念(词法->语法->语义->IR->优化->CodeGen)
- 编译器设计
- 编译器前端(Frontend)
任务是解析源代码。
词法分析、语法分析、语义分析、检查源代码是否存在错误、构建抽象语法树AST(Abstract Syntax Tree)。 如果是LLVM前端(Clang/Swift)还会生成中间代码(intermediate representation)。 - 优化器(Optimizer)
各种优化。改善代码运行时间,例如消除冗余计算等。(类似Xcode里设置编译优化等级) - 后端(Backend)/代码生成器(CodeGenerator)
将代码映射到目标指令集,生成机器语言,并进行机器相关代码优化。
(64位arm的指令集就是arm64,64位x86的指令集就是x86_64)
下面是演示
1. 宏的替换,头文件的导入
2. 词法解析:这里会把代码切成一个个 Token,比如大小括号,等于号还有字符串等。:简单示意
int main(){
@autoreleasepool {
int e' Loc=<main.m:8:1>
int 'int' [StartOfLine] Loc=<main.m:12:1>
identifier 'main' [LeadingSpace] Loc=<main.m:12:5>
l_paren '(' Loc=<main.m:12:9>
r_paren ')' Loc=<main.m:12:10>
l_brace '{' Loc=<main.m:12:11>
at '@' [StartOfLine] [LeadingSpace] Loc=<main.m:13:5>
3.语法分析、抽象语法树
**FunctionDecl** 0x7fb1a70e7c70 <line:12:1, line:21:1> line:12:5 **main** 'int ()'
`-**CompoundStmt** 0x7fb1a69b95d8 <col:11, line:21:1>
|-**ObjCAutoreleasePoolStmt** 0x7fb1a69b9590 <line:13:5, line:19:5>
| `-**CompoundStmt** 0x7fb1a69b9558 <line:13:22, line:19:5>
| |-**DeclStmt** 0x7fb1a70e7e10 <line:14:9, col:32>
| | `-**VarDecl** 0x7fb1a70e7d88 <col:9, line:10:21> line:14:13 used **eight** 'int' cinit
| | `-**IntegerLiteral** 0x7fb1a70e7df0 <line:10:21> 'int' **8**
| |-**DeclStmt** 0x7fb1a69ba298 <line:15:9, col:20>
| | `-**VarDecl** 0x7fb1a70e7e40 <col:9, col:19> col:13 used **six** 'int' cinit
4. 生成IR中间代码(到此 编译器前端 完成)
; Function Attrs: noinline optnone ssp uwtable
define i32 @main() #1 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
%4 = alloca %0*, align 8
%5 = alloca i32, align 4
store i32 0, i32* %1, align 4
%6 = call i8* @llvm.objc.autoreleasePoolPush() #2
5.LLVM 会去做些优化工作+bitcode(优化完成)
6.生成汇编 生成目标代码,生成可执行文件(生成可执行文件完成)
5.app完整编译流程
- 编译信息写入辅助文件,创建文件架构 .app 文件
- 处理文件打包信息
- 执行 CocoaPod 编译前脚本,checkPods Manifest.lock
- 编译.m文件,使用 CompileC 和 clang 命令(对应上面流程)
- 链接需要的 Framework
- 编译 xib
- 拷贝 xib ,资源文件
- 编译 ImageAssets
- 处理 info.plist
- 执行 CocoaPod 脚本
- 拷贝标准库
- 创建 .app 文件和签名
targetID,包含它对应的编译选项
- clang static analyzer 主要是进行语法分析,语义分析和生成中间代码,当然这个过程会对代码进行检查,出错的和需要警告的会标注出来。
- Token
Token 可以分为以下几类
- 关键字:语法中的关键字,if else while for 等。
- 标识符:变量名
- 字面量:值,数字,字符串
- 特殊符号:加减乘除等符号
生成出来的IR代码都是一样的语法形式
不管编译的语言时 Objective-C 还是 Swift 也不管对应机器是什么,亦或是即时编译,LLVM 里唯一不变的是中间语言 LLVM IR。
- CodeGen 生成 IR 代码 这个过程中还会跟 runtime 桥接。(抽象语法树之后,生成IR)
- 各种类,方法,成员变量等的结构体的生成,并将其放到对应的Mach-O的section中。
- Non-Fragile ABI 合成 OBJC_IVAR_$_ 偏移值常量。
- ObjCMessageExpr 翻译成相应版本的 objc_msgSend,super 翻译成 objc_msgSendSuper。
- strong,weak,copy,atomic 合成 @property 自动实现 setter 和 getter。
- @synthesize 的处理。
- 生成 block_layout 数据结构
- __block 和 __weak
- _block_invoke
- ARC 处理,插入 objc_storeStrong 和 objc_storeWeak 等 ARC 代码。ObjCAutoreleasePoolStmt 转 objc_autorealeasePoolPush / Pop。自动添加 [super dealloc]。给每个 ivar 的类合成 .cxx_destructor 方法自动释放类的成员变量。 11.IR:一个文件 对应一个Module LLVM LLVM2 编译流程 12.什么是抽象语法树 抽象语法树