【C++】开源:命令行解析库CLI11配置与使用

发布于:2024-07-04 ⋅ 阅读:(17) ⋅ 点赞:(0)

😏★,°:.☆( ̄▽ ̄)/$:.°★ 😏
这篇文章主要介绍命令行解析库CLI11配置与使用。
无专精则不能成,无涉猎则不能通。——梁启超
欢迎来到我的博客,一起学习,共同进步。
喜欢的朋友可以关注一下,下次更新不迷路🥞

😏1. 项目介绍

项目Github地址:https://github.com/CLIUtils/CLI11

看到一位朋友的评论,说平时命令行解析库用CLI11的多,这里来学习一下。

CLI11 是一个用于处理命令行参数和选项的 C++ 库,旨在简化 C++ 应用程序的命令行界面开发。

主要特点:

1.简单易用:CLI11 的设计目标之一是提供一个简单且直观的 API,使开发者能够轻松地定义和解析命令行选项。

2.现代 C++ 支持:CLI11 充分利用了现代 C++ 的特性,包括类型推导、lambda 表达式等,使其在语法上更为优雅和灵活。

3.丰富的选项支持:支持多种命令行选项,包括标志选项(flags)、位置参数、可选参数、必选参数等,可以方便地定义各种复杂的命令行接口。

4.类型安全:CLI11 在解析和处理命令行参数时,提供了类型安全的机制,避免了常见的类型转换错误。

5.灵活的错误处理:提供了多种错误处理方式,包括参数验证失败时的错误提示、帮助信息的自动生成等。

6.跨平台支持:CLI11 可以在主流的操作系统上运行,包括 Windows、macOS 和各种 Linux 发行版,确保了跨平台的兼容性。

😊2. 环境配置

ubuntu源码安装CLI11库:

git clone https://github.com/CLIUtils/CLI11.git
mkdir build & cd build
cmake ..
make
sudo make install

程序g++编译(不用加-lCLI11):g++ -o main main.cpp

😆3. 使用说明

下面是一个解析命令行的示例:

#include <CLI/CLI.hpp>
#include <iostream>

int main(int argc, char **argv) {
    CLI::App app{"CLI11 example"};

    std::string name;
    app.add_option("-n,--name", name, "Your name")->required();

    CLI11_PARSE(app, argc, argv);

    std::cout << "Hello, " << name << "!" << std::endl;

    return 0;
}

官方还给出了一些示例,如通过命令行检查(如文件、数字范围):

// Copyright (c) 2017-2024, University of Cincinnati, developed by Henry Schreiner
// under NSF AWARD 1414736 and by the respective contributors.
// All rights reserved.
//
// SPDX-License-Identifier: BSD-3-Clause

#include <CLI/CLI.hpp>
#include <iostream>
#include <string>

int main(int argc, char **argv) {

    CLI::App app("Validator checker");

    std::string file;
    app.add_option("-f,--file,file", file, "File name")->check(CLI::ExistingFile);

    int count{0};
    app.add_option("-v,--value", count, "Value in range")->check(CLI::Range(3, 6));
    CLI11_PARSE(app, argc, argv);

    return 0;
}

此外还可以和json库一起使用:

// Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner
// under NSF AWARD 1414736 and by the respective contributors.
// All rights reserved.
//
// SPDX-License-Identifier: BSD-3-Clause

#include <CLI/CLI.hpp>
#include <iostream>
#include <memory>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>

// This example is only built on GCC 7 on Travis due to mismatch in stdlib
// for clang (CLI11 is forgiving about mismatches, json.hpp is not)

using nlohmann::json;

class ConfigJSON : public CLI::Config {
  public:
    std::string to_config(const CLI::App *app, bool default_also, bool, std::string) const override {

        json j;

        for(const CLI::Option *opt : app->get_options({})) {

            // Only process option with a long-name and configurable
            if(!opt->get_lnames().empty() && opt->get_configurable()) {
                std::string name = opt->get_lnames()[0];

                // Non-flags
                if(opt->get_type_size() != 0) {

                    // If the option was found on command line
                    if(opt->count() == 1)
                        j[name] = opt->results().at(0);
                    else if(opt->count() > 1)
                        j[name] = opt->results();

                    // If the option has a default and is requested by optional argument
                    else if(default_also && !opt->get_default_str().empty())
                        j[name] = opt->get_default_str();

                    // Flag, one passed
                } else if(opt->count() == 1) {
                    j[name] = true;

                    // Flag, multiple passed
                } else if(opt->count() > 1) {
                    j[name] = opt->count();

                    // Flag, not present
                } else if(opt->count() == 0 && default_also) {
                    j[name] = false;
                }
            }
        }

        for(const CLI::App *subcom : app->get_subcommands({}))
            j[subcom->get_name()] = json(to_config(subcom, default_also, false, ""));

        return j.dump(4);
    }

    std::vector<CLI::ConfigItem> from_config(std::istream &input) const override {
        json j;
        input >> j;
        return _from_config(j);
    }

    std::vector<CLI::ConfigItem>
    _from_config(json j, std::string name = "", std::vector<std::string> prefix = {}) const {
        std::vector<CLI::ConfigItem> results;

        if(j.is_object()) {
            for(json::iterator item = j.begin(); item != j.end(); ++item) {
                auto copy_prefix = prefix;
                if(!name.empty())
                    copy_prefix.push_back(name);
                auto sub_results = _from_config(*item, item.key(), copy_prefix);
                results.insert(results.end(), sub_results.begin(), sub_results.end());
            }
        } else if(!name.empty()) {
            results.emplace_back();
            CLI::ConfigItem &res = results.back();
            res.name = name;
            res.parents = prefix;
            if(j.is_boolean()) {
                res.inputs = {j.get<bool>() ? "true" : "false"};
            } else if(j.is_number()) {
                std::stringstream ss;
                ss << j.get<double>();
                res.inputs = {ss.str()};
            } else if(j.is_string()) {
                res.inputs = {j.get<std::string>()};
            } else if(j.is_array()) {
                for(std::string ival : j)
                    res.inputs.push_back(ival);
            } else {
                throw CLI::ConversionError("Failed to convert " + name);
            }
        } else {
            throw CLI::ConversionError("You must make all top level values objects in json!");
        }

        return results;
    }
};

int main(int argc, char **argv) {
    CLI::App app;
    app.config_formatter(std::make_shared<ConfigJSON>());

    int item;

    app.add_flag("--simple");
    app.add_option("--item", item);
    app.set_config("--config");

    CLI11_PARSE(app, argc, argv);

    std::cout << app.config_to_str(true, true) << std::endl;
}

在这里插入图片描述

以上。