Doxygen latest release v1.8.11 - last update Mon Oct 25 2021

前処理

doxygenの入力に使うソースファイルは、組込のC言語プリプロセッサによって解析します。

デフォルトでは、部分的な前処理しかしません。つまり、条件付コンパイル構文(#ifのような)と、マクロ定義は評価しますが、マクロ展開はしません。

ですので、次のようなコード断片があると、

#define VERSION 200
#define CONST_STRING const char *

#if VERSION >= 200
  static CONST_STRING version = "2.xx";
#else
  static CONST_STRING version = "1.xx";
#endif

doxygenは、以下のようにパーサーに渡します。

#define VERSION
#define CONST_STRING

  static CONST_STRING version = "2.xx";

前処理を全部無効にするには、設定ファイルで、ENABLE_PREPROCESSINGNO にします。上の例の場合、doxygenは両方の構文を読み込みます。

  static CONST_STRING version = "2.xx";
  static CONST_STRING version = "1.xx";

CONST_STRING マクロを展開したい場合、設定ファイルで MACRO_EXPANSIONYES にします。すると、前処理の結果は、

#define VERSION
#define CONST_STRING

  static const char * version = "1.xx";

となります。 このとき、doxygenは すべて のマクロ定義を展開します(必要なら再帰的に)。 しかし、これでは過剰なことも多いです。 ですので、明示的に指定したdefineのみを展開するよう指示することもできます。 それには、EXPAND_ONLY_PREDEFYES にして、PREDEFINEDEXPAND_AS_DEFINED の後にマクロ定義を指定します。

前処理時点でヘルプが必要となる典型的な例があります。それは、Microsoft の言語拡張 declspec と、GNU の __attribute 拡張です。前者の例です。

extern "C" void __declspec(dllexport) ErrorMsg( String aMessage,...);

何もしないと、doxygenは混乱し、__declspec をある種の関数とみなします。この場合、次のようにします。

ENABLE_PREPROCESSING   = YES
MACRO_EXPANSION        = YES
EXPAND_ONLY_PREDEF     = YES
PREDEFINED             = __declspec(x)=

こうすると、__declspec(dllexport) が、ソースコードを解析する前に、確実に取り除かれます。

さらに複雑な例として、IUnknown という抽象基底クラスの、次のような不明瞭なコード断片があるとします。

/*! IID への参照 */
#ifdef __cplusplus
#define REFIID const IID &
#else
#define REFIID const IID *
#endif


/*! IUnknown インターフェース */
DECLARE_INTERFACE(IUnknown)
{
  STDMETHOD(HRESULT,QueryInterface) (THIS_ REFIID iid, void **ppv) PURE;
  STDMETHOD(ULONG,AddRef) (THIS) PURE;
  STDMETHOD(ULONG,Release) (THIS) PURE;
};

マクロを展開しないと、doxygenは混乱してしまうでしょう。しかし、REFIIDマクロは展開したくないところです。ドキュメントがついていますし、ドキュメントを読んだユーザは、インタフェースを実装する際に使うことになるからです。

設定ファイル内で次のように設定すれば、

ENABLE_PREPROCESSING = YES
MACRO_EXPANSION      = YES
EXPAND_ONLY_PREDEF   = YES
PREDEFINED           = "DECLARE_INTERFACE(name)=class name" \
                       "STDMETHOD(result,name)=virtual result name" \
                       "PURE= = 0" \
                       THIS_= \
                       THIS= \
               __cplusplus

次のように、適切な結果がdoxygenパーサーに与えられます。

/*! IID への参照 */
#define REFIID

/*! IUnknown インターフェース */
class  IUnknown
{
  virtual  HRESULT   QueryInterface ( REFIID iid, void **ppv) = 0;
  virtual  ULONG   AddRef () = 0;
  virtual  ULONG   Release () = 0;
};

ここで、PREDEFINED タグは、関数形式のマクロ定義(DECLARE_INTERFACE)、通常のマクロ置換(PURETHIS)、純粋なdefine(__cplusplus)などを受け入れます。

また、通常はプリプロセッサが自動的に定義するプリプロセッサ定義(__cplusplus)は、doxygenのパーサーを使って手で定義しなければならないことに注意してください。なぜなら、このようなdefineは、プラットフォームやコンパイラ固有の場合が多いからです。

場合によっては、マクロ名や関数を他のもので置き換えて、その結果をマクロ置換えさせたくないこともあるでしょう。これを行うには、= でなく := オペレータを使います。

例えば、次のようなコードがあるとします。

#define QList QListT
class QListT
{
};

QListクラスのクラス定義としてdoxygenに解釈させる方法は、以下のようにdefineするしかありません。

PREDEFINED = QListT:=QList

次は、Valter Minute と Reyes Ponce から提供された例です。これで、MicrosoftのATL & MFC ライブラリの定型コードを読み進むことが可能なように、doxygenをサポートしてくれます。

PREDEFINED           = "DECLARE_INTERFACE(name)=class name" \
                       "STDMETHOD(result,name)=virtual result name" \
                       "PURE= = 0" \
                       THIS_= \
                       THIS= \
                       DECLARE_REGISTRY_RESOURCEID=// \
                       DECLARE_PROTECT_FINAL_CONSTRUCT=// \
                       "DECLARE_AGGREGATABLE(Class)= " \
                       "DECLARE_REGISTRY_RESOURCEID(Id)= " \
                       DECLARE_MESSAGE_MAP= \
                       BEGIN_MESSAGE_MAP=/* \
                       END_MESSAGE_MAP=*/// \
                       BEGIN_COM_MAP=/* \
                       END_COM_MAP=*/// \
                       BEGIN_PROP_MAP=/* \
                       END_PROP_MAP=*/// \
                       BEGIN_MSG_MAP=/* \
                       END_MSG_MAP=*/// \
                       BEGIN_PROPERTY_MAP=/* \
                       END_PROPERTY_MAP=*/// \
                       BEGIN_OBJECT_MAP=/* \
                       END_OBJECT_MAP()=*/// \
                       DECLARE_VIEW_STATUS=// \
                       "STDMETHOD(a)=HRESULT a" \
                       "ATL_NO_VTABLE= " \
                       "__declspec(a)= " \
                       BEGIN_CONNECTION_POINT_MAP=/* \
                       END_CONNECTION_POINT_MAP=*/// \
                       "DECLARE_DYNAMIC(class)= " \
                       "IMPLEMENT_DYNAMIC(class1, class2)= " \
                       "DECLARE_DYNCREATE(class)= " \
                       "IMPLEMENT_DYNCREATE(class1, class2)= " \
                       "IMPLEMENT_SERIAL(class1, class2, class3)= " \
                       "DECLARE_MESSAGE_MAP()= " \
                       TRY=try \
                       "CATCH_ALL(e)= catch(...)" \
                       END_CATCH_ALL= \
                       "THROW_LAST()= throw"\
                       "RUNTIME_CLASS(class)=class" \
                       "MAKEINTRESOURCE(nId)=nId" \
                       "IMPLEMENT_REGISTER(v, w, x, y, z)= " \
                       "ASSERT(x)=assert(x)" \
                       "ASSERT_VALID(x)=assert(x)" \
                       "TRACE0(x)=printf(x)" \
                       "OS_ERR(A,B)={ #A, B }" \
                       __cplusplus \
                       "DECLARE_OLECREATE(class)= " \
                       "BEGIN_DISPATCH_MAP(class1, class2)= " \
                       "BEGIN_INTERFACE_MAP(class1, class2)= " \
                       "INTERFACE_PART(class, id, name)= " \
                       "END_INTERFACE_MAP()=" \
                       "DISP_FUNCTION(class, name, function, result, id)=" \
                       "END_DISPATCH_MAP()=" \
                       "IMPLEMENT_OLECREATE2(class, name, id1, id2, id3, id4,\
                        id5, id6, id7, id8, id9, id10, id11)="

doxygenのプリプロセッサがいかにパワフルかお分かりかと思いますが、さらに自由度が必要なら、いつでも入力フィルタを書いてそれを INPUT_FILTER の後に指定できます。

前処理の効果に不安をお持ちなら、次のように実行してみてください。

  doxygen -d Preprocessor

これによってdoxygenは、前処理を実行した後の入力ソースを標準出力にダンプします。(ヒント:他の出力を無効にするには、設定ファイルで、QUIET = YESWARNINGS = NOと設定してください)。

のセクションに行く / インデックス に戻る

This page was last modified on Mon Oct 25 2021.
© 1997-2021 Dimitri van Heesch, first release 27 oct 1997.
© 2001 OKA Toshiyuki (Japanese translation).
© 2006-2021 TSUJI Takahiro (Japanese translation).
© 2006-2014 TAKAGI Nobuhisa (Japanese translation).