如何将Clang置于C ++模式?

时间:2016-07-13 15:55:15

标签: c++ clang

我正在使用Clang进行AST变换器。它应该将文件名作为输入,对该文件中的代码执行一些转换,并返回转换后的代码。它基于a helpful example from Eli Bendersky

以下是代码:

std::string transform(std::string fileName) {

  // CompilerInstance will hold the instance of the Clang compiler for us,
  // managing the various objects needed to run the compiler.
  CompilerInstance compilerInstance;

  compilerInstance.createDiagnostics();

  auto& langOpts = compilerInstance.getLangOpts();
  langOpts.CPlusPlus = true;

  // Initialize target info with the default triple for our platform.
  auto TO = std::make_shared<TargetOptions>();
  TO->Triple = llvm::sys::getDefaultTargetTriple();
  TargetInfo* targetInfo =
      TargetInfo::CreateTargetInfo(compilerInstance.getDiagnostics(), TO);
  compilerInstance.setTarget(targetInfo);

  compilerInstance.createFileManager();
  auto& fileManager = compilerInstance.getFileManager();

  compilerInstance.createSourceManager(fileManager);
  auto& sourceManager = compilerInstance.getSourceManager();

  compilerInstance.createPreprocessor(TU_Module);
  compilerInstance.createASTContext();

  // A Rewriter helps us manage the code rewriting task.
  auto rewriter = clang::Rewriter(sourceManager, compilerInstance.getLangOpts());

  // Set the main file handled by the source manager to the input file.
  const FileEntry* inputFile = fileManager.getFile(fileName);
  sourceManager.setMainFileID(
      sourceManager.createFileID(inputFile, SourceLocation(), SrcMgr::C_User));
  compilerInstance.getDiagnosticClient().BeginSourceFile(
      compilerInstance.getLangOpts(), &compilerInstance.getPreprocessor());

  // Create an AST consumer instance which is going to get called by
  // ParseAST.
  MyASTConsumer consumer(rewriter);

  // Parse the file to AST, registering our consumer as the AST consumer.
  clang::ParseAST(
    compilerInstance.getPreprocessor(), 
    &consumer, 
    compilerInstance.getASTContext());

  // At this point the rewriter's buffer should be full with the rewritten
  // file contents.
  const RewriteBuffer* buffer = rewriter.getRewriteBufferFor(sourceManager.getMainFileID());

  return std::string(buffer->begin(), buffer->end());
}

以下是我的输入程序negate.cpp

bool negate(bool b) {
    if (b) {
        return false;
    } else {
        return true;
    }
}

当我对此代码运行transform时,出现以下错误:

negate.cpp:1:1: error: unknown type name 'bool'
bool negate(bool b) {
^

这告诉我它在C模式下工作,而不是C ++模式。为了确认,我将bool替换为inttrue替换为1,将false替换为0

int negate(int b) {
    if (b) {
        return 0;
    } else {
        return 1;
    }
}

这很有用,所以我的问题是:

如何将Clang CompilerInstance置于C ++模式?

更新:

我尝试更改调用,但没有运气:

  auto& langOpts = compilerInstance.getLangOpts();
  langOpts.CPlusPlus = true;
  langOpts.CPlusPlus11 = true;

  auto* compilerInvocation = new CompilerInvocation();

  compilerInvocation->setLangDefaults(
    langOpts, 
    clang::InputKind::IK_CXX, 
    LangStandard::lang_gnu11);

1 个答案:

答案 0 :(得分:4)

在执行编译器之前,您必须使用CompilerInvocation / getInvocation()方法检查/设置setInvocation()结构。此结构定义语言选项(调用约定,垃圾收集,...),语言类型(C,CXX,Asm,ObjC,...),目标三元组,预处理器选项和语言标准。它使用方法setLangDefaults()进行设置。

这是InputKind类,它包含您要解析的语言。

如文档中所述,setLangDefaults() API

  

设置一些仅依赖于输入类型的属性

通过检查源代码,您可以看到以下构造函数调用层次结构:

  • CompilerInstance()
  • CompilerInvocation()
  • CompilerInvocationBase()
  • LangOptions()

LangOptions()构造函数中,您可以看到没有设置特定/默认语言(LangOptions.def)。因此需要通过setLangDefaults()特定的API。

你应该这样:

std::string transform(std::string fileName) {

  CompilerInstance compilerInstance;
  compilerInstance.createDiagnostics();

  CompilerInvocation & invocation = compilerInstance.getInvocation();

  // Initialize target info with the default triple for our platform.
  auto TO = std::make_shared<TargetOptions>();
  TO->Triple = llvm::sys::getDefaultTargetTriple();
  TargetInfo* targetInfo =
      TargetInfo::CreateTargetInfo(compilerInstance.getDiagnostics(), TO);
  compilerInstance.setTarget(targetInfo);

  compilerInstance.createFileManager();
  auto& fileManager = compilerInstance.getFileManager();

  compilerInstance.createSourceManager(fileManager);
  auto& sourceManager = compilerInstance.getSourceManager();

  LangOptions langOpts; 
  langOpts.GNUMode = 1;  
  langOpts.CXXExceptions = 1;  
  langOpts.RTTI = 1;  
  langOpts.Bool = 1;   // <-- Note the Bool option here !
  langOpts.CPlusPlus = 1;  
  PreprocessorOptions &PPOpts = compilerInstance.getPreprocessorOpts();

  invocation.setLangDefaults(langOpts, 
                             clang::IK_CXX,
                             TO->Triple, 
                             PPOpts,
                             clang::LangStandard::lang_cxx0x); 


  compilerInstance.createPreprocessor(TU_Module);
  compilerInstance.createASTContext();

  // A Rewriter helps us manage the code rewriting task.
  auto rewriter = clang::Rewriter(sourceManager, compilerInstance.getLangOpts());

  // Set the main file handled by the source manager to the input file.
  const FileEntry* inputFile = fileManager.getFile(fileName);
  sourceManager.setMainFileID(
      sourceManager.createFileID(inputFile, SourceLocation(), SrcMgr::C_User));
  compilerInstance.getDiagnosticClient().BeginSourceFile(
      compilerInstance.getLangOpts(), &compilerInstance.getPreprocessor());

  // Create an AST consumer instance which is going to get called by
  // ParseAST.
  MyASTConsumer consumer(rewriter);

  // Parse the file to AST, registering our consumer as the AST consumer.
  clang::ParseAST(
    compilerInstance.getPreprocessor(), 
    &consumer, 
    compilerInstance.getASTContext());

  // At this point the rewriter's buffer should be full with the rewritten
  // file contents.
  const RewriteBuffer* buffer = rewriter.getRewriteBufferFor(sourceManager.getMainFileID());

  return std::string(buffer->begin(), buffer->end());
}

铿锵教程CIRewriter.cpp中的参考,似乎也有点过时。