2016-11-21 2 views
0

Ich habe eine einzelne cpp-Datei von etwa 100 Zeilen mit dem folgenden Inhalt.Ausführen von mehr als einer FrontendAction auf einer CompilerInstance in

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

Wie Sie sehen können, ist die Hauptfunktion ziemlich einfach und ruft eine Funktion zweimal am Ende auf. Beim zweiten Aufruf dieser Funktion erhalte ich einen Assertionsfehler, der mich überrascht. simple.cpp

Der Inhalt der Datei ist

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

Die Ausgabe dieses Programms auf meinem Rechner ist:

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) 

Das Problem ist: ich mehr als eine Aktion auf ein ausführen möchten CompilerInstanz. Welchen Status muss ich zurücksetzen, um keine Assertionsfehler zu erhalten?

Um es selbst zu erstellen, müssen Sie mit einigen statischen clang und llvm-Bibliotheken verknüpfen. Hier ist die CMakeLists.txt Datei, wenn interessiert:

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

ich ein neues Verzeichnis path/to/llvm/tools/clang/tools/clangapitest gemacht und angepasst, um die CMakeLists.txt Datei in path/to/llvm/tools/clang/tools/CMakeLists.txtadd_subdirectory(clangapitest) eine zusätzliche Zeile zu haben.

Antwort

0

Nun, ich habe es herausgefunden. In der doxygen documentation of CompilerInstance::ExecuteAction gibt es an, dass ein Aufrufobjekt und ein Diagnoseobjekt initialisiert worden sein sollten und kein anderer Zustand (daher keine Quelle und kein Dateimanager). So funktioniert das folgende:

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