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相关文档