cxxopts
軽量なC++オプションパーサーライブラリ。POSIX構文をサポートし、ヘッダーオンリーで使いやすい設計です。
フレームワーク
cxxopts
概要
cxxoptsは、軽量なC++オプションパーサーライブラリです。POSIX構文をサポートし、ヘッダーオンリーで使いやすい設計が特徴です。シンプルさと移植性を重視する開発者に支持されており、多くのオープンソースプロジェクトで採用されています。
詳細
cxxoptsはモダンなC++11以降に対応し、最小限の依存関係でコマンドライン引数の解析を行います。GNU getoptライクなAPIを提供しながら、C++らしい型安全性と使いやすさを実現しています。
主な特徴
- ヘッダーオンリー: 単一のヘッダーファイルをインクルードするだけで使用可能
- 軽量設計: 最小限のコードでコマンドライン解析を実現
- POSIX準拠: GNU getoptと互換性のある構文をサポート
- 型安全: C++の型システムを活用した安全な引数処理
- 自動ヘルプ生成: オプション定義から自動的にヘルプメッセージを生成
- 例外ベース: エラー処理に例外を使用した明確なエラーハンドリング
- C++11対応: モダンなC++機能を活用しつつ、幅広い環境で動作
メリット・デメリット
メリット
- 簡単な導入: ヘッダーオンリーで依存関係が最小限
- 軽量: オーバーヘッドが少なく高速動作
- 親しみやすいAPI: GNU getoptに慣れた開発者には直感的
- 型安全: コンパイル時に型チェックが行われる
- 移植性: 様々なプラットフォームで動作
- 最小限の学習コスト: シンプルなAPIで習得が容易
デメリット
- 機能の制約: 高度な機能は他のライブラリに劣る
- サブコマンド未対応: 複雑なCLIアプリケーションには不向き
- 設定ファイル非対応: 外部設定ファイルの読み込み機能なし
- カスタマイズ性: ヘルプフォーマットなどのカスタマイズが限定的
主要リンク
書き方の例
基本的な使用例
#include <cxxopts.hpp>
#include <iostream>
int main(int argc, char* argv[]) {
cxxopts::Options options("MyApp", "シンプルなコマンドラインアプリケーション");
options.add_options()
("f,file", "処理するファイル名", cxxopts::value<std::string>()->default_value("default.txt"))
("v,verbose", "詳細な出力", cxxopts::value<bool>()->default_value("false"))
("h,help", "ヘルプを表示");
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
return 0;
}
auto filename = result["file"].as<std::string>();
auto verbose = result["verbose"].as<bool>();
std::cout << "処理ファイル: " << filename << std::endl;
if (verbose) {
std::cout << "詳細モードが有効です" << std::endl;
}
return 0;
}
複数の引数型を扱う例
#include <cxxopts.hpp>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
cxxopts::Options options("DataProcessor", "データ処理ツール");
options.add_options()
("i,input", "入力ファイル", cxxopts::value<std::vector<std::string>>())
("o,output", "出力ファイル", cxxopts::value<std::string>())
("t,threads", "スレッド数", cxxopts::value<int>()->default_value("1"))
("r,recursive", "再帰処理", cxxopts::value<bool>()->default_value("false"))
("f,format", "出力形式", cxxopts::value<std::string>()->default_value("json"))
("h,help", "ヘルプを表示");
try {
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
return 0;
}
if (result.count("input")) {
auto inputs = result["input"].as<std::vector<std::string>>();
std::cout << "入力ファイル:" << std::endl;
for (const auto& file : inputs) {
std::cout << " - " << file << std::endl;
}
}
if (result.count("output")) {
auto output = result["output"].as<std::string>();
std::cout << "出力ファイル: " << output << std::endl;
}
auto threads = result["threads"].as<int>();
auto recursive = result["recursive"].as<bool>();
auto format = result["format"].as<std::string>();
std::cout << "スレッド数: " << threads << std::endl;
std::cout << "再帰処理: " << (recursive ? "有効" : "無効") << std::endl;
std::cout << "出力形式: " << format << std::endl;
} catch (const cxxopts::OptionException& e) {
std::cout << "エラー: " << e.what() << std::endl;
return 1;
}
return 0;
}
位置引数を含む例
#include <cxxopts.hpp>
#include <iostream>
int main(int argc, char* argv[]) {
cxxopts::Options options("FileUtil", "ファイルユーティリティ");
options.add_options()
("c,command", "実行するコマンド", cxxopts::value<std::string>())
("v,verbose", "詳細出力")
("d,dry-run", "実際には実行せずに表示のみ")
("h,help", "ヘルプを表示");
// 位置引数を設定
options.parse_positional({"command"});
options.positional_help("COMMAND [OPTIONS]");
try {
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
return 0;
}
if (!result.count("command")) {
std::cout << "エラー: コマンドが指定されていません" << std::endl;
std::cout << options.help() << std::endl;
return 1;
}
auto command = result["command"].as<std::string>();
auto verbose = result.count("verbose") > 0;
auto dry_run = result.count("dry-run") > 0;
std::cout << "実行コマンド: " << command << std::endl;
if (verbose) {
std::cout << "詳細モード: 有効" << std::endl;
}
if (dry_run) {
std::cout << "ドライランモード: 有効(実際には実行されません)" << std::endl;
}
// コマンド実行ロジック
if (command == "list") {
std::cout << "ファイル一覧を表示中..." << std::endl;
} else if (command == "clean") {
std::cout << "クリーンアップ実行中..." << std::endl;
} else {
std::cout << "不明なコマンド: " << command << std::endl;
return 1;
}
} catch (const cxxopts::OptionException& e) {
std::cout << "オプション解析エラー: " << e.what() << std::endl;
return 1;
}
return 0;
}
エラーハンドリングの例
#include <cxxopts.hpp>
#include <iostream>
int main(int argc, char* argv[]) {
cxxopts::Options options("SecureApp", "セキュアなアプリケーション");
options.add_options()
("u,user", "ユーザー名", cxxopts::value<std::string>())
("p,port", "ポート番号", cxxopts::value<int>())
("s,ssl", "SSL接続を使用")
("t,timeout", "タイムアウト(秒)", cxxopts::value<int>()->default_value("30"))
("h,help", "ヘルプを表示");
try {
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
return 0;
}
// 必須パラメータのチェック
if (!result.count("user")) {
throw cxxopts::OptionException("ユーザー名が必要です");
}
if (!result.count("port")) {
throw cxxopts::OptionException("ポート番号が必要です");
}
auto user = result["user"].as<std::string>();
auto port = result["port"].as<int>();
auto ssl = result.count("ssl") > 0;
auto timeout = result["timeout"].as<int>();
// 値の検証
if (port < 1 || port > 65535) {
throw cxxopts::OptionException("ポート番号は1-65535の範囲である必要があります");
}
if (timeout <= 0) {
throw cxxopts::OptionException("タイムアウトは正の値である必要があります");
}
std::cout << "接続設定:" << std::endl;
std::cout << " ユーザー: " << user << std::endl;
std::cout << " ポート: " << port << std::endl;
std::cout << " SSL: " << (ssl ? "有効" : "無効") << std::endl;
std::cout << " タイムアウト: " << timeout << "秒" << std::endl;
} catch (const cxxopts::OptionException& e) {
std::cerr << "エラー: " << e.what() << std::endl;
std::cerr << std::endl << options.help() << std::endl;
return 1;
} catch (const cxxopts::argument_incorrect_type& e) {
std::cerr << "型エラー: " << e.what() << std::endl;
return 1;
} catch (const std::exception& e) {
std::cerr << "予期しないエラー: " << e.what() << std::endl;
return 1;
}
return 0;
}
CMakeでの使用例
# CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(MyCxxoptsApp)
# cxxoptsを取得(FetchContentを使用)
include(FetchContent)
FetchContent_Declare(
cxxopts
GIT_REPOSITORY https://github.com/jarro2783/cxxopts.git
GIT_TAG v3.1.1
)
FetchContent_MakeAvailable(cxxopts)
add_executable(my_app main.cpp)
target_link_libraries(my_app cxxopts::cxxopts)
target_compile_features(my_app PRIVATE cxx_std_11)