
本篇文章会对 clang driver 的 构建 Actions 流程进行详细的讲解

image
当需要处理的源码文件列表 构建完成后,我们就可以根据参数和源文件类型计算需要的 Action 了。
正式分享前,我们先按照惯例分享本文涉及的主要 类图 和 流程图,方便对 参数解析 的主要流程进行理解
Input、Action 类型,产物类型等信息;可以理解为将某种输入转为输出文件的操作步骤,比如,PreprocessJobAction 可以将源码 main.m 转为 main.imbitcode 的过程bitcode 转为 .s 文件的过程.s 文件转为 .o 二进制文件的过程.o 文件合并为静态库/动态库/可执行文件的过程.o 文件与特定的架构做绑定BindArchAction 输入合并为单一的 fat mach-o 文件Input 和 BindArchAction 没有对应任何的过程

构建 Actions 的目的是为了满足以下目的:
clang driver 需要根据 参数 计算需要进行的步骤
比如,当 -emit-llvm 参数传入时,编译器只需要 预处理、编译器前端 两步,不再需要进行 编译器后端 和 汇编
-emit-llvm 的含义是将输入文件编译为 bitcode 文件clang driver 需要根据 输入文件类型 计算需要进行的步骤
比如,当输入的源码文件是汇编类(扩展名是 .s )型时,只需要最后 汇编 阶段BuildUniversalActions 方法源码分析 BuildUniversalActions 方法负责构建 Actions
-arch 参数生成需要处理的 Archs ,留待后续的处理使用

image
-arch 参数,可以通过 ToolChain::getDefaultUniversalArchName() 方法获取 triple 对应的架构

image
BuildActions 计算每个输入文件对应的 SingleActions (可能包含预处理、编译、后端、汇编等)
注意:BuildUniversalActions 的 SingleActions 参数传到 BuildActions 方法后,名字会变为 Actions

image
BuildActions 会先调用 Driver::handleArguments 方法对参数进行一些处理

image
Inputs,并通过 llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> types::getCompilationPhases(const clang::driver::Driver &Driver,llvm::opt::DerivedArgList &DAL, ID Id) 获取需要对输入文件进行处理的 phase 数组

image
types::getCompilationPhases 内部会根据传入的参数获取需要执行的最后一个 phase

image通过 -ccc-print-phases 参数可以对比两种场景的差异,比如,当 -emit-llvm 参数传入时,就会将移除 Backend 后面的 Assemble

image
types::getCompilationPhases 会通过函数 llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> types::getCompilationPhases(ID Id, phases::ID LastPhase) 根据文件类型 TY_ObjC 和 LastPhase 获取后续的 phase 列表
两个函数名相同,参数不一样

imageTypes.def 文件维护了不同文件类型默认情况下需要经历的 phase
.m 需要经历以下 5 个阶段

image
Driver::BuildActions 方法会先组装一个 InputAction (每个 Job 都包含一个 Kind 属性,代表该 Job 的类型,InputAction 的 Kind是 InputClass ),InputAction 就相当于输入文件的占位符

image
phase,并根据 phase 创建 Action(通过调用 ConstructPhaseAction 函数实现)
注意,每个 NewCurrent 都会持有 Current

image
Action 创建流程介绍 本节会介绍通过除 InputAction 以外的 Action 创建流程
PreprocessConstructPhaseAction 方法检测到 phases::Preprocess 时会依次进行以下处理:
TT_ObjCTT_ObjC 获取输出文件的类型 TY_PP_ObjCInput 和 OutputTy 构建 PreprocessJobAction

image

image
.m 文件支持的第一个 phase 是 phases::Preprocess.m 的预处理类型同样由 Types.def 文件维护Compilephases::Compile 代表编译器的 前端 流程
phases::Compile 同样会根据传入的参数判断需要组装的类型,比如是否存在 -rewrite-objc 、-emit-ast 等参数
本例中,会构建 CompileJobAction(该 action 会生成 types::TY_LLVM_BC 文件)

image
Backendphases::Backend 就是我们通常所说的 编译器后端
phases::Backend 负责组装 BackendJobAction,本例中,该 JobAction 的输出文件类型是 TY_PP_Asm (文件扩展名是 .s)

image
Assemblephases::Assemble 会组装 AssembleJobAction ,该 JobAction 的输出文件类型为 TY_Object (文件扩展名是 .o)

image
Link因为 link 是可以将一个或多个源码文件产出的 .o 文件进行链接,所以,LinkAction 会稍微复杂一些:
Driver::BuildActions 方法会维护一个 LinkerInputs 数组,负责记录需要进行 link 操作的 JobAction
当某个源码文件需要进行 link 操作时,就会先临时保存到 LinkerInputs 数组

image
LinkerInputs 是否为空;如果非空,会增加一个 LinkJobAction 进行下一步处理

image截止到这一步, 所有的 Action 就会构造为一个类似于链表的构造

image
bind & Lipolink action 创建完毕后,会根据 BuildUniversalActions 生成的 Archs 数组创建对应数量的 BindArchAction,该JobAction 记录需要产出文件的架构,比如 arm64 或者 armv7
如果 Arch 数量大于 1,会新增一个 LipoJobAction ,LipoJobAction 会将不同的架构的二进制合并为一个 fat mach-o 文件

image
经过这一步后,所有的 Action 就可以组成下面这种结构:

image
本文通过对 BuildUniversalActions 方法的源码分析,介绍了 clang driver 构建 Actions 的流程。
[1]
Action: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1Action.html#details
[2]
InputAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1InputAction.html#details
[3]
PreprocessJobAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1PreprocessJobAction.html#details
[4]
CompileJobAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1CompileJobAction.html#details
[5]
BackendJobAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1BackendJobAction.html#details
[6]
AssembleJobAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1AssembleJobAction.html#details
[7]
LinkJobAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1LinkJobAction.html#details
[8]
BindArchAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1BindArchAction.html#details
[9]
LipoJobAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1LipoJobAction.html#details
[10]
JobAction: https://clang.llvm.org/doxygen/classclang_1_1driver_1_1JobAction.html#details