LLVM

  1. iOS 开发为什么使用的是编译器?
    我们都知道,iOS 编写的代码是先使用编译器把代码编译成机器码,然后直接在 CPU 上执行机器码的。之所以不使用解释器来运行代码,是因为苹果公司希望 iPhone 的执行效率更高、运行速度能达到最快。
  1. 那为什么说用解释器运行代码的速度不够快呢?
    这是因为解释器会在运行时解释执行代码,获取一段代码后就会将其翻译成目标代码(就是字节码(Bytecode)),然后一句一句地执行目标代码。
    也就是说,解释器,是在运行时才去解析代码,这样就比在运行之前通过编译器生成一份完整的机器码再去执行的效率要低。
  1. 既然编译器效率这么高,那为什么还有人用解释器呢?
    所谓事有利弊,解释器可以在运行时去执行代码,说明它具有动态性,程序运行后能够随时通过增加和更新代码来改变程序的逻辑。
    也就是说,你写的程序跑起来后不用重新启动,就可以看到代码修改后的效果,这样就缩短了调试周期。程序发布后,你还可以随时修复问题或者增加新功能,用户也不用一定要等到发布新版本后才可以升级使用。所以说,使用解释器可以帮我们缩短整个程序的开发周期和功能更新周期。
  1. 使用编译器和解释器执行代码的特点,我们就可以概括如下:
  • 采用编译器生成机器码执行的好处是效率高,缺点是调试周期长。
  • 解释器执行的好处是编写调试方便,缺点是执行效率低。


    编译器和解释器(执行器)的对比
  1. iOS 开发使用的到底是什么编译器?
    现在苹果公司使用的编译器是 LLVM,相比于 Xcode 5 版本前使用的 GCC,编译速度提高了 3 倍。同时,苹果公司也反过来主导了 LLVM的发展,让 LLVM 可以针对苹果公司的硬件进行更多的优化。
    总结来说,LLVM 是编译器工具链技术的一个集合。而其中的 lld 项目,就是内置链接器。编译器会对每个文件进行编译,生成 Mach-O(可执行文件);链接器会将项目中的多个 Mach-O 文件合并成一个。
  • 总结编译的几个主要过程:
    1)首先,你写好代码后,LLVM 会预处理你的代码,比如把宏嵌入到对应的位置。
    2)预处理完后,LLVM 会对代码进行词法分析和语法分析,生成 AST(Abstract Syntax Tree) 。AST 是抽象语法树,结构上比代码更精简,遍历起来更快,所以使用 AST 能够更快速地进行静态检查,同时还能更快地生成 IR(Intermediate Representation,中间表示)
    3)最后 AST 会生成 IR,IR 是一种更接近机器码的语言,区别在于和平台无关,通过 IR 可以生成多份适合不同平台的机器码。对于 iOS 系统,IR 生成的可执行文件就是 Mach-O。
    编译的主要过程
  1. 编译时链接器做了什么?
    Mach-O 文件里面的内容,主要就是代码和数据:代码是函数的定义;数据是全局变量的定义,包括全局变量的初始值。不管是代码还是数据,它们的实例都需要由符号将其关联起来。
    为什么呢?因为 Mach-O 文件里的那些代码,比如 if、for、while 生成的机器指令序列,要操作的数据会存储在某个地方,变量符号就需要绑定到数据的存储地址。你写的代码还会引用其他的代码,引用的函数符号也需要绑定到该函数的地址上。
    而链接器的作用,就是完成变量、函数符号和其地址绑定这样的任务。而这里我们所说的符号,就可以理解为变量名和函数名。
  1. 那为什么要让链接器做符号和地址绑定这样一件事儿呢?不绑定的话,又会有什么问题?
    如果地址和符号不做绑定的话,要让机器知道你在操作什么内存地址,你就需要在写代码时给每个指令设好内存地址。写这样的代码的过程,就像你直接在和不同平台的机器沟通,连编译生成 AST 和 IR 的步骤都省掉了,甚至优化平台相关的代码都需要你自己编写。
    这件事儿看起来挺酷,但可读性和可维护性都会很差,比如修改代码后对地址的维护就会让你崩溃。而这种“崩溃”的罪魁祸首就是代码和内存地址绑定得太早。
    另外,绑定得太早除了可读性和可维护性差之外,还会有更多的重复工作。因为,你需要针对不同的平台写多份代码,而这些代码本可以通过高级语言一次编译成多份。
    既然这样,那我们应该怎么办呢?我们首先想到的就是,用汇编语言来让这种绑定滞后。随着编程语言的进化,我们很快就发现,采用任何一种高级编程语言,都可以解决代码和内存绑定过早产生的问题,同时还能扫掉使用汇编写程序的烦恼。

来源:戴铭iOS开发课

你可能感兴趣的:(LLVM)