APP编译过程

2、LLVM、Clang

LLVM

LLVM自己并非编译器,只是一套用于开发编译器、解释器等程序语言相关工具的,主要聚焦于编译器后端功能,如代码生成、代码优化、JIT等。前端

LLVM1 an umbrella project that hosts and develops a set of close-knit low-level toolchain components (e.g., assemblers, compilers, debuggers, etc.) LLVM 是一个涵盖和开发一系列紧密结合的低级工具链组件(例如,汇编器,编译器,调试器等)的综合项目objective-c

传统的编译器一般分为三个部分,前端(frontEnd),优化器(Optimizer)和后端(backEnd),在编译过程当中,前端主要负责词法和语法分析,将源代码转化为抽象语法树;优化器则是在前端的基础上,对获得的中间代码进行优化,使代码更加高效;后端则是将已经优化的中间代码转化为针对各自平台的机器代码。编程

Clang

Clang 是一个C、C++、Objective-C和Objective-C++编程语言的编译器前端。它采用了LLVM做为其后端。swift

Clang是2005年由苹果电脑发起,是LLVM编译器工具集的前端(front-end),目的是输出代码对应的抽象语法树(Abstract Syntax Tree, AST),并将代码编译成LLVM Bitcode。接着在后端(back-end)使用LLVM编译成平台相关的机器语言 。Clang支持C、C++、Objective C。后端

Clang自己性能优异,其生成的AST所耗用掉的内存仅仅是GCC的20%左右,测试证实Clang编译Objective-C代码时速度为GCC的3倍,还能针对用户发生的编译错误准确地给出建议。bash

iOS中的编译

Objective C采用Clang做为前端,而Swift则采用swift()做为前端,两者LLVM(Low level vritual machine)做为编译器后端。编译过程以下图架构

来看看一个文件的编译过程,新建Test.mapp

#import <Foundation/Foundation.h>

int main(){
    @autoreleasepool {
        NSLog(@"%@",@"Hello Leo");
    }
    return 0;
}

复制代码

在终端输入: clang -ccc-print-phases -framework Foundation test.m -o test 会看到下列的:编程语言

0: input, "Foundation", object 
1: input, "test.m", objective-c
2: preprocessor, {1}, objective-c-cpp-output//预处理
3: compiler, {2}, ir //编译生成IR(中间代码)
4: backend, {3}, assembler//汇编器生成汇编代码
5: assembler, {4}, object//生成机器码
6: linker, {0, 5}, image//连接
7: bind-arch, "x86_64", {6}, image//生成Image,也就是最后的可执行文件
复制代码

编译器前端

编译器前端的任务是进行:语法分析,语义分析,生成中间代码(intermediate representation )。在这个过程当中,会进行类型检查,若是发现错误或者警告会标注出来在哪一行。函数

编译器优化

LVVM优化器会进行BitCode的生成,连接期优化等等

编译器后端

LLVM机器码生成器会针对不一样的架构,好比arm64等生成不一样的机器码

4、Xcode执行Build的流程

  • 编译信息写入辅助文件,建立编译后的文件架构(name.app)
  • 写入辅助文件:将项目的文件结构对应表、将要执行的脚本、项目依赖库的文件结构对应表写成文件,方便后面使用
  • 运行预设脚本:Cocoapods 会预设一些脚本,固然你也能够本身预设一些脚原本运行。这些脚本都在 Build Phases 中能够看到;
  • 编译文件:针对每个文件进行编译,生成可执行文件 Mach-O,这过程 LLVM 的完整流程,前端、优化器、后端;使用CompileC和clang命令。
  • 连接库,例如Foundation.framework,AFNetworking.framework…
  • 拷贝资源文件:将项目中的资源文件拷贝到目标包;
  • 编译 storyboard 文件:storyboard 文件也是会被编译的;
  • 连接 storyboard 文件:将编译后的 storyboard 文件连接成一个文件;
  • 编译 Asset 文件:咱们的图片若是使用 Assets.xcassets 来管理图片,那么这些图片将会被编译成机器码,除了 icon 和 launchImage;
  • 运行 Cocoapods 脚本:将在编译项目以前已经编译好的依赖库和相关资源拷贝到包中。
  • 建立.app文件和对其签名

dSYM 文件

咱们在每次编译事后,都会生成一个dsym文件。dsym文件中,存储了16进制的函数地址映射。

在App实际执行的二进制文件中,是经过地址来调用方法的。在App crash的时候,第三方工具(Fabric,友盟等)会帮咱们抓到崩溃的调用栈,调用栈里会包含crash地址的调用信息。而后,经过dSYM文件,咱们就能够由地址映射到具体的函数位置。

5、提升项目Build速度

查看编译时间

咱们须要一个途径,可以看到编译的时间,这样才能有个对比,知道咱们的优化究竟有没有效果。 对于XCode 8,关闭XCode,终端输入如下指令 $ defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

代码优化-forward declaration

@class CLASSNAME,而不是#import CLASSNAME.h。这样,编译器能大大提升#import的替换速度。

对经常使用工具类打包

打包成Framework或者静态库,这样编译的时候这部分代码就不须要从新编译了。

经常使用头文件放到预编译文件里

XCode的pch文件是预编译文件,这里的内容在执行XCode build以前就已经被预编译,而且引入到每个.m文件里了。

Debug模式下,不生成dsym文件

上文提到了,dysm文件里存储了调试信息,在Debug模式下,咱们能够借助XCode和LLDB进行调试。因此,不须要生成额外的dsym文件来下降编译速度。

Debug开启Build Active Architecture Only

在XCode -> Build Settings -> Build Active Architecture Only 改成YES。这样作,能够只编译当前的版本,好比arm7/arm64等等,记得只开启Debug模式。这个选项在高版本的XCode中自动开启了。

相关文章
相关标签/搜索