iOS 编译流程分析

489 阅读4分钟

解释器和编译器

  • 解释器:解释器是直接执行用编程语言编写的指令的程序,解释的程序总是需要解释器来运行
  • 编译器:编译器是需要把我们的源代码翻译成机器能够读的懂二进制文件 举例: 下面是一段python代码
print("hello world\n")

截屏2021-09-02 下午8.59.05.png 只要我们安装了python的环境,就可以执行,这就是解释器的功能。

同样下面是一段c语言的代码:

#include<stdio.h>

int main(int argc,char * argv[]){
    printf("hello world\n");
    return 0;
}

如果我们需要执行需要先编译:

截屏2021-09-02 下午9.06.19.png 编译后会生成一个二进制文件a.out,然后才能运行。我们可以在/usr/bin 目录下找到clangpython,编译器和解释器

总结:解释器实际上就是边解释边运行,而编译器需要将我们所有的代码打包成一个可执行的二进制文件。

LLVM

概述:LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time),对开发者保持开放,并兼容已有脚本。

传统编译器的架构

截屏2021-09-02 下午9.42.08.png

  • Frontend(编译前端):解析源代码。进行词法分析、语法分析,检查源代码是否存语法错误,然后构建抽象语法数(Abstract Syntax Tree).LLVM前端还会生成中间代码(intermedidate representation)IR.
  • (Optimizer)优化器:负责进行各种代码优化。改善代码的运行时间
  • Backend(后端):将代码映射到目标指令集。生成机器语言,并且进行机器相关的代码优化.

iOS编译架构

Objective -C/C/C++的前端编译器都是clang,swift的的前端编译器是swift.后端都是LLVM

ios 编译.png

LLVM 的设计

  • 当编译器决定支持多种语言多种硬件架构时,LLVM的作用就体现出来了。其他的编译器如GCC也非常成功,但是作为整体应用程序设计,就有很多限制了.
  • LLVM最重要的方面是,使用通用的代码表示形式(IR),这样就可以为任何编程语言编写前端,并且可以为任何硬件架构编写后端

LLVM设计.png

编译流程

  • 我们新建一个.m文件通过如下命令查看,编译流程 clang -ccc-print-phases main.m

编译流程.png

  • 0:输入文件:找到源文件
  • 1:预处理阶段:这个过程包括宏的替换,头文件的导入。
  • 2:编译阶段:进行词法分析、语法分析、检测语法是否正确。最终生成IR。
  • 3:后端:这里LLVM会通过一个一个pass(节点)去优化,每个pass去做一些事情,最终生成汇编代码
  • 4:生成目标文件
  • 5:链接:链接需要的动态库和静态库,生成课执行文件
  • 6:通过不同的架构生成对应的课执行文件

预编译

#include <stdio.h>
#define kMachoC     2
int main(int argc, const char * argv[]) {
    int a= 1;
    int b = 3;
    printf("%ld",a+b+kMachoC);
    return 0;
}

clang -E main.m

截屏2021-09-03 上午11.47.13.png

截屏2021-09-03 上午11.47.22.png 可以看到头文件的导入和和宏的替换

编译阶段

词法分析

clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m

截屏2021-09-03 下午1.50.29.png 预编译处理完成后会进行词法分析,这里会把代码切成一个一个token,比如大小括号,还有字符串等

语法分析

clang -fmodules -fsyntax-only -Xclang -ast-dump main.m

截屏2021-09-03 下午1.56.16.png

词法分析完成之后就是语法分析,它的任务是验证语法是否正确,在词法分析的基础上将单词序列组合成各类语法短语。如“程序”、“语句”、“表达式”等待,然后将所有的节点组成抽象语法树。然后分析语法是否正确。

生成中间代码

clang -S -fobjc-arc -emit-llvm main.m 执行上面的命令会生成.ll 文件,

截屏2021-09-03 下午4.00.05.png LLVM IR语法

IR优化

LLVM的优化级别-O0 -O1 -O2 -O3 -Os

优化命令: clang -Os -S -fobjc-arc -emit-llvm main.m -o main.ll 优化后的代码:

截屏2021-09-03 下午4.18.57.png

bitCode

clang -emit-llvm -c main.ll -o main.bc xcode7之后,开启bitcode之后苹果会做进一步优化,生成.bc的中间代码.

生成汇编代码

通过最终的.bc或者.ll生成汇编代码

clang -S -fobjc-arc main.bc -o main.s

clang -S -fobjc-arc main.ll -o main.s

截屏2021-09-03 下午4.38.58.png 汇编优化:clang -Os -S -fobjc-arc main.m -o main.s

生成目标文件

clang -fmodules -c main.s -o main.o

查看目标文件:xcrun nm -nm main.o

截屏2021-09-03 下午4.52.10.png external:表示可以访问的外部文件

生成课执行的文件(链接)

clang main.o -o main

查看链接后的文件:xcrun nm -nm main

截屏2021-09-03 下午4.58.02.png _dyld_stub_binder,表示需要重绑定的符号,也就是printf函数