2016-11-21 4 views
0

У меня есть один файл cpp около 100 строк со следующим содержимым.Выполнение нескольких FrontendAction на CompilerInstance в clang

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

Как вы можете видеть, основная функция довольно проста и вызывает функцию дважды в конце. Во второй раз, когда эта функция называется, я получаю отказ от утверждения, что меня удивляет.

Содержимое файла 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 и настроил файл CMakeLists.txt в path/to/llvm/tools/clang/tools/CMakeLists.txt иметь дополнительную линию add_subdirectory(clangapitest).

ответ

0

Ну, я понял. В doxygen documentation of CompilerInstance::ExecuteAction указано, что объект вызова и объект диагностики должны быть инициализированы, а другое состояние (следовательно, ни один источник, ни файловый менеджер). Таким образом, следующие работы:

SyntaxOnlyAction action; 
instance.setSourceManager(nullptr); 
instance.createDiagnostics(); 
if (instance.ExecuteAction(action)) 
{ 
    std::cout << "Action succeeded.\n"; 
} 
else 
{ 
    std::cout << "Action failed.\n"; 
}