本文会对 clang driver
的 参数解析 流程进行分享
为了控制 clang
的运行,clang
必须支持不同的参数对各种行为进行控制,所以,clang driver
启动后的第一个主要任务就是 参数解析
正式分享前,我们先按照惯例分享本文涉及的主要 类图 和 流程图,方便对 参数解析 的主要流程进行理解
Option
信息的结构体。比如 -v
参数的帮助信息是 Show commands to run and use verbose output
Info
和 OptTable
,提供了一些封装好的方法,比如通过 OptionClass getKind()
方法暴露 Info
的类型Option
和其它命令行参数信息,比如 -arch armv64
的 arm64
会被保存到 Arg
Option
的相关方法clang driver
相关的 Info
信息,是 OptTable
的子类DriverOptTable 记录了 clang driver
相关的 Info
信息,是 OptTable
的子类
DriverOptions
模块提供了函数 const llvm::opt::OptTable &clang::driver::getDriverOptTable()
可以获取 clang driver
支持的所有参数信息
DriverOptTable
初始化时依赖的 InfoTable
参数是通过 clang/Driver/Options.inc
生成的
通过下图,我们可以看到 InfoTable 的长度是 2776
image小知识:当我们编译 llvm
项目时,会由 TableGen
工具将 Options.td
文件生成 Options.inc
原始的文本信息如下:
image
DriverOptTable
继承自 OptTable
,所以,这里会触发 OptTable
的初始化方法
image
image
OptTable
的初始化时,会记录一些关键的 ID,用于后续使用,比如 TheInputOptionID
PrefixChars
和 PrefixesUnion
记录合法的参数前缀,用于后续的快速参数合法性判断,比如 -v
参数的前缀是 -
Driver::ParseArgStrings
Driver::ParseArgStrings
方法的作用是将字符串数组解析为 ArgList
,并做相关的校验
具体流程如下:
Driver::getOpts
获取 clang driver
支持的所有参数 Info
ParseArgs
解析命令行参数image
不支持
或者 不认识
的参数clang driver
不支持 的参数,都可以通过 Options.td
文件查到
以 -pass-exit-codes
为例,gcc
支持该参数,但是 clang
不支持 此参数
image
image
-test
这种,开发者随意拼写的参数
image
ParseArgs
OptTable::ParseArgs
方法负责将字符串数组解析为 ArgList
具体流程如下:
InputArgList
的实例,并存储原始的入参信息while
对原始参数字符串进行遍历,并通过 OptTable::ParseOneArg
方法将所有的原始参数字符串解析为 Arg
的实例Args
会持有所有的解析后的参数通过添加调试代码,我们可以感受一下以下命令行对应的原始参数和解析后的 Arg
实例分别是什么样子
clang -arch arm64 /var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/C/main.m -target arm64-apple-ios11.1
image
ParseOneArg
OptTable::ParseOneArg
方法负责解析单个参数
具体流程如下:
std::lower_bound
查找第一个前缀匹配的 Info
比如,-arch
会变成 arch
Info
初始化 Option
持有参数信息Option::accept
方法校验参数是否正常/
开头,如果开始,会把参数当做源码文件进行处理image
std::lower_bound
会依赖下面两个方法查找第一个前缀匹配的参数
Info.Name
和 Name
的查找逻辑比较复杂,需要深入研究的同学,可以逐步调试帮助理解
image
image
Option::accept
方法会依次进行以下处理
比如,-fembed-bitcode-marker
就是 -fembed-bitcode=marker
参数的别名,两个参数的意义完全相同
image
Option::acceptInternal
方法进行参数校验Option::acceptInternal
方法会根据 Option
的类型进行处理并生成 Arg
实例。
因为 -arch
的类型是 SeparateClass
,所以,会将下一个原始参数字符串(arm64
)当做 value
进行处理
类型示例Separate-arch arm64Flag-vJoined-fembed-bitcode=marker
image
本文通过分析 DriverOptTable
的生成机制并分析Driver::ParseArgStrings
内部流程,对 clang driver
的参数解析流程做了简单的分析
[1]
Info: https://www.llvm.org/doxygen/structllvm_1_1opt_1_1OptTable_1_1Info.html#details
[2]
Option: https://www.llvm.org/doxygen/classllvm_1_1opt_1_1Option.html
[3]
Arg: https://www.llvm.org/doxygen/classllvm_1_1opt_1_1Arg.html
[4]
OptTable: https://www.llvm.org/doxygen/classllvm_1_1opt_1_1OptTable.html#details
[5]
InputArgList: https://www.llvm.org/doxygen/classllvm_1_1opt_1_1InputArgList.html
[6]
DriverOptTable: https://clang.llvm.org/doxygen/DriverOptions_8cpp_source.html