CLI11 — 命令行解析
CLI11 是现代 C++ 命令行解析库,单头文件,支持子命令、自动帮助生成、类型安全,是 Boost.Program_options 的现代替代。
安装
bash
# 单头文件
# 下载 CLI11.hpp:https://github.com/CLIUtils/CLI11/releases
# vcpkg
vcpkg install cli11
# CMake FetchContent
FetchContent_Declare(CLI11
GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git
GIT_TAG v2.4.1)
FetchContent_MakeAvailable(CLI11)
target_link_libraries(myapp PRIVATE CLI11::CLI11)基本用法
cpp
#include <CLI/CLI.hpp>
int main(int argc, char** argv) {
CLI::App app{"我的工具", "mytool"};
app.set_version_flag("--version", "1.0.0");
// 选项(有默认值)
std::string host = "localhost";
int port = 8080;
bool verbose = false;
app.add_option("-H,--host", host, "服务器地址")->envname("APP_HOST");
app.add_option("-p,--port", port, "端口号")->check(CLI::Range(1, 65535));
app.add_flag("-v,--verbose", verbose, "详细输出");
// 必填参数
std::string input_file;
app.add_option("input", input_file, "输入文件")->required()->check(CLI::ExistingFile);
// 解析
CLI11_PARSE(app, argc, argv); // 失败时自动打印帮助并退出
std::cout << "连接到 " << host << ":" << port << "\n";
if (verbose) std::cout << "详细模式开启\n";
return 0;
}bash
# 自动生成的帮助
./mytool --help
# 我的工具
# Usage: mytool [OPTIONS] input
# Positionals:
# input TEXT:FILE REQUIRED 输入文件
# Options:
# -h,--help Print this help message and exit
# --version Display program version information and exit
# -H,--host TEXT [localhost] 服务器地址
# -p,--port INT:INT in [1 - 65535] [8080] 端口号
# -v,--verbose 详细输出多值选项
cpp
// 接受多个值
std::vector<std::string> files;
app.add_option("-f,--files", files, "输入文件列表")->expected(1, -1); // 1到多个
// 固定数量
std::vector<int> coords;
app.add_option("--coords", coords, "坐标 x y")->expected(2);
// 键值对
std::map<std::string, std::string> env_vars;
app.add_option("-e,--env", env_vars, "环境变量 KEY=VALUE");
// 使用
./mytool -f a.txt b.txt c.txt
./mytool --coords 10 20
./mytool -e KEY1=val1 -e KEY2=val2子命令
cpp
CLI::App app{"Git 风格工具"};
// 子命令
auto* add_cmd = app.add_subcommand("add", "添加文件");
auto* commit_cmd = app.add_subcommand("commit", "提交更改");
auto* push_cmd = app.add_subcommand("push", "推送到远程");
// 子命令的选项
std::vector<std::string> add_files;
add_cmd->add_option("files", add_files, "要添加的文件")->required();
std::string commit_msg;
bool amend = false;
commit_cmd->add_option("-m,--message", commit_msg, "提交信息")->required();
commit_cmd->add_flag("--amend", amend, "修改上次提交");
std::string remote = "origin";
std::string branch = "main";
push_cmd->add_option("remote", remote, "远程名称");
push_cmd->add_option("branch", branch, "分支名称");
// 要求至少一个子命令
app.require_subcommand(1);
CLI11_PARSE(app, argc, argv);
if (add_cmd->parsed()) {
for (const auto& f : add_files) std::cout << "添加: " << f << "\n";
}
if (commit_cmd->parsed()) {
std::cout << "提交: " << commit_msg << "\n";
if (amend) std::cout << "(修改上次提交)\n";
}
if (push_cmd->parsed()) {
std::cout << "推送到 " << remote << "/" << branch << "\n";
}验证器
cpp
// 内置验证器
app.add_option("--file", file)->check(CLI::ExistingFile); // 文件必须存在
app.add_option("--dir", dir)->check(CLI::ExistingDirectory); // 目录必须存在
app.add_option("--out", out)->check(CLI::NonexistentPath); // 路径不能存在
app.add_option("--port", port)->check(CLI::Range(1, 65535)); // 数值范围
app.add_option("--level", level)->check(CLI::IsMember({"debug","info","warn","error"}));
// 自定义验证器
auto positive_validator = CLI::Validator(
[](const std::string& s) -> std::string {
int n = std::stoi(s);
if (n > 0) return ""; // 空字符串表示验证通过
return "必须是正整数"; // 返回错误信息
},
"正整数" // 类型描述
);
app.add_option("--count", count)->check(positive_validator);配置文件支持
cpp
// 支持从配置文件读取选项
app.set_config("--config", "config.ini", "配置文件路径");
// config.ini 格式:
// host=localhost
// port=8080
// verbose=true
// 命令行参数优先级高于配置文件关键认知
CLI11 的核心优势是零依赖、单头文件、自动帮助生成。子命令模式适合构建 git 风格的工具。内置验证器(ExistingFile、Range、IsMember)让参数验证变得简单。