zoukankan      html  css  js  c++  java
  • Clang Preprocessor 类的创建

    参考:

    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:

  • 相关阅读:
    Websphere 系列的https证书的配置说明
    Linux下运行windows程序
    Linux常见命令(三)
    使用Java语言开发微信公众平台(八)——自定义菜单功能
    Linux常见命令(二)
    微信小程序,前端大梦想(八)
    微信小程序,前端大梦想(七)
    使用Java语言开发微信公众平台(七)——音乐消息的回复
    微信小程序,前端大梦想(六)
    微信小程序,前端大梦想(五)
  • 原文地址:https://www.cnblogs.com/jerrywossion/p/6429855.html
Copyright © 2011-2022 走看看