なので今回は複数のh/cppを入力してみる。
cppをテキトーに追加してみる
ソースコードをメモリに展開するのはclang::SourceManagerである。しかしSourceManagerに(mainではない)ソースファイルを追加するであろうcreateFileID()は、インクルードパスのSourceLocationを要求する。createMainFileID()は要求しないのに。この違いは何かと思って、createMainFileID()を使わずに以下のようにファイルを追加してみる。
srcMgr.createFileID(fileMgr.getFile("D:\\develop\\Clang\\SampleProj\\Package1\\Super.cpp"), clang::SourceLocation(), clang::SrcMgr::C_User);
すると以下のようなエラーメッセージが出てしまう。
>fatal error: error opening file '<invalid loc>':
うーん、そうですか。ダメですか。でもcreateMainFileID()を複数回呼ぶのもダメですよね。
じゃあってことで、1つめのコードはcreateMainFileID()を、2つめ以降はcreateFileID()を使ってみる。
srcMgr.createMainFileID(fileMgr.getFile("D:\\develop\\Clang\\SampleProj\\Package1\\Super.cpp")); srcMgr.createFileID(fileMgr.getFile("D:\\develop\\Clang\\SampleProj\\Package2\\Sub.cpp"), clang::SourceLocation(), clang::SrcMgr::C_User);
実行すると、Sub.cppは解析結果に含まれない。
SourceLocationの生成を調べる
SourceLocationがデフォルト生成のままだとダメなのか、と思ってSourceLocationを調べると、- メンバ変数はunsigned ID1つだけ。
- コンストラクタは引数なし。
- IDを初期化できそうなメンバ関数はない。
これまで使ってきたクラスの中から生成しそうなやつをピックアップすると
- FileManager
- HeaderSearch
- SourceManager
- clang::SrcMgrのインナークラスであるFileInfoにgetIncludeLoc()というAPIがある。
- SourceManager自身にgetIncludeLoc()というAPIがある。
clang::FileID mainId = srcMgr.createMainFileID(fileMgr.getFile("D:\\develop\\Clang\\SampleProj\\Package1\\Super.cpp")); srcMgr.createFileID(fileMgr.getFile("D:\\develop\\Clang\\SampleProj\\Package2\\Sub.cpp"), srcMgr.getIncludeLoc(mainId), clang::SrcMgr::C_User);
結果、やっぱりダメ。SourceLocationの問題ではないらしい。
複数cppをまとめてコンパイルできると誰が言った?
ここであることが頭をよぎる。gcc等では1回の起動で1つの.cppしか処理しない。clangのクラス群もそのように設計されているのではないか?SourceManagerのMainという概念は、.cpp1ファイルのことを指すのではないか?
もしそうだとすると、非常に面倒なことである。ASTContextにおけるclang::Typeの反復の重複除去も意味がない。
そこで、1つのASTContextで複数の.cppを処理できるのか、試してみることにする。
まずSourceManagerのリセットである。調べたところ、MainFileIDはclearIDTable()メンバ関数でのみリセットされるようである。
ということで、以下のように実装してみる。
clang::IdentifierTable identifierTable(langOpts); clang::SelectorTable selectorTable; clang::Builtin::Context builtinContext; clang::ASTContext astContext(langOpts, srcMgr, targetInfo, identifierTable, selectorTable, builtinContext, 0); clang::ASTConsumer astConsumer; clang::Sema sema(pp, astContext, astConsumer); sema.Initialize(); const char* targets[2] = { "D:\\develop\\Clang\\SampleProj\\Package1\\Super.cpp", "D:\\develop\\Clang\\SampleProj\\Package2\\Sub.cpp" }; for(const char** target = targets; target != (targets + 2); ++target) { srcMgr.clearIDTables(); srcMgr.createMainFileID(fileMgr.getFile(*target)); clang::ParseAST(pp, &astConsumer, astContext); } // 構文解析結果を確認する。 clang::ASTContext::const_type_iterator t = astContext.types_begin(); clang::ASTContext::const_type_iterator eot = astContext.types_end(); for(; t != eot; ++t) { if((*t)->getTypeClass() != clang::Type::Record) { continue; } clang::CXXRecordDecl* pDecl = (*t)->getAsCXXRecordDecl(); if( (pDecl != nullptr) && pDecl->hasDefinition() && pDecl->isClass() ) { std::printf("\n---------------------------------------------------------\n"); (*t)->dump(); } }
実行した結果、次のようなエラーメッセージが。
Assertion failed: NumEnteredSourceFiles == 0 && "Cannot reenter the main file!", file D:\develop\Clang\llvm\tools\clang\lib\Lex\Preprocessor.cpp, line 388
うーむ、Preprocessorの時点で再利用できないのね。
0 件のコメント:
コメントを投稿