- 简介
- 源码到可执行文件流程
- 编译器
- 编译流程
- 预处理(preprocessor)
- 词法分析(lexical anaysis)
- 语法分析(semantic analysis)
- CodeGen
- 生成汇编代码
- 生成目标文件
- 生成可执行文件
- Xcode中查看Clang编译.m文件信息
- Xcode常见编译报错分析
- 1. duplicate symbols报错
- 2. symbol(s) not found for architecture x86_64/arm64
- 应用场景
- Clang Attributes
- Clang警告处理
- 预处理
- Clang插件开发
- 总结
简介
–
拖更很久了,今天水文一篇。简单介绍下iOS底层编译的相关知识,帮助我们充分理解了iOS编译的过程,相信会对我们后续的开发有一定帮助。
源码到可执行文件流程
首先看一下iOS代码是如何从源码变成可执行文件的,有助于我们了解程序从编译到运行的全流程
- 编译器Clang会将源码XXX.m编译为目标文件XXX.o
- 链接器会将目标文件链接打包进最终的可执行文件Mach-O中
- 点击App ICON时,动态链接器dyld会加载可执行文件以及依赖的动态库,并最终执行到main.m里,至此App启动完成
编译器
编译器是将编程语言转换为目标语言的程序,大多数编译器由两部分组成:前端和后端。
- 前端负责词法分析,语法分析,生成中间代码;
- 后端以中间代码作为输入,进行行架构无关的代码优化,接着针对不同架构生成不同的机器码。
前后端依赖统一格式的中间代码(IR),使得前后端可以独立的变化。新增一门语言只需要修改前端,而新增一个CPU架构只需要修改后端即可。
Objective C/C/C++使用的编译器前端是clang,swift是swift,后端都是LLVM。
LLVM是一个模块化和可重用的编译器和工具链技术的集合,Clang 是 LLVM 的子项目,是 C,C++ 和 Objective-C 编译器,目的是提供惊人的快速编译,比 GCC 快3倍,
LLVM 还可以提供一种代码编写良好的中间表示 IR,这意味着它可以作为多种语言的后端,这样就能够提供语言无关的优化同时还能够方便的针对多种 CPU 的代码生成。
编译流程
Objective-C的编译器前端是Clang,诞生之初是为了替代GCC,提供更快的编译速度。我们可以通过下面这张图来了解Clang编译的大致流程:
下面我们通过clang命令来具体分析下源码编译的流程:
首先在命令行里输入
clang -ccc-print-phases main.m
可以看到源文件编译需要的几个不同的阶段
➜ clang -ccc-print-phases main.m
0: input, "main.m", objective-c
1: preprocessor, {0}, objective-c-cpp-output //预编译
2: compiler, {1}, ir //编译成中间代码ir
3: backend, {2}, assembler //生成汇编
4: assembler, {3}, object //生成目标文件.O
5: linker, {4}, image //链接成可执行文件
6: bind-arch, "x86_64", {5}, image
接下来我们新建一个main.m并详细来看下每个步骤分别做了什么
main.m
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}
预处理(preprocessor)
我们用下面的命令来查看clang预处理的结果:
clang -E main.m
注:如果main.m中用到了UIKit等类,可以在命令后添加-sysroot参数,记得将sdk换成你本机的版本,后续命令解决方法相同。如下所示:
clang -E main.m -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk
可以看到预处理后的文件行数有很多,在最后可以找到main函数
# 13 "/Applications/Xcode.app/Contents/Developer