我正在使用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
替换为int
,true
替换为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);
答案 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中的参考,似乎也有点过时。