メインページに戻る
Japan Blog

Google が公開しているソフトウェアの解説 ( その 1 )



今後複数回にわたり Google がオープンソースとして公開しているソフトウェアの紹介をしていきます。
第一弾はコマンドラインの解析ライブラリ google-gflags です。

このライブラリは実際に Google 社内で一般的に使われており、入社したエンジニアがまず最初に覚える Google インフラストラクチャーの1つです。


% foo --big_menu --language japanese


この場合、--big_menu や --language japanese がコマンドラインフラグに相当します。--big_menu は引数を取らないコマンドライン、--language は japanese という引数を取ります。

google-gflagsは getopt といった既存のライブラリと設計もそのユースケースも大きく異なります。

getopt の場合、次のようにコマンドラインの一覧を一箇所に ( 通常はmainで ) 一元管理します。


int main(int argc, char **argv) {
int opt;
extern char *optarg;
bool big_menu = false; std::string language;
while ((opt = getopt(argc, argv, "bl:")) != -1) {
switch(opt) {
case 'b':
big_menu = true; break;
case 'l':
language = optarg; break;
...
}


小規模のソフトウェアであればこのやり方で問題ないでしょう。しかし、何千ものエンジニアが複数のライブラリを独立に開発している状況 ( たとえば Google 社内 ) ではスケールしなくなってきます。自分のライブラリが複数のシステムで使われている場合、個々のシステムの main に自分のフラグを追加する必要があります。また、コマンドライン変数を各ライブラリから参照できるようにするために、big_menu や language をグローバル変数にしないといけません。

google-gflags では、コマンドラインフラグを個々のソースコード中に分散して管理します。個々のオブジェクトにコマンドラインの変数が格納され、そのオブジェクトをリンクした実行バイナリでそのコマンドラインが使えるようになります。

使い方はいたって簡単です。google/gflags.h をインクルードし、マクロを使ってコマンドラインを定義します。

-- foo.cc --


#include "google/gflags.h"

DEFINE_bool(big_menu, true,
"Include 'advanced' options in the menu listing");
DEFINE_string(language, "japanese", "default language");


DEFINE_bool は boolean のフラグを定義しています。他にも次に挙げるような型を定義することができます。

* DEFINE_bool: boolean
* DEFINE_int32: 32-bit integer
* DEFINE_int64: 64-bit integer
* DEFINE_uint64: 64-bit unsigned integer
* DEFINE_double: double
* DEFINE_string: C++ std::string

DEFINE マクロには 3 つの引数がありそれぞれ

* 第 1 引数: コマンドラインフラグの名前
* 第 2 引数: デフォルト値
* 第 3 引数: コマンドラインフラグのデスクリプション ( --help オプションのときに表示される解説文 ) となっています。

定義されたフラグは、FLAGS というプレフィックスがついた通常の変数となります。


void Foo() {
if (FLAGS_big_menu) { .. }
if (FLAGS_language == "japanese") { .. }
}


通常 DEFINE マクロで定義された変数は、そのソースファイルの中からのみ参照できます。他のファイルから参照したい場合は、DECLARE マクロを使います。

次の例では、bar.cc で big_menu コマンドラインフラグを強制的に true にし、 foo.cc 中に定義されている関数 Foo を呼び出しています。

-- bar.cc


DECLARE_bool(big_menu);

void Bar() {
FLAGS_big_menu = true;
Foo();
}


最後に main にコマンドラインを実際に解析するための関数 ( ParseCommandLineFlags ) を追加します。複数のファイルに独立して定義されているコマンドラインフラグに値がセットされます。


int main (int argc, char **argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
..
}


Google のほとんどすべてのバイナリは main でこの関数を呼んでいるため、自分の編集しているソースコードに必要なフラグを追加するだけでそのフラグが使用可能となります。main をそのつど編集する必要は原則ありません。

google-gflags にはフラグをファイルや環境変数から読み込んだり、--help ( ヘルプ ) 出力を自動的に作成するといった便利な機能があります。詳細はドキュメントをご覧ください。

社内のエンジニアは自分のアイデアを実験的に追加する目的で google-gflags を使っています。
現在の動作をちょっとかえてみたいときは、適当なフラグを挿入し、main をいじることなくソースの該当部分の動作をきりかえるだけで実現できます。デバッグや 20% プロジェクトに欠かせない機能の 1 つです。