コマンドラインパーサ(コマンドラインオプション解析器)
拙作ツールをコマンドラインオプション対応にしようと考えて、 既存のものをいろいろ探してみたのですが、私にとっては 帯に短したすきに長しで、しっくりくるものが無かったため、 自分で作ってしまいました。
https://github.com/trueroad/cmdlineparse
C++11 用で、ヘッダファイルひとつだけでできていますので、 インストール不要、簡単に使えます。 ご自分のプロジェクトへ cmdlineparse.hh をコピーして、 ドキュメント を参考にパーサを呼び出す処理を書いていただければ OK です。 ライセンスは 2 条項 BSD にしましたので、使っていただきやすいと思います。 また、GPL の方が良いという方向けに、 GPL 版も用意しています。
各種コマンドラインパーサ
最初は自分で実装するつもりはなくて、いくつか探してみました。 C++コマンドライン引数 は、非常に参考になりました。私の場合の条件としては、
- 長いオプションが使えること
--help
や--version
のようなものですね。 - C++ で使いやすいこと
Linux 界隈でも純粋な C 言語を使うことが少なくなってきていると思います。 - Autotools との相性がよいこと
Linux 界隈では必須かと思います。 - インストール不要
ソースを配布することになるので、 開発者ではない人でも簡単にビルドできるようにする必要があります。 多くの環境には入っていない「何か」をインストールしないとビルドできません、 というのは困ります。
あたりになります。
POSIX 標準
getopt ()
POSIX 標準だと getopt ()
があるのですが、
これだと長いオプションが使えません。
GNU 系
getopt_long ()
getopt ()
を、長いオプションを使えるように拡張したものが、
getopt_long ()
です。
基本的な解析の機能そのものは十分ですが C 言語ベースになります。
また、これには低レイヤの機能しかありませんし、
ヘルプメッセージの作成機能もありません。
gengetopt
getopt_long ()
を解析エンジンとして使い、
高レイヤの機能を持ちヘルプメッセージも作成できる、
gengetopt
があります。
面白いのは、あらかじめオプションやヘルプメッセージなどの定義ファイルを作り、
それを gengetopt で処理すると、
C 言語で書かれたコマンドラインパーサが生成される、
という構造になっているところです。
これを使うか、getopt_long ()
をそのまま使うか、
とも考えたのですが、結局 C 言語ベースになってしまうので、
C++ 的にはどうしても使いにくい、わかりにくい、という感触があります。
C++ が使えずに C で書かざるを得ない時には、最有力になると思います。
Argp
同じく GNU 系だと
Argp
というコマンドラインパーサがあって、
getopt_long ()
よりも高機能、ということのようですが、残念ながらこれも C 言語になります。
C++
boost::program_options
C++ ならこれが本命、かもしれない boost の boost::program_options です。 非常に良い、とは思うのですが、インストールしないと使えません。 非開発者向けはバイナリ配布がメインで、ソースは開発者向けです、 という場合であれば、あまり問題にならないのかもしれませんが、 非開発者向けもソース配布、ですと大きな問題です。 かなり寛容なライセンスなので、自分のソースに同梱してしまおうか、 とも考えたのですが、そうするとかなりサイズが大きくなってしまいます。
flags.hh
getopt ()
のラッパーで、C++ のインタフェースになっている
flags.hh
です。かなりよい、と思うのですが、内部で getopt_long ()
を使っているのが、なんとも。
C++ からは使いやすくなっていると思います。
ですが、getopt 系はグローバル変数を使っていたりするため、
複数同時に使ったりなどすると確実におかしくなってしまいます。
(複数同時なんて、やるわけないだろ、というはごもっともではあります。)
ラップしたことによって、うまく見えないようにしていると思うのですが、
結局、隠れているだけで解決したわけではありません。
cmdline
C++ 向け簡易コマンドラインパーザ (GitHub) です。 ヘッダファイル一つだけ、インストール不要、というところが素晴らしいです。 が、少々機能が乏しいように感じます。
実装
というわけで、結局自分で都合のいいように実装してしまいました。
基本的な解析の機能は getopt_long ()
の動作を参考に、
ほぼ準拠するような形で作ったつもりです。
ですので、一部省略した長いオプション
(例えば、本当のオプションは --help
だけど、短くした
--he
等でも認識する、といった機能)なども動作します。
ヘッダファイル一つだけ、インストール不要、という点については、
cmdline や flags.hh のコンセプトを踏襲したものです。
C++11 向け、としたのは、std::function
や
クロージャを使えばシンプルに実装できるのでは、と思い付いたからです。
でも、よく見てみると flags.hh は std::function
と
クロージャと、使っていますね。
また、私がかかわっている LilyPond
では、公式バイナリビルドシステム
GUB
は GCC 4.9 になっていますので、C++11 の利用は問題なかった、
というのも大きいです。