私は以下の内容の約100行の単一のcppファイルを持っています。コンパイル時に複数のFrontendActionを実行する場合
#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関数は非常に簡単で、最後に関数を2回呼び出します。この関数が呼び出される2回目に、私はアサーションの失敗を得て、私を驚かせます。
ファイル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)
問題がある:私は上の複数のアクションを実行したいですコンパイラのインスタンス。アサーションの失敗を起こさないためには、どのような状態をリセットする必要がありますか?
自分で構築するには、静的なclangとllvmライブラリにリンクする必要があります。興味があればここでCMakeLists.txtファイルがあります:
add_clang_executable(clangapitest clangapitest.cpp)
target_link_libraries(clangapitest clangFrontend)
私は新しいディレクトリpath/to/llvm/tools/clang/tools/clangapitest
を作り、余分なラインadd_subdirectory(clangapitest)
を持っているpath/to/llvm/tools/clang/tools/CMakeLists.txt
にCMakeLists.txtファイルを調整しました。