パスワードを忘れた? アカウント作成
494122 journal

yhtの日記: boost.program_option~3

日記 by yht

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ファイルの値とコマンドラインの値が マージされている。

typodupeerror

コンピュータは旧約聖書の神に似ている、規則は多く、慈悲は無い -- Joseph Campbell

読み込み中...