yhtの日記: boost.program_option~3
boost::program_option~1_2の続き。
Multiple Sourcesの例
例によって、boost.orgのドキュメントを参照の事。この例の全ソースはlibs/program_options/example/multiple_sources.cpp
以下は、直訳・意訳・妄想・実験結果等。
ユーザーにとって、を全てコマンドラインで指定するのは面倒なもの。 もしユーザーが新しいライブラリをインストールし,(利用するために)毎回 新たなオプションを加えたいと望んだらどうだろう。 そんなとき、コマンドラインと共に使るような、コンフィグファイルに共通の 設定を書いておくのが望ましい。
そして、configファイルでの値をコマンドライン指定で上書きできる方がよいし、 一方でinclude pathsはconfigファイルの値とコマンドライン指定のorを取りたい。
早速、コードを見るとしよう。まず、
#include <boost/program_options.hpp>
namespace po = boost::program_options;
#include <iostream>
#include <fstream>
#include <iterator>
using namespace std;
というお約束と、便宜上のvector用のostreamの<<演算子の定義
// A helper function to simplify the main part.
template<class T>
ostream& operator<<(ostream& os, const vector<T>& v)
{
copy(v.begin(), v.end(), ostream_iterator<T>(cout, " "));
return os;
}
をしておく。 次に、幾つかのoptions_descriptionsクラスの変数を宣言する。 複数の変数を宣言する理由は,或るオプション("input-file") はhelpメッセージで表示されて欲しくないし、或るオプションは configファイルの中でのみ意味をなすし、それに 長大なオプションのリストを表示するだけででなく、ヘルプメッセージ の中にも何か構造がある方がよい。 そこで、幾つかのオプション群を宣言する:
int opt;
// Declare a group of options that will be
// allowed only on command line
po::options_description generic("Generic options");
generic.add_options()
("version,v", "print version string")
("help", "produce help message");
// Declare a group of options that will be
// allowed both on command line and in
// config file
po::options_description config("Configuration");
config.add_options()
("optimization", po::value<int>(&opt)->default_value(10), "optimization level")
("include-path,I", po::value< vector<string> >()->composing(), "include path");
// Hidden options, will be allowed both on command line and
// in config file, but will not be shown to the user.
po::options_description hidden("Hidden options");
hidden.add_options()
("input-file", po::value< vector<string> >(), "input file") ;
ここで、``include-path''オプションの宣言の中にあるcomposingメソッドに注目されたい。composingメソッドは、ライブラリーに異なるソースからの値を組み合わせるように伝えている。
そして、実際に複数のオプション群を組み合わせるのは
po::options_description cmdline_options;
cmdline_options.add(generic).add(config).add(hidden);
po::options_description config_file_options;
config_file_options.add(config).add(hidden);
po::options_description visible("Allowed options");
visible.add(generic).add(config);
にあるように、options_descriptionクラスのaddメソッドを用いる。
前回と同じく、
po::positional_options_description p;
p.add("input-file", -1);
として名無しのオプションは``input-file''だと教えておく。
後は実際にファイル・コマンドラインからオプションを読んで 適当な変数に格納するだけなので、大体前と同じ。
po::variables_map vm;
store(po::command_line_parser(ac, av).
options(cmdline_options).positional(p).run(), vm);
ifstream ifs("multiple_sources.cfg");
store(parse_config_file(ifs, config_file_options), vm);
notify(vm);
前回と比べて、新たにparse_config_fileを呼び出し、 store函数を二度呼び出している。
コマンドラインとconfigファイルの両方で同じ種類のオプションを 指定したらどうなるだろうか。 通常は初めに格納された方が優先される。 ``--optimization''オプションがこれに当てはまる。 ``composing''したオプション(``include-file''等)では、値はマージ される。
最後に実行例。まずコンパイル
%g++ -c -o ms.o -O2 -frepo multiple_sources.cpp
%g++ -o ms ms.o -lboost_program_options
collect: multiple_sources.cpp を再コンパイルします
collect: 再リンクします
collect: multiple_sources.cpp を再コンパイルします
collect: 再リンクします
collect: multiple_sources.cpp を再コンパイルします
collect: 再リンクします
collect: multiple_sources.cpp を再コンパイルします
collect: 再リンクします
collect: multiple_sources.cpp を再コンパイルします
collect: 再リンクします
collect: multiple_sources.cpp を再コンパイルします
collect: 再リンクします
collect: multiple_sources.cpp を再コンパイルします
collect: 再リンクします
collect: multiple_sources.cpp を再コンパイルします
collect: 再リンクします
%
して(-frepo付けて、8回も再コンパイルするとは思わなかった)、 実行すると...
%./ms --help
Allowed options:
Generic options:
-v [ --version ] print version string
--help produce help message
Configuration:
--optimization arg (=10) optimization level
-I [ --include-path ] arg include path
%./ms --optimization=4 -I /usr/local/include a.cpp b.cpp
Include paths are: /usr/local/include /opt
Input files are: a.cpp b.cpp
Optimization level is 4
%
%cat multiple_sources.cfg
#
# Comment out this line to use hard-coded default value of 10
#
optimization = 1
include-path = /opt
optimizationオプションはソースの中ではデフォルト値10が、 configファイルの中では1が、コマンドラインでは4が指定されているが、 コマンドラインでの値4が優先されているのが分かる。
一方で、include pathsはconfigファイルの値とコマンドラインの値が マージされている。