本篇文章会对 clang driver
的 构建 Actions 流程进行详细的讲解
image
当需要处理的源码文件列表 构建完成后,我们就可以根据参数和源文件类型计算需要的 Action
了。
正式分享前,我们先按照惯例分享本文涉及的主要 类图 和 流程图,方便对 参数解析 的主要流程进行理解
Input
、Action
类型,产物类型等信息;可以理解为将某种输入转为输出文件的操作步骤,比如,PreprocessJobAction
可以将源码 main.m
转为 main.im
bitcode
的过程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
创建流程
Preprocess
ConstructPhaseAction
方法检测到 phases::Preprocess
时会依次进行以下处理:
TT_ObjC
TT_ObjC
获取输出文件的类型 TY_PP_ObjC
Input
和 OutputTy
构建 PreprocessJobAction
image
image
.m
文件支持的第一个 phase
是 phases::Preprocess
.m
的预处理类型同样由 Types.def
文件维护Compile
phases::Compile
代表编译器的 前端 流程
phases::Compile
同样会根据传入的参数判断需要组装的类型,比如是否存在 -rewrite-objc
、-emit-ast
等参数
本例中,会构建 CompileJobAction
(该 action
会生成 types::TY_LLVM_BC
文件)
image
Backend
phases::Backend
就是我们通常所说的 编译器后端
phases::Backend
负责组装 BackendJobAction
,本例中,该 JobAction
的输出文件类型是 TY_PP_Asm
(文件扩展名是 .s
)
image
Assemble
phases::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 & Lipo
link 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