编译器
大家都知道,我们的计算机CPU只能读懂机器码(machine code,也就是由一堆0和1组成的编码),但我们现在编写的代码并不是机器码,而是高级编程语言(Objective-C、Swift、Java、…),最终也可以被计算机所执行,这就需要编译了,在编译的过程中,编译器的作用便是把我们的高级编程语言通过一系列的操作转化成可被计算机执行的机器语言。
编译器设计
经典的三段式设计(three phase design):前端(Frontend)–优化器(Optimizer)–后端(Backend)
- 其中前端负责分析源代码,可以检查语法级错误,并构建针对该语言的抽象语法树(AST)
- 抽象语法树可以进一步转换为优化,最终转为新的表示方式, 然后再交给让优化器和后端处理
- 最终由后端生成可执行的机器码
三段式设计优势
- 首先解决了一个很大的问题:假如有N种语言(C、OC、C++、Swift…)的前端,同时也有M个架构(模拟器、arm64、x86…)的Target,是否就需要 N × M 个编译器?
- 三段式架构的价值就体现出来了,通过共享优化器的中转,很好的解决了这个问题。
- 假如你需要增加一种语言,只需要增加一种前端;假如你需要增加一种处理器架构,也只需要增加一种后端,而其他的地方都不需要改动。这复用思想很牛逼吧。
编译步骤
- 源代码(source code)
- 预处理器(preprocessor)
- 编译器(compiler)
- 汇编程序(assembler)
- 目标代码(object code)
- 链接器(Linker)
- 可执行文件(executables)
Clang / LLVM
iOS 开发中 Objective-C 和 Swift 都用的是 Clang / LLVM 来编译的。LLVM是一个模块化和可重用的编译器和工具链技术的集合,Clang 是 LLVM 的子项目,是 C,C++ 和 Objective-C 编译器,目的是提供惊人的快速编译,比 GCC 快3倍,其中的 clang static analyzer 主要是进行语法分析,语义分析和生成中间代码,当然这个过程会对代码进行检查,出错的和需要警告的会标注出来。LLVM 核心库提供一个优化器,对流行的 CPU 做代码生成支持。lld 是 Clang / LLVM 的内置链接器,clang 必须调用链接器来产生可执行文件。参考
编译命令
clang -fobjc-arc -framework Foundation main.m -o main
-fobjc-arc
表示编译器需要支持arc特性-framework Fundation
表示引用Fundation
框架main.m
为需要进行编译的源代码文件-o main
表示输出的可执行文件的中文名
消息机制及消息转发
将代码转换为C查看实现原理
通过Xcode的Command Line Tool
创建一个测试项目,编写代码如下:
int main (int argc, const char * argv[])
{
@autoreleasepool
{
// insert code here...
Person *person = [[Person alloc] init];
NSLog(@"Hello, World!");
}
return 0;
}
命令行运行:clang -rewrite-objc main.m
,生成main.cpp
文件,代码如下
int main (int argc, const char * argv[])
{
/* @autoreleasepool */
{ __AtAutoreleasePool __autoreleasepool;
Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_cg_kmk6sd7j26d863kzm4bsc2sw0000gn_T_main_04c1bd_mi_0);
}
return 0;
}
消息转发机制网上有很多介绍,可以参考:
相关的一些知识: