编译器架构
传统编译器架构(Three-Phase)
Three-Phase.png上图是最简单的三段式编译器架构。
-
Frontend:前端
词法分析、语法分析、语义分析、生成中间代码 -
Optimizer:优化器
中间代码优化 -
Backend:后端
生成机器码首先,我们看到source是我们的源代码,进入编译器的前端Frontend;在前端完成之后,就进入优化器这一模块;优化完成之后进入后端模块;在这全部完成之后,根据你的架构是x86,armv7等产生机器码。
这样就会有一个问题,有M种语言,N种架构,那就会有M*N种编译方式需要处理,显然架构不合理。
Apple支持的语言
C
C++
Objective-C
Swift
...
iPhone CPU架构
指令集对应的机型:
2019 A13芯片arm64e : iphone11、iphone11 Pro
2018 A12芯片arm64e : iphone XS、iphone XS Max、iphoneXR
2017 A11芯片arm64: iPhone 8、iPhone 8 Plus、and iPhone X
2016 A10芯片arm64:iPhone 7、7 Plus、iPad (2018)
2015 A9芯片arm64: iPhone 6S、6S Plus
2014 A8芯片arm64: iPhone 6、iPhone 6 Plus
2013 A7芯片arm64: iPhone 5S
armv7s:iPhone5、iPhone5C、iPad4(iPad with Retina Display)
armv7:iPhone4、iPhone4S、iPad、iPad2、iPad3(The New iPad)、iPad mini、iPod Touch 3G、iPod Touch4
模拟器32位处理器测试需要i386架构
模拟器64位处理器测试需要x86_64架构
真机32位处理器需要armv7,或者armv7s架构
真机64位处理器需要arm64架构
LLVM:
-
The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
-
LLVM项目是模块化、可重用的编译器以及工具链技术的集合
-
美国计算机协会(ACM)将其2012年软件系统奖项颁给了LLVM,之前曾经得此奖项的软件和技术包括Mosaic、the World Wide Web、Smalltalk、UNIX、Eclipse等等
-
创始人Chris Lattner ,亦是swift之父
-
有些文章把LLVM当做Low Level Virtual Machine(低级虚拟机)的缩写简称,官方描述如下
The name "LLVM" itself is not an acronym; it is the full name of the project
"LLVM"这个名称本身不是首字母缩略词;它是项目的全名
LLVM百度百科
LLVM架构:
LLVM架构.png- 不同的前后端使用统一的中间代码 LLVM Intermediate Representation(LLVM IR)
- 如果需要支持一种新的编程语言,那么只需要实现一个新的前端就可以
- 如果需要支持一种新的硬件设备,那么只需要实现一个新的后端就可以
- 优化阶段是一个通用的阶段,它针对的是统一的LLVM IR,不论是支持新的编程语言,还是支持新的硬件设备,都不需要对优化阶段做修改
- 相比之下,GCC的前端和后端没分的太开,前端后端耦合在了一起,所以GCC为了支持一门新语言,或者支持一个新的平台,就会变得特别困难
- LLVM现在被作为实现各种静态和运行时编译语言的通用基础结构(GCC家族、Java、.NET、Python、Ruby、Scheme、Haskell、D等)
- 广义的LLVM是整个LLVM架构
-
狭义的LLVM是指LLVM后端
LLVM架构2.png
由上图可知,需要支持Swift这个新的语言,只需要实现一个新的前端swiftc就可以实现
GCC:
GCC架构.jpegGCC百度百科.png
GCC百度百科
GCC的消亡与Clang的崛起
Apple一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错,但Apple对编译工具会提出更高的要求。
一方面,是Apple对Objective-C语言新增很多特性,但GCC开发者并不买Apple的账--不给实现,因此索性后来两者分成两条分支分别开发,这也造成Apple的编译器版本远落后于GCC的官方版本。另一方面,GCC的代码耦合度太高,不好独立,而且越是后期的版本,代码质量越差,但Apple想做的很多功能(比如更好的IDE支持)需要模块化的方式来调用GCC,但GCC一直不给做。所以,这种不和让Apple一直在寻找一个高效的、模块化的、协议更放松的开源替代品。GCC系统庞大而笨重,而Apple大量使用的Objective-C在GCC中优先级很低。此外GCC作为一个纯粹的编译系统,与IDE配合得很差。加之许可证方面的要求,Apple无法使用LLVM 继续改进GCC的代码质量。于是,Apple决定从零开始写 C、C++、Objective-C语言的前端 Clang,完全替代掉GCC。
Clang
-
Clang是LLVM项目的一个子项目
-
基于LLVM架构的C/C++/Objective-C编译器前端
相比GCC,Clang具有如下优点:
- 编译速度快:在某些平台上,Clang的编译速度显著的快过GCC(Debug模式下编译OC速度比GCC)快3倍
- 占用内存小:Clang生成的AST所占用的内存是GCC的五分之一左右
- 模块化设计:Clang采用基于库的模块化设计,易于IDE集成及其他用途的重用
- 诊断信息可读性强:在编译过程中,Clang创建并保留了大量详细的元数据(metadata),有利于调试
- 设计清晰简单,容易理解,易于扩展增强
LLVM架构3.png
clang.png
clang百度百科
OC源代码的前端编译过程
源代码:
#include <stdio.h>
#define AGE 40
int main(int argc, const char * argv[]) {
int a = 10;
int b = 20;
int c = a + b + AGE;
return 0;
}
- 命令行查看编译的过程:$ clang -ccc-print-phases main.m(打印编译阶段)
0: input, "main.m", objective-c //找到源代码:main.m 文件
1: preprocessor, {0}, objective-c-cpp-output //预处理器,include,import 宏定义换掉
2: compiler, {1}, ir // 编译成ir 中间代码
3: backend, {2}, assembler // 后端 交给后端
4: assembler, {3}, object // 目标代码
5: linker, {4}, image // 链接 其他一些静态库动态库
6: bind-arch, "x86_64", {5}, image // 适合某个架构的代码
预处理(preprocessor)
-
查看预处理结果:$ clang -E main.m
预处理.png
词法分析
- 词法分析,生成Token:$clang -fmodules -E -Xclang -dump-tokens main.m
annot_module_include '#include <stdio.h>
#define AGE 40
int main(int argc, const char * argv[]) {
int a = 10;
int b = 20;
int c = a + b ' Loc=<main.m:9:1>
int 'int' [StartOfLine] Loc=<main.m:13:1>
identifier 'main' [LeadingSpace] Loc=<main.m:13:5>
l_paren '(' Loc=<main.m:13:9>
int 'int' Loc=<main.m:13:10>
identifier 'argc' [LeadingSpace] Loc=<main.m:13:14>
comma ',' Loc=<main.m:13:18>
const 'const' [LeadingSpace] Loc=<main.m:13:20>
char 'char' [LeadingSpace] Loc=<main.m:13:26>
star '*' [LeadingSpace] Loc=<main.m:13:31>
identifier 'argv' [LeadingSpace] Loc=<main.m:13:33>
l_square '[' Loc=<main.m:13:37>
r_square ']' Loc=<main.m:13:38>
r_paren ')' Loc=<main.m:13:39>
l_brace '{' [LeadingSpace] Loc=<main.m:13:41>
int 'int' [StartOfLine] [LeadingSpace] Loc=<main.m:14:5>
identifier 'a' [LeadingSpace] Loc=<main.m:14:9>
equal '=' [LeadingSpace] Loc=<main.m:14:11>
numeric_constant '10' [LeadingSpace] Loc=<main.m:14:13>
semi ';' Loc=<main.m:14:15>
int 'int' [StartOfLine] [LeadingSpace] Loc=<main.m:15:5>
identifier 'b' [LeadingSpace] Loc=<main.m:15:9>
equal '=' [LeadingSpace] Loc=<main.m:15:11>
numeric_constant '20' [LeadingSpace] Loc=<main.m:15:13>
semi ';' Loc=<main.m:15:15>
int 'int' [StartOfLine] [LeadingSpace] Loc=<main.m:16:5>
identifier 'c' [LeadingSpace] Loc=<main.m:16:9>
equal '=' [LeadingSpace] Loc=<main.m:16:11>
identifier 'a' [LeadingSpace] Loc=<main.m:16:13>
plus '+' [LeadingSpace] Loc=<main.m:16:15>
identifier 'b' [LeadingSpace] Loc=<main.m:16:17>
plus '+' [LeadingSpace] Loc=<main.m:16:19>
numeric_constant '40' [LeadingSpace] Loc=<main.m:16:21 <Spelling=main.m:11:13>>
semi ';' Loc=<main.m:16:24>
return 'return' [StartOfLine] [LeadingSpace] Loc=<main.m:18:5>
numeric_constant '0' [LeadingSpace] Loc=<main.m:18:12>
semi ';' Loc=<main.m:18:13>
r_brace '}' [StartOfLine] Loc=<main.m:19:1>
eof '' Loc=<main.m:19:2>
语法分析
- 生成语法树(AST,Abstract Syntax Tree):clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
新增方法:
void test(int a, int b) {
int c = a + b -3;
}
语法分析.png
语法分析2.png
swift生成语法树:swiftc -dump-ast main.swift
swfit生成SIL代码:swiftc -emit-sil main.swift
生成中间代码(LLVM IR)
- LLVM有3种表示形式(但本质是等价的)
1,text:便于阅读的文本格式,类似于汇编语言,扩展名为.ll,clang -S -emit-llvm main.m
2,memory:内存格式
3,bitcode:二进制格式,扩展名为.bc,clang -c -emit-llvm main.m - swift生成IR代码:swiftc -emit-ir main.swift -o main.ll
官方语法参考:
https://llvm.org/docs/LangRef.html
文章参考:
https://www.jianshu.com/p/9dbb5930f0ea
https://blog.csdn.net/xhhjin/article/details/81164076
https://ke.qq.com/course/322016
网友评论