(py)gccxmlを使用してC / C ++コードからメタ情報を抽出する

gccxmlが登場する前は、C / C ++コードからメタ情報を抽出する方法は1つしかありませんでした。 まず、 C ++言語の文法に対応できるパーサーを作成する必要がありました。 これは、週末に自宅で通常解決する問題ではありません。



これで、パーサーを記述する必要がなくなりました。 変更されたgccコンパイラはコードを分析し、プログラムで検出されたすべての名前空間、型、クラス、および関数の説明を提供します。 データはXML形式で発行され、原則として、さらなる自動分析および処理の準備ができています。



pygccxmlライブラリーは、gccxmlから受け取ったXMLデータの解析に役立ちます。 これは単なるgccxml形式のリーダーではありません-ライブラリは、収集されたメタデータを調べるためのインターフェイスを提供します。 特に、「型T 1とT 2は互換性がありますか?」または「クラスC 1はC 2を継承しますか?」などの質問に答える既製の関数があります。 ライブラリはPythonで書かれています。





gccxmlの紹介



Gccxmlはキットウェアで開発されました(CMakeの著者でもあります)。 これは、GCCからの修正C ++パーサーです。



おそらくgccxmlをまだインストールしていないでしょう。 個人的には、パッケージマネージャーを使用してgccxmlをインストールしましたが、この手順を詳しく説明する必要はありません。 お使いのOSのパッケージマネージャーがいない場合は、仕方がないと思います。



簡単な関数定義から始めましょう。

namespace test { int fn(int a, int b); }
      
      





コンパイルします:

 gccxml -fxml=test.xml test.cpp
      
      





出力は、次のコンテンツ(フラグメント)を持つtest.xmlです。

 <GCC_XML> <Namespace id="_1" name="::" members="… _96 …" mangled="_Z2::" demangled="::"/> <Namespace id="_96" name="test" context="_1" members="_141 " mangled="_Z4test" demangled="test"/> <FundamentalType id="_128" name="int" size="32" align="32"/> <Function id="_141" name="fn" returns="_128" context="_96" mangled="_ZN4test2fnEii" demangled="test::fn(int, int)" location="f1:2" file="f1" line="2" extern="1" > <Argument name="a" type="_128" location="f1:2" file="f1" line="2"/> <Argument name="b" type="_128" location="f1:2" file="f1" line="2"/> </Function> <File id="f1" name="test.cpp"/> </GCC_XML>
      
      





ここでは、ドキュメントなしですべてが明らかです。 C ++言語の他の構成の例は示しません。すべてが同じです。 主な目標が達成されました-メタ情報は、さらに自動処理に適した形式で抽出されます。



より多くのメタ情報を取得する



ソースコードには、C ++言語のセマンティクスよりも多くの情報が含まれている場合があります。 例:WindowsでのSALアノテーション (__in、__ outなど)



 BOOL WINAPI CreateProcess( __in_opt LPCTSTR lpApplicationName, __inout_opt LPTSTR lpCommandLine, __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, __in BOOL bInheritHandles, __in DWORD dwCreationFlags, __in_opt LPVOID lpEnvironment, __in_opt LPCTSTR lpCurrentDirectory, __in LPSTARTUPINFO lpStartupInfo, __out LPPROCESS_INFORMATION lpProcessInformation );
      
      





例:API機能が利用可能なMac OS Xの最小バージョンに関する情報。



 CFErrorRef CFErrorCreate( CFAllocatorRef allocator, CFStringRef domain, CFIndex code, CFDictionaryRef userInfo ) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
      
      





この追加のメタ情報でさえ、gccxmlを使用して抽出できます。 ここでは、gcc固有のC ++構文拡張機能である属性構成体が役立ちます。 関数fnの定義を実験します。



 #define __foo __attribute__((gccxml("__foo")) #define __bar __attribute__((gccxml("__bar")) namespace test { __foo int fn(__bar int a, int b); }
      
      





属性は、ソーステキスト内の最も近い意味単位に「適用」されます。 したがって、最初の属性は関数fnに関連し、2番目の属性はパラメーターaに関連しています。 Gccはさまざまな属性を理解しますが、この場合はgccxml属性のみに関心があります。



Gccxmlは、fn関数に関する次の情報を提供します。 ご覧のとおり、すべての注釈が保存され、さらに処理するために使用できます。



 <Function id="_141" name="fn" returns="_128" context="_96" mangled="_ZN4test2fnEii" demangled="test::fn(int, int)" location="f1:7" file="f1" line="7" extern="1" attributes="gccxml(__foo)"> <Argument name="a" type="_128" location="f1:7" file="f1" line="7" attributes="gccxml(__bar)"/> <Argument name="b" type="_128" location="f1:7" file="f1" line="7"/> </Function>
      
      







pygccxmlの紹介



Pygccxmlは、Roman Yakovenkoと共同開発者です。 このプロジェクトの目標は、boost :: pythonを使用したC ++ / Pythonバインダーの自動生成です。 なぜ彼らはSWIGが好きではなかったのだろうか



Pygccxmlは、パッケージマネージャーを使用してインストールするか、手動でインストールできますこちらからダウンロードしてください 。インストール手順はREADME.txtを参照)。



pygccxmlのドキュメントは貧弱です。 始めるには十分ですが、基本的な機能を超えるものが必要な場合は、ライブラリのソースコードを調べる必要があります。 これは奇妙ですが、ドキュメントはオンラインで表示することはできません。 ダウンロードすることしかできません。



以下は、pygccxmlライブラリーを使用した単純なC ++コードアナライザーの例です。

スクリプトは、テスト名前空間で宣言されたすべての関数を出力します。



 import pygccxml db = pygccxml.parser.parse(['test.cpp']) global_ns = pygccxml.declarations.get_global_namespace(db) for test_ns in global_ns.namespaces('test'): for function in test_ns.calldefs(): pygccxml.declarations.print_declarations(function)
      
      





スクリプトの結果は次のとおりです。



 free_function_t: 'fn' location: [./test.cpp]:4 artificial: 'False' attributes: gccxml(__foo) demangled: test::fn(int, int) mangled: _ZN4test2fnEii return type: int arguments type: int a, int b
      
      







コードのアイデア



言語やコンパイラに興味がないのに、なぜプログラムでC ++コードを分析する必要があるのですか? 実用的な読者は尋ねます。 次に、自動コード分析を必要とする非常に現実的なタスクについて説明します。



Alexey Pakhunovがnotakernelguyとしても書いているものを次に示します

最近、Win32 APIレベルでUTF-8サポートをエミュレートするライブラリがないのはなぜだろうと思いました。 つまり このようなライブラリは、たとえば、提案されたシステムCreateFileAおよびCreateFileWに加えてCreateFileUtf8を実装し、CreateFileマクロは3つのオプションから目的の実装を選択します。
2007年、アレクセイは、Notepad2でのUnicodeサポートの透過的な実装のために、このようなライブラリを作成することを決定しました。 Windowsヘッダーファイルを自動的に処理し、目的のライブラリをプログラムで生成することを想定していました。 Alexey gccxmlを使用せず 、2012年には彼のライブラリはまだ準備ができていません。



私の練習からの次の2つの例。



gccxmlを使用して、Mac OS Xの基本オブジェクト指向C APIであるCoreFoundationの C ++ラッパーを作成しました。このプロジェクトの目標は、CFオブジェクトの有効期間の自動制御を実装することです。 はい、 ARCを知っています。



次に、2番目の例を示します。 C ++で記述されたデータ処理システムがあります 。 システムは最初はシングルスレッドです。パフォーマンスを向上させるために、相互作用するオブジェクトの一部を異なるフローに分散することが計画されています。 これを行うには、メソッド呼び出しを変換して一連のプロキシクラスを作成し、メッセージを別のスレッドに送信します。メッセージを展開すると、プロキシの背後に隠されたオブジェクトのメソッドが呼び出されます。 オブジェクトへのアクセスは単一のストリームから実行されるため、既存のコードを変更する必要はありません。 同じタイプのコードを大量に記述する必要があり、このタスクは自動ジェネレーターに任せるのが最適です。



Gccxmlの制限



残念ながら、gccxmlにはいくつかの欠点があります。 コードから宣言のみが抽出され、関数本体は使用できません。 テンプレート宣言も使用できません。 Gccxmlはかなり古いバージョンのgccに基づいており、開発はあまり活発ではありません。



All Articles