
本文会对 clang driver 的 参数解析 流程进行分享
为了控制 clang 的运行,clang 必须支持不同的参数对各种行为进行控制,所以,clang driver 启动后的第一个主要任务就是 参数解析
正式分享前,我们先按照惯例分享本文涉及的主要 类图 和 流程图,方便对 参数解析 的主要流程进行理解
Option 信息的结构体。比如 -v 参数的帮助信息是 Show commands to run and use verbose outputInfo 和 OptTable,提供了一些封装好的方法,比如通过 OptionClass getKind() 方法暴露 Info 的类型Option 和其它命令行参数信息,比如 -arch armv64 的 arm64 会被保存到 ArgOption 的相关方法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,用于后续使用,比如 TheInputOptionIDPrefixChars 和 PrefixesUnion 记录合法的参数前缀,用于后续的快速参数合法性判断,比如 -v 参数的前缀是 -Driver::ParseArgStrings Driver::ParseArgStrings 方法的作用是将字符串数组解析为 ArgList,并做相关的校验
具体流程如下:
Driver::getOpts 获取 clang driver 支持的所有参数 InfoParseArgs 解析命令行参数
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 会变成 archInfo 初始化 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