Chris Lattner 就是那个跳槽去特斯拉的Swift之父,他很久以前写了一个用于 开发一个编译器的工具套件叫 Low Level Virtual Machine 也就是常常看见的 LLVM,Clang 就是 LLVM 着一套工具中的一个。LLVM可以用于常规编译器,JIT编译器,汇编器,调试器,静态分析工具等一系列跟编程语言相关的工作。
Clang 的编译速度惊人,比 GCC 快3倍,LLVM 也提供一种代码编写良好的中间表示 IR,可以作为多种语言的后端,提供语言无关的优化同时还能够方便的针对多种 CPU 的代码生成。
编译OC流程
下面这部分简单的代码将会如何被编译成可执行的呢?
#import <Foundation/Foundation.h>
#define DEFINEEight 8
int main(){
@autoreleasepool {
int eight = DEFINEEight;
int six = 6;
NSString* site = [[NSString alloc] initWithUTF8String:"starming"];
int rank = eight + six;
NSLog(@"%@ rank %d", site, rank);
}
return 0;
}
1.预处理
处理以#
开头的的预编译指令 #include
#define
#if
#else
等
clang -E main.m
# 1 "/System/Library/Frameworks/Foundation.framework/Headers/FoundationLegacySwiftCompatibility.h" 1 3
# 185 "/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h" 2 3
# 2 "main.m" 2
int main(){
@autoreleasepool {
int eight = 8;
int six = 6;
NSString* site = [[NSString alloc] initWithUTF8String:"starming"];
int rank = eight + six;
NSLog(@"%@ rank %d", site, rank);
}
return 0;
}
2.词法分析
代码通过 Clang Static Analyzer 被识别为 关键词 标识符 字面量( int,string) 和 特殊符号(+,=),他们可以被叫为记号 Token,他们将会在生成语法树被使用到。
clang -fmodules -E -Xclang -dump-tokens main.m
annot_module_include '#import <Fo' Loc=<main.m:2:1>
int 'int' [StartOfLine] Loc=<main.m:5:1>
identifier 'main' [LeadingSpace] Loc=<main.m:5:5>
l_paren '(' Loc=<main.m:5:9>
r_paren ')' Loc=<main.m:5:10>
l_brace '{' [LeadingSpace] Loc=<main.m:5:12>
at '@' [StartOfLine] [LeadingSpace] Loc=<main.m:6:5>
identifier 'autoreleasepool' Loc=<main.m:6:6>
l_brace '{' [LeadingSpace] Loc=<main.m:6:22>
identifier 'NSString' [StartOfLine] [LeadingSpace] Loc=<main.m:7:9>
star '*' [LeadingSpace] Loc=<main.m:7:18>
identifier 'a' Loc=<main.m:7:19>
equal '=' [LeadingSpace] Loc=<main.m:7:21>
at '@' [LeadingSpace] Loc=<main.m:7:23>
string_literal '"aaa"' Loc=<main.m:7:24>
semi ';' Loc=<main.m:7:29>
identifier 'NSLog' [StartOfLine] [LeadingSpace] Loc=<main.m:8:9>
l_paren '(' Loc=<main.m:8:14>
at '@' Loc=<main.m:8:15>
string_literal '"hi %@"' Loc=<main.m:8:16>
comma ',' Loc=<main.m:8:23>
identifier 'a' Loc=<main.m:8:24>
r_paren ')' Loc=<main.m:8:25>
semi ';' Loc=<main.m:8:26>
r_brace '}' [StartOfLine] [LeadingSpace] Loc=<main.m:9:5>
return 'return' [StartOfLine] [LeadingSpace] Loc=<main.m:10:5>
numeric_constant '0' [LeadingSpace] Loc=<main.m:10:12>
semi ';' Loc=<main.m:10:13>
r_brace '}' [StartOfLine] Loc=<main.m:11:1>
eof '' Loc=<main.m:11:2>
每一行一个token 从左到右看,后面的 StartOfLine LeadingSpace Loc 都是位置信息
3.语法分析
生成以 表达式 为节点的 语法树,最小的表达式可以是 字面亮 也就是上面的Token ,按照特定的语法规则,将它们组织起来。生成语法树 Abstract Syntax Tree (AST)
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
TranslationUnitDecl 0x7fa80f018ad0 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7fa80f018fc8 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x7fa80f018d20 '__int128'
|-TypedefDecl 0x7fa80f019028 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x7fa80f018d40 'unsigned __int128'
|-TypedefDecl 0x7fa80f0190b8 <<invalid sloc>> <invalid sloc> implicit SEL 'SEL *'
| `-PointerType 0x7fa80f019080 'SEL *'
| `-BuiltinType 0x7fa80f018f30 'SEL'
|-TypedefDecl 0x7fa80f019198 <<invalid sloc>> <invalid sloc> implicit id 'id'
| `-ObjCObjectPointerType 0x7fa80f019140 'id' imported
| `-ObjCObjectType 0x7fa80f019110 'id' imported
|-TypedefDecl 0x7fa80f019278 <<invalid sloc>> <invalid sloc> implicit Class 'Class'
| `-ObjCObjectPointerType 0x7fa80f019220 'Class'
| `-ObjCObjectType 0x7fa80f0191f0 'Class'
|-ObjCInterfaceDecl 0x7fa80f0192c8 <<invalid sloc>> <invalid sloc> implicit Protocol
|-TypedefDecl 0x7fa80f019618 <<invalid sloc>> <invalid sloc> implicit __NSConstantString 'struct __NSConstantString_tag'
| `-RecordType 0x7fa80f019430 'struct __NSConstantString_tag'
| `-Record 0x7fa80f019390 '__NSConstantString_tag'
|-TypedefDecl 0x7fa80f0196a8 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x7fa80f019670 'char *'
| `-BuiltinType 0x7fa80f018b60 'char'
|-TypedefDecl 0x7fa80f047978 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag [1]'
| `-ConstantArrayType 0x7fa80f047920 'struct __va_list_tag [1]' 1
| `-RecordType 0x7fa80f0197a0 'struct __va_list_tag'
| `-Record 0x7fa80f0196f8 '__va_list_tag'
|-ImportDecl 0x7fa80f0486b0 <main.m:2:1> col:1 implicit Foundation
|-FunctionDecl 0x7fa80f048738 <line:5:1, line:11:1> line:5:5 main 'int ()'
| `-CompoundStmt 0x7fa80f393998 <col:12, line:11:1>
| |-ObjCAutoreleasePoolStmt 0x7fa80f393950 <line:6:5, line:9:5>
| | `-CompoundStmt 0x7fa80f393928 <line:6:22, line:9:5>
| | |-DeclStmt 0x7fa80f3a3b38 <line:7:9, col:29>
| | | `-VarDecl 0x7fa80f3a3580 <col:9, col:24> col:19 used a 'NSString *' cinit
| | | `-ObjCStringLiteral 0x7fa80f3a3648 <col:23, col:24> 'NSString *'
| | | `-StringLiteral 0x7fa80f3a3618 <col:24> 'char [4]' lvalue "aaa"
| | `-CallExpr 0x7fa80f3938c0 <line:8:9, col:25> 'void'
| | |-ImplicitCastExpr 0x7fa80f3938a8 <col:9> 'void (*)(id, ...)' <FunctionToPointerDecay>
| | | `-DeclRefExpr 0x7fa80f3a3b50 <col:9> 'void (id, ...)' Function 0x7fa80f3a3670 'NSLog' 'void (id, ...)'
| | |-ImplicitCastExpr 0x7fa80f3938f8 <col:15, col:16> 'id':'id' <BitCast>
| | | `-ObjCStringLiteral 0x7fa80f393800 <col:15, col:16> 'NSString *'
| | | `-StringLiteral 0x7fa80f3a3bb8 <col:16> 'char [6]' lvalue "hi %@"
| | `-ImplicitCastExpr 0x7fa80f393910 <col:24> 'NSString *' <LValueToRValue>
| | `-DeclRefExpr 0x7fa80f393820 <col:24> 'NSString *' lvalue Var 0x7fa80f3a3580 'a' 'NSString *'
| `-ReturnStmt 0x7fa80f393980 <line:10:5, col:12>
| `-IntegerLiteral 0x7fa80f393960 <col:12> 'int' 0
`-<undeserialized declarations>
TranslationUnitDecl 是根节点,表示一个源文件。Decl 表示一个声明,Expr 表示表达式,Literal 表示字面量是特殊的 Expr,Stmt 表示语句。
4.中间语言生成
将语法树翻译成 LLVM IR 中间代码,做为 LLVM Backend 输入的桥接语言。这样做的好处在前言里也提到了,方便 LLVM Backend 给多语言做相同的优化,做到语言无关。
- 各种类,方法,成员变量等的结构体的生成,并将其放到对应的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 方法自动释放类的成员变量。
- 深入剖析 iOS 编译 Clang LLVM
- 基于clang插件的一种iOS包大小瘦身方案