パスワードを忘れた? アカウント作成
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ファイルの値とコマンドラインの値が マージされている。

494123 journal

yhtの日記: boost.program_option~2

日記 by yht

前のboost::program_option~1ではコマンドライン・オプションを読み込む簡単な例を見たが, オプションにデフォルト値を与えたり、色々な型のオプションを使えたりすると便利なので、 ちょっとした応用編。

例によって、boost.orgのドキュメントを参照の事。この例の全ソースはlibs/program_options/example/options_description.cpp

以下は、直訳・意訳・妄想・実験結果等。

前回と同様、

#include <boost/program_options.hpp>

using namespace boost;
namespace po = boost::program_options;

#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;

とお約束から始まる。

次に、前回と同様にpo::options_descriptionクラスの変数を用意してサポートするオプションを登録してゆくのだが、今回は少し変えてある。

  int opt;
  po::options_description desc("Allowed options");
    desc.add_options()
      ("help", "produce help message")
      ("optimization", po::value<int>(&opt)->default_value(10), "optimization level")
      ("include-path,I", po::value< vector<string> >(), "include path")
      ("input-file", po::value< vector<string> >(), "input file");

「help」オプションは、前回と同じ。どんな場合でもこのオプションを加えておくのがよい。

「optimization」オプションは、前回の「compression」と次の2点で異なる。
1. 変数のアドレス(&opt)を指定している。この変数の中にオプションの値が入っていく。
2. ユーザーが指定しなかった場合のオプションのデフォルト値10を指定している。

「include-path」オプションはinclude pathをコマンドラインから読み込み(複数可)、 std::vector<std::string>に入れる。別名として、短縮形「-I」でも受け付ける。 また、options_descriptionクラスのインターフェースが一つのソース(コマンドライン)だけ から読み込む唯一の例になっている。

「input-file」オプションは、処理すべきファイルのリストで、

compiler --input-file=a.cpp

というように使うことになり、

compiler a.cpp

という標準的な使い方と比べると少し変だが、初めてだからよいだろう。

上の例のように、オプションの名前の無いコマンドライン・トークンを、 このライブラリでは``positional options''と呼び、この種類のものも 読み込む事が出来る。ユーザーの若干の骨折りで、``a.cpp'' が ``--input-file=a.cpp''であることをライブラリに教えてやればよい。 その為に必要なコードは

  po::positional_options_description p;
  p.add("input-file", -1);

  po::variables_map vm;
  po::store(po::command_line_parser(ac, av).
    options(desc).positional(p).run(), vm);
  po::notify(vm);

の最初の2行。後半4行でコマンドラインからvmへオプションを読み込んでいる。 前回はpo::parse_command_line()函数で読み込んだ(簡素な読み込みルールの場合は こちらが便利)が、より詳しい情報をやり取りする必要があり、po::command_line_parser クラスを利用する。

これでオプションの読み込みが済んだので、コンパイラの実装は省略し、オプションの 表示のみをする。

  if (vm.count("help")) {
    cout << "Usage: options_description [options]\n";
    cout << desc;
    return 0;
  }

  if (vm.count("include-path"))
  {
    cout << "Include paths are: "
      << vm["include-path"].as< vector<string> >() << "\n";
  }

  if (vm.count("input-file"))
  {
    cout << "Input files are: "
      << vm["input-file"].as< vector<string> >() << "\n";
  }

  cout << "Optimization level is " << opt << "\n";

必要なコードは実装したので、コンパイルと実行。

%g++ -o odesc -O2 options_description.cpp -lboost_program_options-mt
%

でコンパイル。-lboost_program_optionsでもよい。

%./odesc --help
Usage: options_description [options]
Allowed options:
  --help                    produce help message
  --optimization arg (=10)  optimization level
  -I [ --include-path ] arg include path
  --input-file arg          input file
%./odesc -I /usr/local/include a.cpp
Include paths are: /usr/local/include
Input files are: a.cpp
Optimization level is 10
%./odesc -I /usr/local/include a.cpp --optimization 15
Include paths are: /usr/local/include
Input files are: a.cpp
Optimization level is 15
%

さて、上の例でまだちょっとした問題が残っている。 それは``--input-file''オプションを指定できることと、表示されていること。 オプションを隠すのは次の例まで待ってほしい。

494205 journal

yhtの日記: boost.program_option~1

日記 by yht

シミュレーション等のコードを書いていると,オプションで実行時に与えたい パラメーターが徐々に増えていって、ファイルから読み込ませたくなるが、 手頃な(ライセンスや移植性等の点で)となると案外悩むところ。 一回書いてしまえば使いまわすだけなので、暇な時の悩みではあるが。

gcc-4.2でboostのコンパイル・インストールがどうも上手く出来ないので、 boost関係を調べていてBoost::program_optionsなるライブラリを見つけた (いつの間に入った!)ので、忘れないようにメモをば。

オリジナルはboost.orgのドキュメントなので、要参照。

例題
簡単の為 namespaceのaliasを

namespace po = boost::program_options;

として定義する。
最初の例は、二つしかないオプションを読み込むもの(全ソースはexample/first.cpp)。
最初に

#include<boost/program_options.hpp>
namespace po = boost::program_options;

として、後は必要に応じて

#include<iostream>
#include<iterator>>
using namespace std;

等といつもの通りに加える。

originalはtry-catchで例外処理をしているので、first.cppを見るとして、 簡単の為例外処理は省く。

まずサポートするオプションを宣言するため、

po::options_description desc("Allowed options");
desc.add_options()
    ("help","produce help message")
    ("compression",po::value<int>(),"set compression level");

と幾つかの変数を定義する。 可能なオプションの集合は options_descriptionクラスで定義される。 こいつのadd_options()メソッドが、()演算子を定義していて,()演算子が 実際にオプションの追加作業を担う。この例では、「help」という名のオプションは、 値がなく、「compression」というオプションはint型の値を持つ。

次にコマンドラインからの読み込みを

po::variables_map vm;
po::store(po::parse_command_line(argc,argv,desc),vm);
po::notify(vm);

により行う。 初めにvariables_mapクラスの変数を定義する。このクラスは任意の型のオプションを補完しておく為のものである。次に store,parse_command_line,notify函数によりvmにオプション(オプションの種類とその値)が格納されるであろう。

読み込んだらオプションを順番に評価していく。

if(vm.count("help")) {
  cout << desc << "\n";
  return 1;
}

if(vm.count("compression")) {
  cout << "Compression level was set to "
   << vm["compression"].as<int>() << ".\n";
} else {
  cout << "Compression level was not set.\n";
}

variables_mapクラスは、std::mapと同じように使う事が出来るが、 オプションの値は上記のようにasメソッドで取り出さなければならない点が異なる。

これにてオプションの評価が終わり、初期化等が始まるが、 このfirst.cppはオプションを読み込む例なので、読み込んだオプションを 表示して終了する。

コンパイルは

g++ -o first -O2 first.cpp -lboost_program_options
g++ -o first -O2 first.cpp -lboost_program_options-mt

等と,必要なライブラリをリンクする必要がある(実行環境はgcc-4.1.2,boost-1.33.1 on amd64)。後はいつもと同じ。

実行例は

%./first
Compression level was not set.
%./first --help
Allowed options:
  --help                produce help message
  --compression arg     set compression level

%./first --compression 15
Compression level was set to 15.
%

と、「--オプション名 値」でオプションを与える。 この続きは次の巻にあるべし。

497111 journal

yhtの日記: mpich2

日記 by yht
今まで遊んでいた数値計算のプログラムを、並列化しようと思ってwebを漁っていたら、
OpenMPとMPIというのが流行らしいことが分かった。
OpenMPは私が昔posix threadでループを分割して処理させていたのを半自動化させるものらしい。
IntelのFortran compilerではサポートされ、GCCも来る4.2からはサポートされるとのこと。
MPIはクラスターで計算させるとき等、独立なプロセスをプロセス間通信で繋いで分散計算を実現する
という他は、非同期に実行し、時々同期するという点ではマルチ・スレッドのプログラムに似ているか。
通信のコストが馬鹿にならないので、賢い領域分割が必要らしい。
昔、Lattice QCD計算をしている人に聞いたらMPIは使っていないと言っていたけれども、
その手の最適化は後日気が向いたらやるとして、まずは分散計算の練習をしてみる。
それで、必要となるMPIの実装だが、色々とあるようである。
mpich1,mpich2,lam/mpi,openmpi等々。
大した理由はないが、mpich2を以下のconfigurationでコンパイル・インストールした。
./configure --prefix=${HOME}/local --enable-f77 --enable-f90 --enable-cxx --enable-romio --enable-mpe
後は~/.mpd.confと~/.mpd.hostsを適当に設定してインストールはお終い。
497602 journal

yhtの日記: boostのコンパイル

日記 by yht
長年愛用していたキーボードの一部のキーが反応しなくなってきたので一念発起して HappyHackingLight2に替える。
結果、机が少し広くなった。次は液晶画面か。
久しぶりに家のサーバーの中のC++環境を更新すべく、boost-1.33.1をダウンロードして コンパイルした。
コンパイルは終わって、うっかりmake checkなんてやったのが大失敗。
半日経ってもまだ終わらない(PentiumII-400MHz,PC100-768MB)。
---
半日は言い過ぎだったけれども、12-13時間かかっているようだ。 templateは時間がかかるなぁ。
typodupeerror

Stableって古いって意味だっけ? -- Debian初級

読み込み中...