参考:

Create a working compiler with the LLVM framework, Part 2

How to parse C programs with Clang: A tutorial

[Clang,libClang] exercise1 : FileManager

注意:此篇笔记各类之构造函数源码来自 llvm/clang doxygen 5.0.0 svn,与现行版本(此时为 3.9.1)有一定出入,其中主要是现行版本有些参数是 llvm::IntrusiveRefCntPtr(llvm 实现的 smart pointer)而不是 std::shared_ptr

一、Preprocessor 的构造函数

前端由许多部分组成,其中第一部分通常是一个 lexer,clang 中 Preprocessor 类是 lexer 的 main interface。出于性能考虑,clang 没有独立的预处理器程序,而是在 lexing 的过程中进行预处理。

Preprocessor 的构造函数如下所示:

 1 Preprocessor::Preprocessor(
2 std::shared_ptr<PreprocessorOptions> PPOpts, // constructor: PreprocessorOptions()
3 DiagnosticsEngine& diags,
4 LangOptions& opts, // constructor: LangOptions()
5 // Keep track of the various options that can be enabled,
6 // which controls the dialect of C or C++ that is accepted
7 SourceManager& SM,
8 HeaderSearch& Headers,
9 ModuleLoader& TheModuleLoader,
10 IdentifierInfoLookup* IILookup = nullptr,
11 bool OwnsHeaderSearch = false,
12 TranslationUnitKind TUKind = TU_Complete
13 )

Preprocessor 的构造函数

DiagnosticsEngine : 用来给用户报告错误和警告信息。构造函数如下:

1 DiagnosticsEngine::DiagnosticsEngine(
2 IntrusiveRefCntPtr<DiagnosticIDs> Diags, // constructor: DiagnosticIDs()
3 // used for handling and querying diagnostic IDs
4 DiagnosticOptions* DiagOpts, // constructor: DiagnosticOptions()
5 // Options for controlling the compiler diagnostics engine
6 DiagnosticConsumer* client = nullptr,
7 bool ShouldOwnClient = true
8 )

DiagnosticsEngine 的构造函数

其中 DiagnosticConsumer 是一个抽象接口,由前端的 clients 实现,用来 formats and prints fully processed diagnostics。clang 内置一个 TextDiagnosticsConsumer 类,将错误和警告信息写到 console 上,clang binary 用的 DiagnosticConsumer 也是这个类。TextDiagnosticsConsumer 的构造函数如下:

1 TextDiagnosticPrinter::TextDiagnosticPrinter(
2 raw_ostream& os, // llvm::outs() returns a reference to a raw_ostream for standard output
3 DiagnosticOptions* diags,
4 bool OwnsOutputStream = false // within destructor:(OS is the member, initialized with os)
5 // if (OwnsOutputStream) delete &OS
6 )

TextDiagnosticPrinter 的构造函数

SourceManager :handles loading and caching of source files into memory。构造函数如下:

1 SourceManager::SourceManager(vim
2 DiagnosticsEngine& Diag,
3 FileManager& FileMgr,
4 bool UserFilesAreVolatile = false
5 )

SourceManager 的构造函数

FileManager :实现了对文件系统查找、文件系统缓存、目录查找管理的支持。构造函数如下:

1 FileManager::FileManager(
2 const FileSystemOptions& FileSystemOpts, // use default constructor
3 IntrusiveRefCntPtr<vfs::FileSystem> FS = nullptr
4 )

FileManager 的构造函数

HeaderSearch :Encapsulates the information needed to find the file referenced by a #include or #include_next, (sub-)framework lookup, etc。构造函数如下:

1 HeaderSearch::HeaderSearch(
2 std::shared_ptr<HeaderSearchOptions> HSOpts, // constructor: HeaderSearchOptions::HeaderSearchOptions(StringRef _Sysroot = "/")
3 SourceManager& SourceMgr,
4 DiagnosticsEngine& Diags,
5 const LangOptions& LangOpts,
6 const TargetInfo* Target
7 )

HeaderSearch 的构造函数

TargetInfo :Exposes information about the current target。 其构造函数为 protected,因此需要调用工厂函数 static TargetInfo* TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr<TargetOptions>& Opts) ,其中 TargetOptions 类包含 target 的相关信息,如 CPU、ABI 等。类中有一个属性 Triple 用以定义 target 的架构。Triple 是一个 string,形如 i386-apple-darwin,通过 llvm::sys::getDefaultTargetTriple() 可以获得编译 llvm 的机器的 host triple。

ModuleLoader:描述了 module loader 的抽象接口。Module loader 负责解析一个 module name(如“std”),将其与实际的 module file 联系起来,并加载该 module。CompilerInstance 便是一个实现了该接口的 module loader。

二、通过 CompilerInstance 创建 Preprocessor

比起手写 Preprocessor,CompilerInstance 更加实用一些。CompilerInstance 主要有两个作用:(1)管理运行编译器所必须的各个对象,如 preprocessor、target information、AST context 等;(2)提供创建和操作常用 Clang 对象的有用方法。下面是其类定义的一部分:

 1 class CompilerInstance : public ModuleLoader {
2 /// The options used in this compiler instance.
3 std::shared_ptr<CompilerInvocation> Invocation;
4 /// The diagnostics engine instance.
5 IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
6 /// The target being compiled for.
7 IntrusiveRefCntPtr<TargetInfo> Target;
8 /// The file manager.
9 IntrusiveRefCntPtr<FileManager> FileMgr;
10 /// The source manager.
11 IntrusiveRefCntPtr<SourceManager> SourceMgr;
12 /// The preprocessor.
13 std::shared_ptr<Preprocessor> PP;
14 /// The AST context.
15 IntrusiveRefCntPtr<ASTContext> Context;
16 /// An optional sema source that will be attached to sema.
17 IntrusiveRefCntPtr<ExternalSemaSource> ExternalSemaSrc;
18 /// The AST consumer.
19 std::unique_ptr<ASTConsumer> Consumer;
20 /// The semantic analysis object.
21 std::unique_ptr<Sema> TheSema;
22 /// ...
23 };

CompilerInstance 类定义的一部分

下列代码通过 CompilerInstance 来创建 Preprocessor:

 1 #include <memory>
2
3 #include "clang/Basic/LangOptions.h"
4 #include "clang/Basic/TargetInfo.h"
5 #include "clang/Frontend/CompilerInstance.h"
6
7 int main() {
8 clang::CompilerInstance ci;
9
10 ci.createDiagnostics();
11
12 std::shared_ptr<clang::TargetOptions> pTargetOptions =
13 std::make_shared<clang::TargetOptions>();
14 pTargetOptions->Triple = llvm::sys::getDefaultTargetTriple();
15 clang::TargetInfo *pTargetInfo =
16 clang::TargetInfo::CreateTargetInfo(ci.getDiagnostics(), pTargetOptions);
17 ci.setTarget(pTargetInfo);
18
19 ci.createFileManager();
20 ci.createSourceManager(ci.getFileManager());
21 ci.createPreprocessor(clang::TU_Complete);
22
23 return 0;
24 }

Use CompilerInstance to construct Preprocessor

首先创建 DiagnosticsEngine(通过 createDiagnostics()),然后创建并设置 TargetInfo,然后依次创建 FileManager(通过 createFileManager()),SourceManager(通过 createSourceManager (FileManager &FileMgr)),最后创建 Preprocessor(createPreprocessor(TranslationUnitKind))。

三、FileManager 与 SourceManager

FileManager:

p, li { white-space: pre-wrap }

Clang Preprocessor 类的创建的更多相关文章

  1. C# 根据类名称创建类示例

    //获得类所在的程序集名称(此处我选择当前程序集) string bllName = System.IO.Path.GetFileNameWithoutExtension(System.Reflect ...

  2. php简单实用的操作文件工具类(创建、移动、复制、删除)

    php简单实用好用的文件及文件夹复制函数和工具类(创建.移动.复制.删除) function recurse_copy($src,$dst) {  // 原目录,复制到的目录 $dir = opend ...

  3. 李洪强iOS开发之OC[013] -类的创建的练习

    // //  main.m //  12 - 类的创建练习 // //  Created by vic fan on 16/7/9. //  Copyright © 2016年 李洪强. All ri ...

  4. C++:类的创建

    类的创建 #include<iostream> #include<cmath> using namespace std; class Complex //声明一个名为Compl ...

  5. 2--OC -- 类的创建与实例化

    2.OC -- 类的创建与实例化   一.OC类的简述 1.OC类分为2个文件:.h文件用于类的声明,.m文件用于实现.h的函数: 2.类是声明使用关键字:@interface.@end : 3.类是 ...

  6. JAVA类的创建: 创建JAVA的类 ,JAVA的字段,JAVA类的方法

    1. 创建Java的类 如果说Java的一切都是对象,那么类型就是决定了某一类对象的外观与行为.可是类型的关键字不是type,而是class,创建一个新的类型要用下面的代码: 1 2 3 class ...

  7. python 通过元类控制类的创建

    一.python中如何创建类? 1. 直接定义类 class A: a = 'a' 2. 通过type对象创建 在python中一切都是对象 在上面这张图中,A是我们平常在python中写的类,它可以 ...

  8. Day 5-7 exec 和元类的创建.

    exec方法 元类 exec(str_command,globals,locals)参数1:字符串形式的命令参数2:全局作用域(字典形式). 如果不指定,默认globals参数3:局部作用(字典形式) ...

  9. Egret 类的创建和继承--TypeScript

    class test extends egret.DisplayObjectContainer { /** * 类的创建 */ //属性 name: string; age: number; ts: ...

  10. 快速创建SpringBoot2.x应用之工具类自动创建web应用、SpringBoot2.x的依赖默认Maven版本

    快速创建SpringBoot2.x应用之工具类自动创建web应用简介:使用构建工具自动生成项目基本架构 1.工具自动创建:http://start.spring.io/ 2.访问地址:http://l ...

随机推荐

  1. NC23482 小A的最短路

    题目链接 题目 题目描述 小A这次来到一个景区去旅游,景区里面有N个景点,景点之间有N-1条路径.小A从当前的一个景点移动到下一个景点需要消耗一点的体力值.但是景区里面有两个景点比较特殊,它们之间是可 ...

  2. ELK查询和汇总

    查询表明细: ELK的KQL样例,显示时间请选择最近15天: 样例1:查询ol_lc 表增删改查,不是jy2_rw的账号明细 KQL:(ol_lc or oc.ol_lc) and (select o ...

  3. mysqlGTID主从同步出现1236错误问题

    从主库xtrabackup备份,配置好gtid复制,从主库的从库复制.一直报错误 Last_IO_Error: Got fatal error 1236 from master when readin ...

  4. Oracle高级队列介绍

    原始链接:http://www.oracle-developer.net/display.php?id=411 oracle高级队列介绍 高级队列Advanced Queuing(AQ)在oracle ...

  5. 使用winsw将jar包注册成windows服务

    使用winsw将jar包注册成windows服务 注:exe文件作用:使用winsw将jar包注册成windows服务(下载地址https://github.com/winsw/winsw/relea ...

  6. WSL2镜像文件压缩

    WSL2的镜像文件(*.vhdx)支持自动扩容,但是一般不会自动缩容.一旦某次存放过大文件以后,即使后续删除,镜像文件体积仍然不会缩小,导致大量磁盘空间浪费.因此,可以定期对镜像文件进行手动压缩. 镜 ...

  7. 【LeetCode二叉树#03】翻转二叉树的几种方法

    翻转二叉树 力扣题目链接(opens new window) 翻转一棵二叉树. 这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树 ...

  8. [Python] 协程学习过程

    开始 ​ 之前一直在做那个rProxy的项目,后来发现,服务端不用协程或者异步编程这样的手段是不行的,最主要的问题就是对于每个http请求都对应一个线程,这个开销非常大.对于一个网页而言,四五十个ht ...

  9. 影刀rpa第一个学习项目开发所得

    1.我要在某个位置新增一条指令,但是可能没有选择好的原因,这条指令被添加到指令的最后面了,我的指令行数有几十行,然后我就要把这条指令拖动到上一屏我指定的位置上,但当我拖动指令到了当前屏最上方时,发现编 ...

  10. 专访实在智能孙林君:颠覆传统RPA的实在IPA模式如何做到真正人人可用?

      王吉伟对话实在智能孙林君:颠覆传统引领RPA行业的实在IPA模式是如何炼成的? 王吉伟对话实在智能孙林君:为什么第一款颠覆行业的RPA诞生在实在智能? 专访实在智能孙林君:打造出真正人人可用的实在 ...