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

clang 源码导读(2): clang driver 流程简介

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

前言

本文会对 clang driver 的内部流程做一个简单的介绍。

clang driver 流程简介

clang Driver 负责拼接编译器命令和 ld 命令。

注意:clang driver 自身不会对源码进行编译

clang Driver 的处理逻辑分为以下几步:

Parse: Option Parsing:解析传入的参数

Pipeline: Compilation Action Construction:根据每个输入的文件和类型,组建 action(比如 PreprocessJobAction

可以通过 clang -ccc-print-phases 可以查看需要处理的 action

代码语言:javascript
复制
  clang -ccc-print-phases -c t0.c t1.c
              +- 0: input, "t0.c", c
           +- 1: preprocessor, {0}, cpp-output
        +- 2: compiler, {1}, ir
     +- 3: backend, {2}, assembler
  +- 4: assembler, {3}, object
  5: bind-arch, "x86_64", {4}, object
              +- 6: input, "t1.c", c
           +- 7: preprocessor, {6}, cpp-output
        +- 8: compiler, {7}, ir
     +- 9: backend, {8}, assembler
  +- 10: assembler, {9}, object
  11: bind-arch, "x86_64", {10}, object

Bind: Tool & Filename Selection:根据 action 选择对应的工具文件名信息

通过 clang -ccc-print-bindings 可以查看对应的工具文件名信息

代码语言:javascript
复制
clang -ccc-print-bindings -c t0.c t1.c -arch arm64 -arch armv7
# "aarch64-apple-darwin19.6.0" - "clang", inputs: ["t0.c"], output: "/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/T/t0-9a2aac.o"
# "arm-apple-darwin19.6.0" - "clang", inputs: ["t0.c"], output: "/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/T/t0-7a4059.o"
# "arm-apple-darwin19.6.0" - "darwin::Lipo", inputs: ["/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/T/t0-9a2aac.o", "/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/T/t0-7a4059.o"], output: "t0.o"
# "aarch64-apple-darwin19.6.0" - "clang", inputs: ["t1.c"], output: "/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/T/t1-950abb.o"
# "arm-apple-darwin19.6.0" - "clang", inputs: ["t1.c"], output: "/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/T/t1-044386.o"
# "arm-apple-darwin19.6.0" - "darwin::Lipo", inputs: ["/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/T/t1-950abb.o", "/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/T/t1-044386.o"], output: "t1.o"

Translate: Tool Specific Argument Translation:根据输入的参数转为不同 tool 的参数

xcrun --sdk iphoneos clang -arch arm64 main.m -v-arch arm64 参数为例:

原始命令:

代码语言:javascript
复制
xcrun --sdk iphoneos clang -arch arm64  main.m -v

各个 tool 的参数:

image

  • usr/bin/clang -cc1 的参数:-triple arm64-apple-ios14.4.0

Execute:调用不同的 tool 执行任务。

该步骤会通过创建子进程方式调用tool

仍然以 xcrun --sdk iphoneos clang -arch arm64 main.m -v 为例,clang driver 最终会创建两个子线程 clang -cc1ld 执行最终的编译任务和链接任务

  • clang -cc1 可以将源码转为对象文件。本例中,clang -cc1 会将 .m 文件转为 .o 文件

为了方便理解,我们可以将下面的图片和上面的流程对应:

DriverArchitecture

更多相关内容可以参考笔者之前的文章 Ruby 与 clang 的 "Clang driver" 部分 或者 Driver Design & Internals


clang driver 源码概览

首先,我们以 xcrun -l clang main.m -v -O2 -o demo 为例对整个流程做一个简单的介绍

  1. 第一步:clang 会以 driver 模式被调用
  2. 第二步,clang driver 会根据传入的 main.m 参数构建为两个 Job
    1. 第一个任务是编译任务clang 接收 -cc1 参数后会以编译器的身份执行编译任务,输入文件是 main.m,输出文件是 main.o 对象文件
    2. 第二个任务是链接任务ld 会将 main.o 链接为 demo 可执行文件
  3. 最后,会根据上面的两个 Job 创建新的进程执行上面的两个 Job

image

正式分享前,我们先对本文涉及的 流程图 进行初步分享。读者可以结合流程图辅助记忆。

注意:随着源码的逐渐分析,流程图的细节会被逐渐完善

  1. main 函数会先创建诊断 (DiagnosticsEngine)实例 诊断是编译器与开发者进行交互的重要部分。编译器通过诊断可以提供错误、警告或建议。

image

  1. 随后,开始创建 Driver (clang::driver::Driver) 的实例:TheDriverTheDriver 负责后续的 clang driver 相关任务

image

  1. 通过 DriverBuildCompilation 方法生成需要执行的命令

image

  1. Driver 构造完 Jobs 后,会通过 DriverExecuteCompilation 方法执行命令

image

构建 Compilation

下面,我们再对 BuildCompilation 的流程进一步拆解。

BuildCompilation 方法主要包含以下步骤:

参数处理

调用 ParseArgStrings 函数 处理程序接收的参数 和 对配置文件解析

image

通过 computeTargetTriple 函数获取 triple 并通过 getToolChain 函数获取对应的 ToolChain

image

getToolChain 函数逻辑比较简单,对于 iOS 开发者,该函数会返回根据 triple 的系统信息返回 DarwinClang 的实例

image

创建 Commpilation 持有参数

image

通过 BuildInputs 函数获取输入文件

image

clang driver 支持一次性编译多个文件,比如下面的命令可以同时编译 main.mtest.m 两个源码文件

代码语言:javascript
复制
xcrun -l -sdk iphoneos clang main.m -arch arm64 -target x86_64-apple-ios8.0 test.m -v

BuildInputs 方法会遍历所有的参数,并筛选 Option::InputClass 类型的参数,最后会调用函数 types::ID types::lookupTypeForExtension(llvm::StringRef Ext) 获取对应的 types::ID

image

types::ID types::lookupTypeForExtension(llvm::StringRef Ext) 函数会根据输入文件 main.m 的扩展名 m 获取该文件的类型 TY_OBJC

image

输入文件处理完成后,会通过 BuildUniversalActions 函数构建 Action

image

随后再通过 BuildJobs 函数构建 Jobs

image

经过本节分析后,我们的流程图节点也膨胀了一倍,并且能够和之前分享的 clang driver 流程图片基本一一对应。

本文总结

本文结合实际的例子,对 clang driver 流程进行了简单的分享。

下一篇开始,我们会对 clang driver 的各种细节逐一介绍。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • clang driver 流程简介
  • clang driver 源码概览
  • 构建 Compilation
  • 本文总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档