Doxygen で internal な実装群を隠す

隠すやり方がいくつかあるんだけど、 どう隠したいかで使うべきコマンドが違うみたい…。

遭遇したケース

通常、 source file local な class やメソッドに対する Doxygen コメントとかは Doxygen の設定の EXTRACT_〜 を適切にすれば出力されないはず。

私が今回遭遇したケースは

  • constexpr function なのでヘッダーに実装を書いてる
  • Google C++ Style Guide に則るとヘッダーファイルでは無名名前空間が使えないので impl という名前空間に入れてる
  • 勢い余ってせっかく書いた doxygen コメントは残しておきたいが、内部実装なので API リファレンスとしての Doxygen の output からは除外したい
  • そういった実装が複数連続してる存在してるのでまとめて隠したい

この場合は @cond, @endcond を使うとできる。

github.com

Doxygen における条件による出力の出し分け方

いくつか方法がある。以下網羅できてるかは知らない。

#ifndef を使う方法

  • 隠したいところを Doxygen 解釈時以外には絶対に定義されないマクロの #ifndef で括る
#ifndef DOXYGEN_SHOW_CLASS_FOO

/// This class provides so FOO features.
class Foo {
};

#endif  // !defined(DOXYGEN_SHOW_CLASS_FOO)
  • ENABLE_PREPROCESSING = YES にする
  • 出力したいときは PREDEFINED = DOXYGEN_SHOW_CLASS_FOO にする

これは @cond が実装される前に使われてた方法らしい。

  • C / C++ として何か作用したいわけではないのに、 C / C++ としてのソースが汚れる
  • プリプロセッサマクロを解釈するようなツール群が期待しない動作になる or 期待動作のために追加設定が必要になる、かも
    • エディタのコードハイライティング
    • lint など静的解析ツール
    • ...

あたりが欠点かなぁ…。

@cond を使う方法

これは上で書いたので簡単に言うと #ifndef とかの代わりに Doxygen コマンドを使う、と。

/// @cond DOXYGEN_SHOW_CLASS_FOO

/// This class provides so FOO features.
class Foo {
};

/// This class provides so BAR features.
class Bar {
};

/// @endcond
  • 出力したいときは ENABLED_SECTIONS=DOXYGEN_SHOW_CLASS_FOO のようにする

これは使いやすいよね。コードハイライティングがおかしくなったりもしないだろうし。 ちなみに常時出力しないのでよければ @cond のうしろ(「セクションラベル」と呼ぶらしい)は省略できるらしい。

/// @cond

/// This class provides so FOO features.
class Foo {
};

/// This class provides so BAR features.
class Bar {
};

/// @endcond

まぁ、どういう意図で @condで括っているかの表明にもなるから、私だったら省略しないルールにすると思う。

@if を使う方法

これが紛らわしい。 @cond がざっくりまとめて出力・非出力を切り替える目的に使えるのに対して、 @if はコメントブロック内で一部の出力条件を変える目的に使う。 この「コメントブロック内〜」が重要なんだけど私は最初読み飛ばしちゃってて混乱した。 要はクラスなり関数なりの説明のまとまりの中で一部を出力する条件を記述するのに使えるってことらしい。

今回のように目的が「コードを読んだ人には見せるけど Doxygen 出力からは隠す」だと

/// This class provides so FOO features.
///
/// @if CLASS_FOO_SECRET
/// This is not doxygen-documented secret, Ha ha.
/// @endif
class Foo {
};

みたいなことになる。 ENABLED_SECTIONS=CLASS_FOO_SECRET としてやれば括ってあるところも出力される。 ただ、コメントブロックをまたげないので、 今回のように複数関数をまとめて出力する・しないを切り替えたいような用途には使えない。 これだけだと私にはあんまりありがたみが感じられなかったんだが、

/// This class provides so FOO features.
///
/// @if english
/// Details by English.
/// @elseif japanese
/// 日本語での詳細記述。
/// @endif
class Foo {
};

こんな感じで言語を切り替えるのに使ってるのは、 そういえば以前に見たような記憶がかすかにある…。 ENABLED_SECTIONS と出力先を切り替えながら出力すると 複数言語分のドキュメントが生成できる、と。