LLVM编译流程等相关知识整理
Overview
整理这篇博客主要是了解iOS编译的过程,了解其相关知识,丰富自己的知识体系。
在写这篇博客之前查看了李明杰在腾讯课堂的关于LLVM的付费课程,《LLVM编译器实战教程》相关书籍,还有网络上一些博客,在此向他们致敬!

什么是LLVM
LLVM项目是模块化、可重用的编译器以及工具链技术的集合。
LLVM跟传统的静态编译器一样使用了经典三段式的结构设计,如下图所示,分别为前端、优化器和后端。
传统编译器架构

Frontend(编译器前端):进行词法分析、语法分析、语义分析、生成中间代码(IR)。Optimizer(优化器):中间代码优化。Backend(后端):生成机器码
LLVM编译器如这篇文章的头图所示。这样做的优点如下:
- 如果需要支持一种新的编程语言,只需要实现一种新的编译器前端即可。
- 如果需要支持一种新的硬件设备,只需要实现一个新的后端即可。
- 优化阶段是一个通用的阶段,它针对的是统一的
LLVM IR,不论是支持新的编程语言,还是支持新的硬件设备,都不需要对优化阶段进行修改。
什么是Clang
Clang是LLVM项目的一个子项目,是基于LLVM架构的C/C++/Objective-C编译器前端。
Clang常用指令
Clang工具可以再Xcode中查看,具体路径为:
1 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang |
可以再终端输入Clang -help查看所有指令。
常用的指令如下所示:
- 生成可执行文件:
clang main.o -o main - 查看编译过程:
clang -ccc-print-phases main.m - 查看预处理结果:
clang -E main.m - 语法分析,生成Token:
clang -fmodules -E -Xclang -dump-tokens main.m - 生成语法树(AST):
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m - LLVM中间表示层(LLVM IR):
clang -S -fobjc-arc -emit-llvm main.m -o main.ll - 生成汇编:
clang -S -fobjc-arc main.m -o main.s - 生成目标文件:
clang -fmodules -c main.m -o main.o
swiftc常用指令
swiftc工具可以在Xcode中查看,具体路径为:
1 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc |
可以在终端输入swiftc -help 查看相关指令。
常用的指令如下所示:
- 生成可执行文件:
swiftc -o main.out main.swift - 生成抽象语法树(AST):
swiftc main.swift -dump-ast - 生成中间语言(SIL):
swiftc main.swift -emit-sil - LLVM中间表示层(LLVM IR):
swiftc main.swift -emit -ir - 生成汇编:
swiftc main.swift -emit-assembly
App编译过程
- 编译信息写入辅助文件,创建文件架构 .app 文件
- 处理文件打包信息
- 执行 CocoaPod 编译前脚本,checkPods Manifest.lock
- 编译.m文件,使用 CompileC 和 clang 命令
- 链接需要的 Framework
- 编译 xib
- 拷贝 xib ,资源文件
- 编译 ImageAssets
- 处理 info.plist
- 执行 CocoaPod 脚本
- 拷贝标准库
- 创建 .app 文件和签名
Swift语言编译过程
Swift编译前端使用的是swiftc,其中Swift前端会多出SIL optimizer,它会将*.swift生成的中间代码*.sil设置成High-Level IR。
因为swift在编译时就完成了方法绑定直接通过地址调用,属于强类型语言。方法调用也不像OC那样进行消息转发,这样编译就可以获得更多的信息用在后端的优化上。

关于LinkMap
Link Map File其实就是链接的映射文件,它是在Xcode生成可执行文件的同时生成的链接信息文件,用于描述可执行文件的构造部分,包含了代码段和数据段的分布情况。
Object files
这个部分的内容都是 .m 文件编译后的 .o 和需要 link 的 .a 文件。前面是文件编号,后面是文件路径。
Sections
这里描述的是每个 Section在可执行文件中的位置和大小。每个 Section 的 Segment 的类型分为__TEXT代码段和 __DATA 数据段两种。
Symbols
Symbols是对Sections进行了再划分。这里会描述所有的methods,ivar和字符串,及它们对应的地址,大小,文件编号信息。
关于符号表dSYM
符号表是内存地址与函数名、文件名、行号的映射表。符号表的元素如下所示:
<起始地址><结束地址><函数>[<文件名:行号>]
一般打包完成后会保存符号表文件,后期可以通过堆栈进行解析和还原,来定位用户APP发生Crash的代码位置。
可以参考Bugly相关文档