前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >clang 源码导读(3): clang driver 参数解析

clang 源码导读(3): clang driver 参数解析

作者头像
酷酷的哀殿
发布2021-03-18 09:50:33
2K0
发布2021-03-18 09:50:33
举报
文章被收录于专栏:酷酷的哀殿

前言

本文会对 clang driver参数解析 流程进行分享

为了控制 clang 的运行,clang 必须支持不同的参数对各种行为进行控制,所以,clang driver 启动后的第一个主要任务就是 参数解析

正式分享前,我们先按照惯例分享本文涉及的主要 类图流程图,方便对 参数解析 的主要流程进行理解

  1. Info[1] 是保存了预定义的各种 Option 信息的结构体。比如 -v 参数的帮助信息是 Show commands to run and use verbose output
  2. Option[2] 是持有 InfoOptTable,提供了一些封装好的方法,比如通过 OptionClass getKind() 方法暴露 Info 的类型
  3. Arg[3] 持有了 Option 和其它命令行参数信息,比如 -arch armv64arm64 会被保存到 Arg
  4. OptTable[4] 提供解析参数,并懒加载创建 Option 的相关方法
  5. InputArgList[5] 持有了输入的原始参数和解析后的参数列表
  6. DriverOptTable[6] 记录了 clang driver 相关的 Info 信息,是 OptTable 的子类

一、DriverOptTable

DriverOptTable 记录了 clang driver 相关的 Info 信息,是 OptTable 的子类

  1. 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

  1. 因为 DriverOptTable 继承自 OptTable,所以,这里会触发 OptTable 的初始化方法

image

image

  1. OptTable 的初始化时,会记录一些关键的 ID,用于后续使用,比如 TheInputOptionID
  2. 同时,会通过 PrefixCharsPrefixesUnion 记录合法的参数前缀,用于后续的快速参数合法性判断,比如 -v 参数的前缀是 -

二、Driver::ParseArgStrings

Driver::ParseArgStrings 方法的作用是将字符串数组解析为 ArgList,并做相关的校验

具体流程如下:

  1. 调用 Driver::getOpts 获取 clang driver 支持的所有参数 Info
  2. 调用 ParseArgs 解析命令行参数
  3. 对解析到的命令行参数进行判断,检测到 不支持 或者 未知 的参数时,会抛出异常

image

如何区分 不支持 或者 不认识 的参数

  1. clang driver 不支持 的参数,都可以通过 Options.td 文件查到 以 -pass-exit-codes 为例,gcc 支持该参数,但是 clang 不支持 此参数

image

image

  1. 不认识 的参数就是类似于 -test 这种,开发者随意拼写的参数

image

三、ParseArgs

OptTable::ParseArgs 方法负责将字符串数组解析为 ArgList

具体流程如下:

  1. 先初始化 InputArgList 的实例,并存储原始的入参信息
  2. 通过 while原始参数字符串进行遍历,并通过 OptTable::ParseOneArg 方法将所有的原始参数字符串解析为 Arg 的实例
  3. 最后 Args 会持有所有的解析后的参数

通过添加调试代码,我们可以感受一下以下命令行对应的原始参数和解析后的 Arg 实例分别是什么样子

代码语言:javascript
复制
clang -arch arm64 /var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/C/main.m -target arm64-apple-ios11.1

image

四、ParseOneArg

OptTable::ParseOneArg 方法负责解析单个参数

具体流程如下:

  1. 先移除参数的前缀,并通过 std::lower_bound 查找第一个前缀匹配的 Info 比如,-arch 会变成 arch
  2. 根据 Info 初始化 Option 持有参数信息
  3. 通过 Option::accept 方法校验参数是否正常
  4. 参数正常时直接返回
  5. 如果没有找到合适的参数,再判断参数是否以 / 开头,如果开始,会把参数当做源码文件进行处理
  6. 其它情况下,会当做参数当做 未知参数 进行下一步处理

image

  1. std::lower_bound 会依赖下面两个方法查找第一个前缀匹配的参数 Info.NameName 的查找逻辑比较复杂,需要深入研究的同学,可以逐步调试帮助理解

image

image

  1. Option::accept 方法会依次进行以下处理 比如,-fembed-bitcode-marker 就是 -fembed-bitcode=marker 参数的别名,两个参数的意义完全相同

image

  1. 先转发到 Option::acceptInternal 方法进行参数校验
  2. 判断解析到的参数是否属于别名
  3. 如果别名,会进行特殊处理

  1. 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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 酷酷的哀殿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、DriverOptTable
  • 二、Driver::ParseArgStrings
    • 如何区分 不支持 或者 不认识 的参数
    • 三、ParseArgs
    • 四、ParseOneArg
    • 总结
      • 参考资料
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档