无法使用llvm和clang解析C.

我正在用llvm编写一个小工具来解析C和C代码,但我似乎无法让它成功解析C语言.我可能错过了一些明显的东西.

这是我到目前为止:

#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;
}

它确实解析C很好,但它在namespace关键字和extern“C”{块上错误.到目前为止,我很难过.如果有人有线索,我缺少的东西,请分享.

解决方法:

我相信我弄明白了这个问题.在调用编译器实例上的许多方法之前,应始终在编译器实例上调用setInvocation,因为它实际上只是代理调用.

在创建CompilerInvocation对象后,我将setInvocation调用移到了右边,现在可以正常工作了.

上一篇:在另一台机器上运行从clang llvm编译的程序


下一篇:c – 如何使用LLVM为不同的目标体系结构编译程序?