编译原理
Last updated
Was this helpful?
Last updated
Was this helpful?
本文参考
一般可以将编程语言分为两种,和。
像C++,Objective C都是编译语言。编译语言在执行的时候,必须先通过编译器生成机器码,机器码可以直接在CPU上执行,所以执行效率较高。
像JavaScript,Python等都是直译式语言(脚本语言)。直译式语言不需要经过编译的过程,而是在执行的时候通过一个中间的解释器将代码解释为CPU可以执行的代码。所以,较编译语言来说,直译式语言效率低一些,但是编写的更灵活,也就是为啥JS大法好。
iOS开发目前的常用语言是:Objective和Swift。二者都是编译语言,换句话说都是需要编译才能执行的。二者的编译都是依赖于Clang + LLVM. 篇幅限制,本文只关注Objective C,因为原理上大同小异。
可能会有同学想问,我不懂编译的过程,写代码也没问题啊?这点我是不否定的。但是,充分理解了编译的过程,会对你的开发大有帮助。本文的最后,会以以下几个例子,来讲解如何合理利用XCode和编译
__attribute__
Clang警告处理
预处理
插入编译期脚本
提高项目编译速度
三段式设计
编译主要步骤 1. 源代码(source code) -> 2. 预处理器(preprocessor) -> 3. 编译器(compiler) -> 4. 汇编程序(assembler) -> 5. 目标代码(object code) -> 6. 链接器(Linker) -> 7. 可执行文件(executables)
废话不多说,直接进入正题😍
Clang 需要用 CMake 和 Ninja 来编译,可以通过 Homebrew 安装
安装 Homebrew
安装 CMake 3.12.4
安装 Ninja 1.8.2
源码下载
下载 LLVM (clang 9)
选择自动创建schemes,选择targetALL_BUILD
,然后开始漫长的编译预计1500s
出现以下错误时,可能是权限导致,加上sudo
再次尝试编译
编译成功后将权限还原到默认
简单的编译过程如图
编译器前端的任务是进行:语法分析,语义分析,生成中间代码(intermediate representation )。在这个过程中,会进行类型检查,如果发现错误或者警告会标注出来在哪一行。
编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化。iOS的编译过程,后端的处理如下
LVVM优化器会进行BitCode的生成,链接期优化等等。
LLVM机器码生成器会针对不同的架构,比如arm64等生成不同的机器码。
编译信息写入辅助文件,创建文件架构 .app 文件
处理文件打包信息
执行 CocoaPod 编译前脚本,checkPods Manifest.lock
编译.m文件,使用 CompileC 和 clang 命令
链接需要的 Framework
编译 xib
拷贝 xib ,资源文件
编译 ImageAssets
处理 info.plist
执行 CocoaPod 脚本
拷贝标准库
创建 .app 文件和签名
替换宏定义
头文件的导入
编译条件
把代码细拆分成最小的Token(包含代码位置),如大小括号,
等于号还有字符串等
验证语法是否正确
将所有节点生成AST
CodeGen 会负责将AST自上而下递归遍历翻译成 LLVM IR
IR 是编译过程的前端输出,后端的输入
LLMV在编译时会做些优化,Xcode编译设置中可设置级别
开启Bitcode会进一步优化
Pass 是LLVM优化的一个节点,可以自定义
对于不想看我啰里八嗦讲一大堆原理的同学,可以直接跳到本文的最后一个章节。
Objective C采用Clang(swift采用)作为编译器前端,LLVM(Low level vritual machine)作为编译器后端。