酷酷的哀殿


  • 首页

  • 技术

  • 笔记

  • 杂记

  • Todo

  • 关于

  • 搜索
close

clang 源码导读(7): clang 编译器前端入门

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

[toc]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
graph TD


ExecuteCC1Tool-->cc1_main-->CompilerInstance-->CompilerInvocation--1. CompilerInvocation 初始化流程-->父类CompilerInvocationBase初始化--1.1父类实例属性默认初始化-->别名1.2["1.2  LangOpts, TargetOpts, DiagnosticOpts, HeaderSearchOpts, PreprocessorOpts"]

CompilerInvocation--1.3属性默认初始化-->CodeGenOpts



cc1_main--2.参数解析-->clang::CompilerInvocation::CreateFromArgs--2.1-->llvm::opt::OptTable::ParseArgs-->InputArgList-->ArgList

clang::CompilerInvocation::CreateFromArgs--2.2-->CompilerInvocation::parseSimpleArgs


cc1_main--3.编译流程开始-->
ExecuteCompilerInvocation-->CompilerInstance::ExecuteAction-->FrontendAction::BeginSourceFile

FrontendAction::BeginSourceFile--3.1-->CompilerInstance::createPreprocessor-->Preprocessor初始化
FrontendAction::BeginSourceFile--3.2-->FrontendAction::CreateWrappedASTConsumer-->CodeGenAction::CreateASTConsumer-->BackendConsumer-->CreateLLVMCodeGen-->CodeGeneratorImpl-->CodeGenOpts
CompilerInstance::ExecuteAction--3.4-->FrontendAction::Execute-->ASTFrontendAction::ExecuteAction-->ParseAST--3.5-->Preprocessor::EnterMainSourceFile-->Preprocessor::EnterSourceFile-->Lexer::Lexer
ParseAST--3.6-->Parser::Initialize-->Parser::ConsumeToken-->Preprocessor::Lex

进行后续的分享前,我们先回忆一下编译器前端的功能

从 main.m 到 a.out 的完整的编译流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
graph LR
  subgraph 示例
   真实文件:::file
   流程:::process
  end

main.m:::file-->词法分析&预处理:::process-->语法分析&语义分析:::process-->CodeGen:::process-->main.ll[main.ll]:::file

classDef process fill:#f96;
classDef file fill:#f9f,stroke:#333,stroke-width:4px

前言

clang 编译器前端负责从源码生成中间码,它通常由 clang 模块驱动,并通常包含以下几个步骤:

image

本文会先对 clang 编译器前端的流程进行简单的介绍,并会在后面的系列文章依次分享下面的几个库:

  1. clangLex :负责词法分析和预处理,处理宏、令牌和 pragma 构造
  2. clangAST:负责提供了构建、操作和遍历 AST 相关的功能
  3. clangParse:负责从词法分析的结果进行处理
  4. clangSema:负责语义分析
  5. clangCodeGen:负责生成 LLVM IR 代码

clang

clang 模块只包含 5 个可编译文件,大部分的功能都是依赖其它模块提供

clang 库 的 driver.cpp 是整个程序的入口。

image

clang 模块主要负责以下任务:

  1. main 函数检测输入的参数是否包含以 -cc1 开头的参数

    image

  2. 通过 ExecuteCC1Tool 函数分发不同的 cc1类型。

    clang 目前支持 3 种类型

    1. -cc1 : LLVM ‘Clang’ Compiler

    2. -cc1as : Clang Integrated Assembler

    3. -cc1gen-reproducer: Generate Libclang invocation reproducers

    image

  3. cc1_main 函数负责初始化 CompilerInstance、DiagnosticIDs,并调用 CreateFromArgs 函数构建 CompilerInvocation

    image

  4. CreateFromArgs 函数内部会非常多的函数对参数进行解析

    image

  5. 当-emit-obj 参数传入时,ParseFrontendArgs 函数会将 frontend::EmitObj赋值给 ProgramAction

    后面的 CreateFrontendBaseAction 函数会依赖依赖 ProgramAction

    image

    对 -emit-objc 不熟悉的朋友,可以看看 clang driver 系列文章

  6. 调用 clangFrontendTool 模块的 ExecuteCompilerInvocation 函数执行编译任务

    image

clangFrontendTool

clangFrontendTool 非常简单,目前只包含一个可编译文件 ExecuteCompilerInvocation.cpp

image

  1. ExecuteCompilerInvocation 会判断先是否存在 -h -v 等参数,如果存在,会执行对应的任务

    值得注意的是,这里会尝试加载 plugin

    image

  2. 经过一系列的判断后,才会通过 CreateFrontendAction 创建需要执行的编译器前端任务

    image

  3. CreateFrontendAction 会先调用 CreateFrontendBaseAction 创建 FrontendAction 的子类

    image

  4. CreateFrontendBaseAction 函数会因为前文提到的 EmitObj 参数创建 EmitObjAction 的实例

    image

  5. 任务创建完成后,会调用 clangFrontend 模块的 ExecuteAction 函数执行编译任务

    image

clangFrontend

clangFrontend 模块包含了很多重要的功能。

cc1_main 函数创建的 CompilerInstance 就是来自 clangFrontend

image

CompilerInstance 是 clangFrontend 中非常重要的一个类。它持有了诸如 preprocessor、Target、AST 等属性

image

CompilerInstance 执行过程

CompilerInstance::ExecuteAction 会通过 Inputs 获取输入文件,并依次调用以下方法:

  1. Act.BeginSourceFile()

  2. Act.Execute()

  3. Act.EndSourceFile()

image

Ac 就是之前提到的 FrontendAction 的子类 EmitObjAction

Act.BeginSourceFile()

  1. Act.BeginSourceFile() 函数会通过懒加载方式创建 FileManager 和 SourceManager

    image

    FileManager 负责和文件系统交互,文件缓存、目录查找等任务

    image

    SourceManager 负责查找并将文件缓存到内存

    image

  2. 通过 createPreprocessor 函数创建预处理器

    image

    预处理器 初始化时,会构建一个包含各个语言的关键字列表IdentifierTable Identifiers;,方便后续词法分析使用

    image

  3. 通过 createASTContext 创建 ASTContext

    image

    image

  4. 随后,会调用函数FrontendAction::CreateWrappedASTConsumer 创建 ASTConsumer

image

Act.Execute()

Act.Execute() 实际上是执行 EmitObjAction 继承自 FrontendAction 的 Execute 函数

FrontendAction:Execute 随后会调用 CodeGenAction::ExecuteAction 函数

image

CodeGenAction::ExecuteAction 函数会调用ASTFrontendAction::ExecuteAction

image

ASTFrontendAction::ExecuteAction 会调用 CompilerInstance的 createSema 函数创建 Sema

image

Sema 后续会用于语义分析

image

各项准备工作结束后,就会调用 clangParse 模块的 clang::ParseAST 构建 abstract syntax tree

image

总结

本文对 clang 编译器前端入门知识进行了简单介绍。

下一篇文章,我们会开始分享 ParseAst 的第一个主要流程:词法分析和 pragma 处理

相关推荐

  • clang 源码导读(1): clang 导读
  • clang 源码导读(2): clang driver 流程简介
  • clang 源码导读(3): clang driver 参数解析
  • clang 源码导读(4): clang driver 构建 Actions
  • clang 源码导读(5): clang driver 构建 Jobs
#clang# #clang driver#
clang 源码导读(6): clang driver 执行命令
clang 源码导读(8)- 词法分析和预处理
  • 文章目录
  • 站点概览
酷酷的哀殿

酷酷的哀殿

单身狗

74 日志
83 标签
    • 前言
    • clang
    • clangFrontendTool
    • clangFrontend
      • CompilerInstance 执行过程
      • Act.BeginSourceFile()
      • Act.Execute()
    • 总结
© 2021 酷酷的哀殿 京ICP备18052541号-2
Powered by - Hugo v0.80.0
Theme by - NexT
0%