问题
I'm writing a little tool with llvm to parse C and C++ code, but I can't seem to get it to successfully parse C++ at all. I'm probably missing something obvious.
This is what I have so far:
#include <iostream>
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/LangStandard.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/DirectoryLookup.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Parse/ParseAST.h"
class MyASTConsumer : public clang::ASTConsumer {
public:
bool HandleTopLevelDecl(clang::DeclGroupRef d);
virtual ~MyASTConsumer() { }
};
bool MyASTConsumer::HandleTopLevelDecl(clang::DeclGroupRef d)
{
for(auto ii = d.begin(); ii != d.end(); ii++)
{
printf("decl type: %s\n", (*ii)->getDeclKindName());
auto namedDecl = llvm::dyn_cast<clang::NamedDecl>(*ii);
if(namedDecl)
{
printf("name: %s\n", namedDecl->getName().data());
}
}
return true;
}
int main(int, char **argv)
{
using clang::CompilerInstance;
using clang::TargetOptions;
using clang::TargetInfo;
using clang::FileEntry;
using clang::DiagnosticOptions;
using clang::TextDiagnosticPrinter;
using clang::SrcMgr::CharacteristicKind;
using clang::StringRef;
using clang::DirectoryLookup;
using llvm::MemoryBuffer;
using clang::LangOptions;
using clang::FrontendOptions;
using clang::LangStandard;
using clang::CompilerInvocation;
using clang::InitializePreprocessor;
using clang::Preprocessor;
using clang::PreprocessorOptions;
using clang::HeaderSearch;
using clang::HeaderSearchOptions;
CompilerInstance ci;
DiagnosticOptions diagnosticOptions;
ci.createDiagnostics();
CompilerInvocation *invocation = new CompilerInvocation;
LangOptions &langOpts = ci.getLangOpts();
langOpts.RTTI = 1;
langOpts.Bool = 1;
langOpts.CPlusPlus11 = 1;
langOpts.GNUKeywords = 1;
langOpts.CXXExceptions = 1;
langOpts.POSIXThreads = 1;
langOpts.SpellChecking = 1;
invocation->setLangDefaults(langOpts, clang::IK_CXX, LangStandard::lang_gnucxx11);
ci.setInvocation(invocation);
llvm::IntrusiveRefCntPtr<TargetOptions> pto( new TargetOptions() );
pto->Triple = llvm::sys::getDefaultTargetTriple();
llvm::IntrusiveRefCntPtr<TargetInfo> pti(TargetInfo::CreateTargetInfo(ci.getDiagnostics(), pto.getPtr()));
ci.setTarget(pti.getPtr());
ci.createFileManager();
auto &fileManager = ci.getFileManager();
ci.createSourceManager(fileManager);
llvm::IntrusiveRefCntPtr<HeaderSearchOptions> headerSearchOpts( new HeaderSearchOptions() );
ci.createPreprocessor();
auto &pp = ci.getPreprocessor();
pp.setPredefines(builtinMacros);
HeaderSearch &headerSearch = pp.getHeaderSearchInfo();
for(auto &inc: builtinIncludePaths)
{
auto dirEntry = fileManager.getDirectory(StringRef(inc), true);
DirectoryLookup dirLookup(dirEntry, CharacteristicKind::C_System, false);
headerSearch.AddSearchPath (dirLookup, true);
}
MyASTConsumer *astConsumer = new MyASTConsumer();
ci.setASTConsumer(astConsumer);
ci.createASTContext();
const FileEntry *pFile = fileManager.getFile(argv[1]);
auto &sourceManager = ci.getSourceManager();
sourceManager.createMainFileID(pFile);
ci.getDiagnosticClient().BeginSourceFile(
ci.getLangOpts(),
&pp
);
clang::ParseAST(pp, astConsumer, ci.getASTContext());
ci.getDiagnosticClient().EndSourceFile();
return 0;
}
It does parse C just fine, but it errors out on the namespace
keyword and extern "C" {
blocks. So far I'm stumped. If anyone has a clue, something I'm missing, please share.
回答1:
I believe I figured out the problem. You should always call setInvocation
on the compiler instance before calling a lot of the methods on the compiler instance, as it actually just proxies to the invocation.
I moved the setInvocation
call to right after the CompilerInvocation object is created, and things now work.
来源:https://stackoverflow.com/questions/23327997/failing-to-parse-c-using-llvm-and-clang