在clang中的CompilerInstance上执行多个FrontendAction

时间:2016-11-21 10:18:03

标签: c++ c++11 clang llvm-clang llvm-c++-api

我有一个大约100行的cpp文件,其中包含以下内容。

#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h>
#include <iostream>

// The filename that will be processed (twice).
static const char* FILENAME = "simple.cpp";

// System header locations, you may need to
// adjust these.
static const char* SYSTEM_HEADERS[] =
{
    "/usr/include/c++/5.4.0",
    "/usr/include/x86_64-linux-gnu/c++/5.4.0",
    "/usr/include/c++/5.4.0/backward",
    "/usr/local/lib/clang/4.0.0/include",
    "/usr/include/x86_64-linux-gnu",
    "/usr/include"
};

// Location for builtin headers. You may need to
// adjust this.
static const char* RESOURCE_DIR = "/usr/local/lib/clang/4.0.0";

// Uncomment this to see header search paths.
// #define PRINT_HEADER_SEARCH_PATHS

// Constructs a CompilerInvocation
// that must be fed to a CompilerInstance.
clang::CompilerInvocation* makeInvocation();

// Executes a single SyntaxOnlyAction on
// the given CompilerInstance.
void secondCallThisFunctionFails(clang::CompilerInstance& instance);

int main()
{
    using namespace clang;

    CompilerInstance instance;

    instance.createDiagnostics();

    instance.setInvocation(makeInvocation());
    instance.getFrontendOpts().Inputs.emplace_back
    (
        FILENAME, 
        FrontendOptions::getInputKindForExtension(FILENAME)
    );

    // First call is OK.
    secondCallThisFunctionFails(instance);

    // Second call results in assertion failures.
    secondCallThisFunctionFails(instance);

    return 0;
}

clang::CompilerInvocation* makeInvocation()
{
    using namespace clang;
    auto invocation = new CompilerInvocation();

    invocation->TargetOpts->Triple = llvm::sys::getDefaultTargetTriple();
    invocation->setLangDefaults(
        *invocation->getLangOpts(), 
        IK_CXX, 
        llvm::Triple(invocation->TargetOpts->Triple), 
        invocation->getPreprocessorOpts(), 
        LangStandard::lang_cxx11);

    auto& headerSearchOpts = invocation->getHeaderSearchOpts();

    #ifdef PRINT_HEADER_SEARCH_PATHS
        headerSearchOpts.Verbose = true;
    #else
        headerSearchOpts.Verbose = false;
    #endif

    headerSearchOpts.UseBuiltinIncludes = true;
    headerSearchOpts.UseStandardSystemIncludes = true;
    headerSearchOpts.UseStandardCXXIncludes = true;
    headerSearchOpts.ResourceDir = RESOURCE_DIR;

    for (const auto sytemHeader : SYSTEM_HEADERS)
    {
        headerSearchOpts.AddPath(sytemHeader, frontend::System, false, false);
    }

    return invocation;
}

void secondCallThisFunctionFails(clang::CompilerInstance& instance)
{
    using namespace clang;
    SyntaxOnlyAction action;
    if (instance.ExecuteAction(action))
    {
        std::cout << "Action succeeded.\n";
    }
    else
    {
        std::cout << "Action failed.\n";
    }
}

如您所见,main函数非常简单,最后调用函数两次。第二次调用这个函数时,我得到一个断言失败,让我感到惊讶。

文件simple.cpp的内容是

// test wether we actually configured C++11 or greater
#include <thread>
int main() { return 0; }

我的机器上的这个程序的输出是:

Action succeeded.
clangapitest: ../tools/clang/lib/Basic/SourceManager.cpp:819: clang::FileID clang::SourceManager::getFileIDLoaded(unsigned int) const: Assertion `0 && "Invalid SLocOffset or bad function choice"' failed.
Aborted (core dumped)

问题是:我想在CompilerInstance上执行多个操作。为了不让断言失败,我需要重置什么状态?

要自己构建它,你必须链接一些静态clang和llvm库。如果感兴趣的话,这里是CMakeLists.txt文件:

add_clang_executable(clangapitest clangapitest.cpp)
target_link_libraries(clangapitest clangFrontend)

我制作了一个新目录path/to/llvm/tools/clang/tools/clangapitest并调整了path/to/llvm/tools/clang/tools/CMakeLists.txt中的CMakeLists.txt文件,以增加一行add_subdirectory(clangapitest)

1 个答案:

答案 0 :(得分:1)

好吧,我明白了。在 CompoloInstance :: ExecuteAction的doxygen文档中,它声明了一个调用对象和诊断对象应该已经初始化,没有其他状态(因此没有源或文件管理器)。因此,以下工作:

&#xA;&#xA;
  SyntaxOnlyAction操作;&#xA; instance.setSourceManager(nullptr);&#xA; instance.createDiagnostics();&#xA ; if(instance.ExecuteAction(action))&#xA; {&#xA; std :: cout&lt;&lt; “行动成功。\ n”;&#xA;}&#xA;其他&#xA; {&#xA; std :: cout&lt;&lt; “行动失败。\ n”;&#xA;}&#xA;  
&#xA;