编译器

1.编译/解释

  • 编译型语言

代码须编译成机器码才能在CPU上执行的语言,如OC和Swift,其优点是代码执行效率高。

  • 解释型语言

解释型语言,如 JavaScript 和 Python,代码不需要经过编译器,而是通过解释器直接将代码解释成CPU可以执行的代码。编写灵活,但执行效率低一些~

本篇主要关注编译型语言。编译过程可以划分为前端和后端两部分:

2.Clang

编译器前端将不同的高级编程语言经过词法分析、语法分析转化为与前端语言无关的统一的中间表示。iOS 中的编译器前端使用的是 Clang,它是一个 C++ 编写的、基于LLVM 的 C/C++/Objective-C/Objective-C++ 编译器。其主要任务是处理一些和具体机器无关的针对语言的分析操作:

预处理:

  • 符号化 (Tokenization)
  • 宏定义的展开
  • #include 的展开。

语法和语义分析:

  • 将符号化后的内容转化为一棵解析树 (parse tree)
  • 解析树做语义分析(包含类型检查和其他检查)
  • 输出一棵抽象语法树(Abstract Syntax Tree* (AST))

生成代码

  • 将 AST 转换为更低级的中间码 (LLVM IR)

3.LLVM

编译器后端负责优化中间代码并生成对应平台的汇编代码。LLVM 属于编译器后端,其主要作用是:

代码优化

  • 对生成的中间码做优化
  • 生成特定目标代码
  • 输出汇编代码

汇编器

  • 将汇编代码转换为以.o 结尾的目标对象文件(将可读的汇编代码转换为机器代码)。

链接器

  • 读取目标文件和库并解决未知符号问题,将它们编码进一个可执行文件或动态库中。

4.Bitcode

一般的编译流程:OC -> Clang AST -> CIL IR -> LLVM IR -> MIR -> Mach-O。

Bitcode 是 LLVM 中引入的一种中间代码,处在编译的LLVM IR这一阶段,尚未到 MIR 这一步。

Bitcode 提交到商店后,后续构建过程交给苹果完成。步骤之一就是剥离二进制符号(Binary symbol stripping),即从二进制文件中删除非必要的元数据,以便优化二进制文件的大小。

发布新款设备后,苹果可以用 Bitcode 生成对应芯片的MIR,无需开发者重新打包上传。

更新:苹果曾强推 Bitcode,但 Xcode 14 后遭到弃用~

在TARGET -> Build Settings -> Linking -> Other linker Flags 中可配置链接参数。

  • -all_load

将静态库中所有文件都加载到IPA里,包括没用的一些文件、函数等。

  • -noall_load

链接器默认的配置,只加载用到的那部分代码,没用到的会被优化掉,减小包体。

1
2
OC是动态语言,如果调用的方法没有被编译进来,运行时会闪退。
编译时,如果发现没有此方法,会报错”referenced from..”。
  • -force_load<文件>

加载指定的某些文件。导入静态库后找不到文件或方法,推荐使用这个参数。

  • -ObjC

如果工程里有OC和C++等代码,只将所有ObjC文件(.m、分类等)编译到IPA里。


题外话:

1、可以使用合适的链接参数,优化包体大小。

2、如果工程与静态库里定义了同名类或函数,但仅仅是将此静态库打包到了工程里,并没有 import 或使用它,此时是不会报错的。因为链接时默认使用 -noall_load 参数,不会链接没用到的类和函数,应用的二进制中只包含我们自己的那个类和函数。反之如果使用 -all_load 或 -ObjC 参数,即使没用到,也会报错。

6.Xcode Build

Xcode 是根据 target 分别编译的。每个 target 的具体的编译过程可以通过展开日志查看。

基本的格式是先简明一句说明要干什么,再缩进的几行说明具体的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Build target CodeMix of project CodeMix with configuration Debug

CompileC /Users/../XXViewController.o CodeMix/XXViewController.m
normal x86_64 objective-c com.apple.compilers.llvm.clang.1_0.compiler
cd /Users/../CodeMix
export LANG=en_US.US-ASCII
export PATH=“../XXViewController.o

Ld /Users/../Debug-iphonesimulator/CodeMix.app/CodeMix normal x86_64
cd /Users/../CodeMix
export IPHONES_DEPLOYMENT_TARGET=11.2
..

PhaseScriptExecution Run\ Script /Users/../Script-0AC86E9E1FF6721A00098A24.sh
cd /Users/Macmafia/Desktop/CodeMix
export ACTION=build
export AD_HOC_CODE_SIGNING_ALLOWED=YES
export ALTERNATE_GROUP=staff

/bin/sh -c /Users/../Script-0AC86E9E1FF6721A00098A24.sh

PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE symbols(src text, des text);
COMMIT;

Touch /Users/../Build/Products/Debug-iphonesimulator/CodeMix.app
cd /Users/../CodeMix
export PATH="/Applications/Xcode.app/../Debug-iphonesimulator/CodeMix.app

CodeSign /Users/../Debug-iphonesimulator/CodeMix.app
cd /Users/../CodeMix
export CODESIGN_ALLOCATE=/Applications/Xcode.app/../codesign_allocate

Signing Identity: "-"
..
Build succeeded 2018/1/26 下午9:35

从上面日志可以看到,大致的过程是:

  • compile swift文件
  • compile各个.m文件(按名字升序)
  • compile xib
  • compile storyboard
  • link storyboards
  • copy静态资源,包括img,string,font
  • compile asset catalogs
  • run custom shell script
  • process info.plist
  • copy Swift standard libraries into xx.app(拷贝swift标准库)
  • sign app(代码签名)
  • touch app(生成.app文件)
  • validate app(真机build有)

参考文章:

#©编译器-objccn

#©极客学院-OC期刊

#©GCC编译器


编译器
https://davidlii.cn/2019/02/15/compile.html
作者
Davidli
发布于
2019年2月15日
许可协议