酷酷的哀殿


  • 首页

  • 技术

  • 笔记

  • 杂记

  • Todo

  • 关于

  • 搜索
close

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

时间: 2021-03-02   |   阅读: 1995 字 ~4分钟

前言

本文会对 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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
      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 可以查看对应的工具和文件名信息

    1
    2
    3
    4
    5
    6
    7
    
    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 参数为例:

    原始命令:

    1
    
    xcrun --sdk iphoneos clang -arch arm64  main.m -v
    

    各个 tool 的参数:

    1. usr/bin/clang -cc1 的参数: -triple arm64-apple-ios14.4.0
    2. usr/bin/ld 的参数: -arch arm64

    image

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

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

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

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

    2. ld 负责将多个对象文件、库进行链接操作,并产出最后的产出文件。本例中,ld 会产出 可执行文件

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

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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
graph LR

  subgraph clangDriver
    Driver
    Driver::BuildCompilation
    Driver::ExecuteCompilation
  end

  subgraph clang
    CreateAndPopulateDiagOpts
  end

  main--1 创建诊断-->CreateAndPopulateDiagOpts
  main--2 创建 Driver 实例-->Driver
  main--3 创建 Compilation-->Driver::BuildCompilation
  main--4 执行 Compilation-->Driver::ExecuteCompilation
  1. main 函数会先创建诊断 (DiagnosticsEngine)实例

    诊断是编译器与开发者进行交互的重要部分。编译器通过诊断可以提供错误、警告或建议。

    image

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

    image

  3. 通过 Driver 的 BuildCompilation 方法生成需要执行的命令

    image

  4. 当 Driver 构造完 Jobs 后,会通过 Driver 的 ExecuteCompilation 方法执行命令

    image

构建 Compilation

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

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

  1. 参数处理

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

    image

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

    image

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

    image

  3. 创建 Commpilation 持有参数

    image

  4. 通过 BuildInputs 函数获取输入文件

    image

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

    1
    
    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

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

    image

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

    image

  7. 随后再通过 BuildJobs 函数构建 Jobs

    image

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
graph TD
  subgraph clangDriver
    Driver
    Driver::BuildCompilation
    Driver::ParseArgStrings
    loadConfigFile
    computeTargetTriple
    getToolChain
    Compilation
    Driver::BuildInputs
    BuildUniversalActions
    BuildJobs

    Driver::ExecuteCompilation
  end

  subgraph clang
    CreateAndPopulateDiagOpts
  end

  subgraph clangFrontend
    clang::ParseDiagnosticArgs
  end

  subgraph clangBasic
    DiagnosticsEngine
  end

  subgraph Darwin
   MachO::LookupTypeForExtension
  end

  main--1.1 创建诊断-->CreateAndPopulateDiagOpts-->clang::ParseDiagnosticArgs-->DiagnosticsEngine

  main--1.2 创建 Driver-->Driver
  main--2.0 创建 Compilation-->Driver::BuildCompilation--2.1 参数解析-->Driver::ParseArgStrings
  Driver::BuildCompilation--2.2 配置文件解析-->loadConfigFile

  Driver::BuildCompilation--2.3 计算 Triple -->computeTargetTriple
  Driver::BuildCompilation--2.4 获取 toolchain-->getToolChain
  Driver::BuildCompilation--2.5 创建Compilation-->Compilation
  Driver::BuildCompilation--2.6 计算需要处理的源码文件列表-->Driver::BuildInputs--2.6.1 遍历参数-->for-Args--"2.6.2 筛选 Option::InputClass 类型参数,并根据源码文件扩展名获取产出类型"-->MachO::LookupTypeForExtension
  Driver::BuildCompilation--2.7 创建 jobAction-->BuildUniversalActions
  Driver::BuildCompilation--2.8 创建 job-->BuildJobs

  main--3.0 执行任务-->Driver::ExecuteCompilation

本文总结

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

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

相关推荐

  • clang 源码导读(1): clang 导读
  • clang 源码导读(3): clang driver 参数解析
  • clang 源码导读(4): clang driver 构建 Actions
  • clang 源码导读(5): clang driver 构建 Jobs
  • clang 源码导读(6): clang driver 执行命令
#clang# #clang driver#
clang 源码导读(1): clang 导读
clang 源码导读(3): clang driver 参数解析
  • 文章目录
  • 站点概览
酷酷的哀殿

酷酷的哀殿

单身狗

74 日志
83 标签
    • 前言
    • clang driver 流程简介
    • clang driver 源码概览
    • 构建 Compilation
    • 本文总结
© 2021 酷酷的哀殿 京ICP备18052541号-2
Powered by - Hugo v0.80.0
Theme by - NexT
0%