コマンドラインの解析

CodeZine / 2013年7月16日 14時0分

 前回のGDBM、コレ使ってコンフィギュレーション(設定情報)をファイルに保存し、次回起動時に復元する小さなアプリケーションを実装し開発チームにリリースしたところ、これがなかなか好評で、数日後新たなリクエストが寄せられました。生成されたコンフィギュレーション・ファイルをブラウズ/編集するコンソールアプリが欲しいんだそうな。キー/値のいずれも文字列ならば、さほどの手間はかからんだろうと引き受けました。

 コンソールアプリっていうからにはコマンドラインを解析し、与えられたオプションに基づいてそれに応じた処理を行わにゃなりません。簡単なものであれば:

list01
int main(int argc, char* argv[]) { vector<string> args(argv, argv+argc); if ( args.size() <= 1 ) { cerr << "no input file(s). --help to see the help." << endl; return 1; } if ( args[1] == "--help" ) { usage(); // '使い方'を出力 return 0; } if ( args[1] == .... ) ...
 みたいな"力技"でコマンドラインを解析するんですが、オプションが増えてくると力技では相当に面倒で複雑なコーディングを強いられます。

 コマンドラインを解析してくれるライブラリといえば、Cの世界ならgetopt()が有名どころですけど、今回はいつもなにかとお世話になっているBoostライブラリ群の中の一つ、program_optionsを使います。

■前準備:Boostをビルドする

 それではBoostのビルドから始めましょう。現時点での最新版1.54.0をダウンロードページから拾って適当なディレクトリに展開します(ここを<BOOST_ROOT>と表記します)。Windows/Visual C++であれば、コマンドプロンプト立ち上げて<BOOST_ROOT>に移動しbootstrap,続いてb2を実行すればBoostの提供する全ライブラリを片っ端からコンパイルし、<BOOST_ROOT>\stage\libに置いてくれます。生成されるライブラリはマルチスレッド・ランタイムDLL・Release/Debug(-MD/-MDd)です。

※1
 サンプル・プロジェクトをお試しの際は、環境変数BOOST_ROOTを設定してください。



■Boost.program_optionsのかんたんチュートリアル

 Boost.program_optionsによるコマンドライン解析は、

options_descriptionにオプションを記述して parserに(1)を食わせてコマンドラインを解析し (2)の結果をvariables_mapから取り出す というダンドリになります。

 簡単な例をいくつか紹介しましょう。例えば小さなコンパイラ:myccを作るとしましょうか。コマンドライン文法はこんなカンジで:

- mycc foo.c bar.c:foo.c,bar.cをコンパイルし実行形式を作る - mycc -O2 ... :最適化レベルを2にする(デフォルト値は0) - mycc -I../include ...:インクルード・パス設定(複数設定可) - mycc --help:ヘルプを出力する  いちばん単純な、オプションスイッチ(-,--から始まる識別子)に後続するオプション値を持たない(上記では--help)場合。

list02
#include <iostream> #include <boost/program_options.hpp> namespace po = boost::program_options; using namespace std; int main(int argc, char* argv[]) { try { // オプションを記述して po::options_description desc("オプションの説明"); desc.add_options() ("help,h" , "ヘルプの出力") ; // parserに食わせ po::command_line_parser parser(argc,argv); parser.options(desc); // 解析結果を variables_map に格納し po::variables_map vm; po::store(parser.run(), vm); po::notify(vm); // 結果を読み出す if ( vm.count("help") ) { cout << "mycc [option]... <input_file>... " << desc << endl; } return 0; } catch(exception& e) { cerr << "error: " << e.what() << " "; } catch(...) { cerr << "Exception of unknown type! "; } return 1; }


 variables_mapはstd::mapから導出されているので、count()メンバ関数で指定したオプションがコマンドラインに指定されたかを知ることができます。また、options_descriptionをストリームに<<するとヘルプが出てくる親切設計。



CodeZine

トピックスRSS

ランキング