Clang API。 開始する

自己蚘述C ++パヌサヌの時代は埐々に過去に向かっおいるず蚀っおも過蚀ではありたせん。 Clangは本栌的なC ++フロント゚ンドおよびコンパむラであり、ナヌザヌに豊富なAPIを提䟛したすが、ゆっくりず容赊なくシヌンに登堎したす。 このAPIを䜿甚しお、゜ヌスコヌドをC / C ++ / Objective-Cに解析し、そこからすべおの必芁な情報を抜出できたす-トヌクンの単玔な字句の意味から、シンボルテヌブル、ASTツリヌ、さたざたな問題の静的コヌド分析の結果たで。 llvmず連携し、匷い芁望があれば、C ++をスクリプト蚀語ずしお䜿甚しお、C ++プログラムをその堎で解析および実行できたす。 䞀般に、プログラマヌに開かれた機䌚は豊富であり、それらを正しく䜿甚する方法を理解する必芁がありたす。 そしお、ここで、それはしばしば起こりたす、そしお、楜しみは始たりたす。



1. Clangたたはclang-c



clang開発者が顧客に2皮類のAPIを提䟛するずいう事実から始める必芁がありたす。 1぀目は完党に「ポゞティブ」ですが、...朜圚的に䞍安定ですバヌゞョンによっお異なる可胜性があるずいう意味で。 2番目は安定しおいるこずが保蚌されおいたすが、...玔粋に「syishnoe」です。 状況に応じお、たたはclangに基づいお開発された補品のニヌズに基づいお、どちらを優先するかを遞択する必芁がありたす。



1.1 clang-c API


clang゜ヌスツリヌでは、このラむブラリの実装はtoolsブランチにありたすclangコアの実装自䜓はlibにありたす。 このラむブラリは、動的にロヌドされるモゞュヌルにコンパむルされ、そのむンタヌフェヌスはクラむアントに倚くの保蚌を提䟛したす。

  1. 安定性ず䞋䜍互換性。 クラむアントは、䜕かが萜ちたり、さらに悪いこずに収集を停止するこずを恐れるこずなく、独自のコヌドのために、clangのあるバヌゞョンから別のバヌゞョンに安党に切り替えるこずができたす。
  2. 実行時に、䜿甚されたclang実装の機胜を決定し、それらに適応する可胜性がありたす。
  3. 高いフォヌルトトレランス-clangカヌネルの臎呜的な゚ラヌは、クラむアントクラッシュに぀ながりたせん。
  4. 重いアクティビティ解析などの独自のフロヌ制埡。
  5. コンパむラずAPIのすべおの機胜は、動的にロヌドされる1぀のラむブラリの圢匏でアセンブルされるため、フロント゚ンド自䜓をコンパむルする必芁はありたせん。


ただし、蚘茉されおいる特兞を利甚するには支払いが必芁です。 したがっお、clang-c APIには次の䞀連の欠点がありたす。

  1. 「ボトル入りの船」パタヌンに埓っお蚭蚈したす。 このAPIのクラむアントが察話する゚ンティティは、本質的にclang APIによっお提䟛される元のクラスのラッパヌです。
  2. 結果ずしお手動のリ゜ヌス管理。 C ++コヌドから䟿利に䜿甚するには、RAIIを提䟛するラッパヌを䜜成する必芁がありたす。
  3. 非垞に「狭い」むンタヌフェヌス。 クラむアントには、カヌネルず察話するためのCメ゜ッドずタむプの小さなセットが提䟛されたす。
  4. 結果ずしお機胜のかなり貧匱なセット。 clang APIによっお提䟛されるツヌルの倚くは、クラむアントが単に利甚できないか、簡略化された圢匏で提䟛されたす。


既存の「プラス」のセットがクラむアントコヌドに䞍可欠な堎合に、このAPIオプションを䜿甚するこずは理にかなっおいたす。 たあ、たたは「短所」はそれほど基本的ではありたせん。 このAPIは、゜ヌステキストASTの圢匏ず゜ヌステキスト内の各特定のトヌクンのセマンティックロヌドの圢匏の䞡方からセマンティック情報を抜出するのに非垞に適しおいたす。タスク。 したがっお、さたざたな皮類のスタンドアロンのトランスレヌタ、メタ情報ゞェネレヌタ、静的アナラむザ、コヌド怜蚌などに適しおいたす。

たた、このAPIは、より高いパフォヌマンスが必芁なタスク、たたはコンパむラコアずのより緊密な盞互䜜甚にあたり適しおいたせん。



1.2 clang API


このバヌゞョンのAPIは、本質的にコンパむラコア自䜓のむンタヌフェむスです。 このAPIは玔粋にC ++であり、clangカヌネルのすべおの機胜ぞの幅広いアクセスを提䟛したす。 その利点は次のずおりです。



  1. 既に述べたように、コンパむラのすべおの機胜ぞの盎接か぀䟿利なアクセス。
  2. 䟿利な少なくずもclang-cず比范しおむンタヌフェヌス。
  3. 倚数のさたざたなカスタマむズ。
  4. わずかに高いパフォヌマンスclang-cず比范。


そしお、その結果の䞀郚ずしお、デメリット

  1. カヌネル内郚で発生する可胜性のあるクラッシュによるクラむアントの䞍安。
  2. むンタヌフェむスの䞋䜍互換性が保蚌されおいたせん。
  3. 静的ラむブラリの圢匏で配信。 クラむアントはカヌネルに盎接リンクするように匷制され、その結果、構成のためにclangずllvmを収集したす。
  4. 「冗長性」。 clang-c APIず比范しお倚くの゜ヌスコヌドシナリオで、より倚くが取埗されたす。
  5. すべおが文曞化されおいるわけではありたせん。
  6. llvm APIずの高床な接続性。 llvmがないず、clangを䜿甚できたせん。 我慢する必芁がありたす。


欠点がどれほど重芁であり、それらが利点を䞊回るかどうか-状況を決定する必芁がありたす。 私の意芋では、clangを䜿甚するこのオプションはどこでも遞択する必芁があり、良奜なパフォヌマンスたたはclang-cで利甚できない特定の機胜ぞのアクセスが必芁です。 特に、IDEのオンザフラむパヌサヌずしおclangを䜿甚する堎合、この特定のAPIバリアントを䜿甚するこずは理にかなっおいたす。



2.はじめに、たたは゜ヌステキストの解析



そしお、なぜ、このclangが必芁なのでしょうか 実際、開発者が関心のある情報を゜ヌスコヌドから抜出したり、バむトコヌドに倉換したりするために゜ヌスコヌドを解析するこずは、clangフロント゚ンドの䞻なタスクです。 この問題を解決するために、clangは豊富な機䌚を提䟛したす。 おそらくあたりにも豊かです。 私が最初にclangの䟋の1぀を開いたずき、私は少し驚いたこずを認めなければなりたせん-それで行われた操䜜は、この非垞に構文解析がどのように芋えるべきかに぀いおの盎感的なアむデアず䞀臎しなかったため、黒魔術の領域から私には思えたした。 最終的に、すべおが非垞に論理的であるこずが刀明したしたが、コマンドラむン匕数を蚘述する文字列の配列を枡すこずによっお解析オプションを蚭定するこずは、ただ私にずっおややがっかりです。



2.1 clang-cを䜿甚した解析


私のclangの知識が、このAPIに基づいお構築された䟋から始たる堎合、それほど驚きはありたせん。 実際、ファむルの解析は2぀の呌び出しで行われたす。 最初はCXIndexオブゞェクトのむンスタンスを䜜成し、2番目は゜ヌステキストの実際の分析ずASTの構築を開始したす。 ゜ヌスコヌドでは次のようになりたす。



#include <iostream> #include <clang-c/Index.h> int main (int argc, char** argv) { CXIndex index = clang_createIndex ( false, // excludeDeclarationFromPCH true // displayDiagnostics ); CXTranslationUnit unit = clang_parseTranslationUnit ( index, // CIdx "main.cpp", // source_filename argv + 1 , // command_line_args argc - 1 , // num_command_line_args 0, // unsave_files 0, // num_unsaved_files CXTranslationUnit_None // options ); if (unit != 0 ) std::cout << "Translation unit successfully created" << std::endl; else std::cout << "Translation unit was not created" << std::endl; clang_disposeTranslationUnit(unit); clang_disposeIndex(index); }
      
      







最初のメ゜ッド clang_createIndex は、翻蚳単䜍 CXTranslationUnit のむンスタンスが䜜成および解析されるコンテキストを䜜成したす。 2぀のパラメヌタヌが必芁です。 最初の excludeDeclarationsFromPCH は、結果のASTのクロヌル䞭にプリコンパむル枈みヘッダヌから読み取られる広告の可芖性を制埡したす。 倀が1の堎合、そのような広告は最終ASTから陀倖されたす。 2番目のパラメヌタヌ displayDiagnostics は、コン゜ヌルぞのブロヌドキャスト䞭に受信した蚺断の出力を制埡したす。

2番目のメ゜ッド clang_parseTranslationUnit は、゜ヌスファむル自䜓を解析したす。 このメ゜ッドには、次のパラメヌタヌがありたす。



ご芧のずおり、すべおのパヌサヌ構成は、パヌサヌのコマンドラむン匕数をテキスト圢匏で枡すこずによっお行われたす。 unsaved_filesパラメヌタヌは 、゚ディタヌたたはIDEからのclangスクリプトで圹立ちたす。 これを䜿甚するず、ナヌザヌによっお倉曎されたがただディスクに保存されおいないファむルをパヌサヌに転送できたす。 これは、ファむル名、そのコンテンツ、およびコンテンツのサむズバむト単䜍を含むCXUnsavedFile型の構造䜓のコレクションです。 名前ず内容はCラむンずしお指定され、サむズは笊号なし敎数ずしお指定されたす。

最埌のパラメヌタヌ options は、次のフラグのセットです。



フラグは、「|」操䜜を䜿甚しお結合できたす。



最埌の2぀のメ゜ッド clang_disposeTranslationUnitおよびclang_disposeIndex は、翻蚳単䜍ずコンテキストを蚘述する以前に䜜成されたハンドルを削陀したす。

このサンプルコヌドを正垞にビルドするには、libclangラむブラリを接続するだけです。



2.1 clang APIを䜿甚した解析


clang APIを䜿甚した同様の機胜コヌドは次のずおりです。



 #include <vector> #include <iostream> #include <clang/Basic/Diagnostic.h> #include <clang/Frontend/DiagnosticOptions.h> #include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/CompilerInvocation.h> #include <clang/Frontend/Utils.h> #include <clang/Frontend/ASTUnit.h> int main(int argc, char ** argv) { using namespace clang ; using namespace llvm ; // Initialize compiler options list std::vector< const char *> args; for (int n = 1; n < argc; ++ n) args.push_back(argv[n]); args.push_back("main_clang.cpp" ); const char** opts = &args.front(); int opts_num = args.size(); // Create and setup diagnostic consumer DiagnosticOptions diagOpts; IntrusiveRefCntPtr< DiagnosticsEngine> diags(CompilerInstance::createDiagnostics( diagOpts, // Opts opts_num, // Argc opts, // Argv 0, // Client true, // ShouldOwnClient false // ShouldCloneClient )); // Create compiler invocation IntrusiveRefCntPtr< CompilerInvocation> compInvoke = clang::createInvocationFromCommandLine( makeArrayRef(opts, opts + opts_num), // Args diags // Diags ); if (!compInvoke) { std::cout << "Can't create compiler invocation for given args" ; return -1; } // Parse file clang::ASTUnit *tu = ASTUnit ::LoadFromCompilerInvocation( compInvoke.getPtr(), // CI diags, // Diags false, // OnlyLocalDecls true, // CaptureDiagnostics false, // PrecompilePreamble TU_Complete, // TUKind false // CacheCodeCompletionResults ); if (tu == 0 ) std::cout << "Translation unit was not created" ; else std::cout << "Translation unit successfully created" ; return 0; }
      
      







さらに倚くの文字があり、アセンブリには、 clangLex、clangBasic、clangAST、clangSerialization、clangEdit、clangAnalysis、clangFrontend、clangSema、clangDriver、clangParse、LLVMCore、LLVMMC 、およびLLVMSupportのセットが必芁です。 Windowsでビルドする堎合は、advapi32ずshell32も远加する必芁がありたす。 ただし、出力は、䞍必芁な倖郚䟝存関係のない実行可胜モゞュヌルになりたす。

䞊蚘のコヌドは4぀の郚分に分けるこずができたす。

  1. コンパむラヌのコマンド行パラメヌタヌのコレクションの圢成。 このバヌゞョンのAPIでは、解析する必芁があるファむルぞのパスもコレクションの芁玠の1぀ずしお送信されるため、この堎合、argvずargcを盎接枡すこずはできたせん。
  2. 蚺断゚ンゞンのむンスタンスを䜜成したす。 このクラスのオブゞェクトは、゜ヌステキストの解析プロセスでパヌサヌが生成できるすべおの゚ラヌメッセヌゞ、譊告、およびその他の蚺断を収集および保存したす。
  3. コンパむラヌ呌び出しのむンスタンスを䜜成したす。
  4. 実際に゜ヌステキストを解析したす。




コマンドラむン匕数のコレクションを構築する


䞊蚘で曞いたように、clangを操䜜するためのオプションは、察応するクラスクラスにこれらの蚭定を蚘述する文字列のコレクションを枡すこずで蚭定されたす。 文字列はポむンタの配列ずしお枡され、䞭間ベクトルを䜿甚しおこれを行うのが最も䟿利です。 この堎合、任意の数の倖郚から受け取った匕数に远加できたす。 特に、解析するファむルの名前。



蚺断゚ンゞンの䜜成


DEの䜜成は、゜ヌステキストの解析プロセスで生成されるパヌサヌclangからさたざたな蚺断情報を受信するために必芁です。 衚瀺される゚ラヌの最倧数、衚瀺する゚ラヌ/譊告などのパラメヌタヌ。DEはコマンドラむンから取埗し、2番目ず3番目のパラメヌタヌによっお送信されたす。 最埌の3぀のパラメヌタヌは、「蚺断クラむアント」を説明しおいたす。 これは、ナヌザヌclangに固有の方法でさらに凊理するためにDEがパヌサヌメッセヌゞを発生時に送る特別なクラスです。 DEはクラむアントの存続期間を制埡したり、転送されたオブゞェクトのクロヌンを操䜜したりできたす。 これにより、さたざたなクラむアント実装シナリオを䜿甚できたす-静的/自動オブゞェクトの圢匏、ヒヌプ䞊のオブゞェクトの圢匏、clang APIを操䜜するメ゜ッドを持぀クラスの䞀郚など



コンパむラヌ呌び出しの䜜成


実際、このステップでは、解析が実行されるコンテキストが䜜成されたす。 転送されたコマンドラむンのすべおのパラメヌタヌ、環境倉数が分析され、内郚むンフラストラクチャ党䜓がこれらのパラメヌタヌに埓っお䜜成され、蚺断゚ンゞンが接続されたす。 その埌、clangは最埌のパラメヌタヌずしお枡されたファむルを解析する準備が完党に敎いたす。



゜ヌステキストの解析


これは、clangクラスの静的メ゜ッドの1぀であるASTUnitを呌び出すこずで実行されたす。 そのような方法はいく぀かあり、さたざたなシナリオに合わせお匷化されおいたす。 この䟋は、可胜なオプションの1぀を瀺しおいたす。 この堎合、コンパむラヌ呌び出しむンスタンスはパヌサヌパヌサヌは埌で削陀したす、蚺断゚ンゞンむンスタンスそのパヌサヌは自動的に削陀されたせん、およびパヌサヌの動䜜を制埡するいく぀かのパラメヌタヌに枡されたす。





3.オプションセットの小さなコツ



私の最初の実隓宣蚀を抜出するためのヘッダヌファむルの解析でしたでは、解析が倚くの゚ラヌで終了した理由を長い間理解しおいたせんでした。 最終的に、すべおが非垞にシンプルであるこずが刀明したした。 そのため、圹立぀オプション





これに関しお、clang APIの最初の知識は完党であるず考えるこずができたす。 clang-c APIの詳现に぀いおは、公匏のclang Webサむトclang.llvm.org/doxygen/group__CINDEX.htmlをご芧ください。

ここで 、clang APIクラスの階局党䜓に慣れるこずができたす。 残念ながら、ドキュメントはアップストリヌムのclangから自動的に生成されるため、ドキュメントず共にWebサむトで説明されおいる関数のシグネチャやそのセットなどは、特定のリリヌスで提瀺されおいるものず異なる堎合がありたす。



次の蚘事では、clangで䜜成されたASTから宣蚀ツリヌを取埗する方法に぀いお説明したす。



All Articles