CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface.

Overview

CLI11: Command line parser for C++11

CLI11 Logo

Build Status Linux and macOS Build Status Windows Build Status Azure Actions Status Code Coverage Codacy Badge Join the chat at https://gitter.im/CLI11gitter/Lobby License: BSD Latest release DOI Conan.io Try CLI11 1.9 online

What's newDocumentationAPI Reference

CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface.

Table of Contents

Features that were added in the last released major version are marked with " 🆕 ". Features only available in master are marked with " 🚧 ".

Background

Introduction

CLI11 provides all the features you expect in a powerful command line parser, with a beautiful, minimal syntax and no dependencies beyond C++11. It is header only, and comes in a single file form for easy inclusion in projects. It is easy to use for small projects, but powerful enough for complex command line projects, and can be customized for frameworks. It is tested on Travis, AppVeyor, Azure, and GitHub Actions, and is used by the GooFit GPU fitting framework. It was inspired by plumbum.cli for Python. CLI11 has a user friendly introduction in this README, a more in-depth tutorial GitBook, as well as API documentation generated by Travis. See the changelog or GitHub Releases for details for current and past releases. Also see the Version 1.0 post, Version 1.3 post, or Version 1.6 post for more information.

You can be notified when new releases are made by subscribing to https://github.com/CLIUtils/CLI11/releases.atom on an RSS reader, like Feedly, or use the releases mode of the GitHub watching tool.

Why write another CLI parser?

An acceptable CLI parser library should be all of the following:

  • Easy to include (i.e., header only, one file if possible, no external requirements).
  • Short, simple syntax: This is one of the main reasons to use a CLI parser, it should make variables from the command line nearly as easy to define as any other variables. If most of your program is hidden in CLI parsing, this is a problem for readability.
  • C++11 or better: Should work with GCC 4.8+ (default on CentOS/RHEL 7), Clang 3.4+, AppleClang 7+, NVCC 7.0+, or MSVC 2015+.
  • Work on Linux, macOS, and Windows.
  • Well tested using Travis (Linux) and AppVeyor (Windows) or Azure (all three). "Well" is defined as having good coverage measured by CodeCov.
  • Clear help printing.
  • Nice error messages.
  • Standard shell idioms supported naturally, like grouping flags, a positional separator, etc.
  • Easy to execute, with help, parse errors, etc. providing correct exit and details.
  • Easy to extend as part of a framework that provides "applications" to users.
  • Usable subcommand syntax, with support for multiple subcommands, nested subcommands, option groups, and optional fallthrough (explained later).
  • Ability to add a configuration file (ini or TOML 🆕 format), and produce it as well.
  • Produce real values that can be used directly in code, not something you have pay compute time to look up, for HPC applications.
  • Work with standard types, simple custom types, and extensible to exotic types.
  • Permissively licensed.

Other parsers

The major CLI parsers for C++ include, with my biased opinions: (click to expand)

Library My biased opinion
Boost Program Options A great library if you already depend on Boost, but its pre-C++11 syntax is really odd and setting up the correct call in the main function is poorly documented (and is nearly a page of code). A simple wrapper for the Boost library was originally developed, but was discarded as CLI11 became more powerful. The idea of capturing a value and setting it originated with Boost PO. See this comparison.
The Lean Mean C++ Option Parser One header file is great, but the syntax is atrocious, in my opinion. It was quite impractical to wrap the syntax or to use in a complex project. It seems to handle standard parsing quite well.
TCLAP The not-quite-standard command line parsing causes common shortcuts to fail. It also seems to be poorly supported, with only minimal bugfixes accepted. Header only, but in quite a few files. Has not managed to get enough support to move to GitHub yet. No subcommands. Produces wrapped values.
Cxxopts C++11, single file, and nice CMake support, but requires regex, therefore GCC 4.8 (CentOS 7 default) does not work. Syntax closely based on Boost PO, so not ideal but familiar.
DocOpt Completely different approach to program options in C++11, you write the docs and the interface is generated. Too fragile and specialized.

After I wrote this, I also found the following libraries:

Library My biased opinion
GFlags The Google Commandline Flags library. Uses macros heavily, and is limited in scope, missing things like subcommands. It provides a simple syntax and supports config files/env vars.
GetOpt Very limited C solution with long, convoluted syntax. Does not support much of anything, like help generation. Always available on UNIX, though (but in different flavors).
ProgramOptions.hxx Interesting library, less powerful and no subcommands. Nice callback system.
Args Also interesting, and supports subcommands. I like the optional-like design, but CLI11 is cleaner and provides direct value access, and is less verbose.
Argument Aggregator I'm a big fan of the fmt library, and the try-catch statement looks familiar. 👍 Doesn't seem to support subcommands.
Clara Simple library built for the excellent Catch testing framework. Unique syntax, limited scope.
Argh! Very minimalistic C++11 parser, single header. Don't have many features. No help generation?!?! At least it's exception-free.
CLI Custom language and parser. Huge build-system overkill for very little benefit. Last release in 2009, but still occasionally active.
argparse C++17 single file argument parser. Design seems similar to CLI11 in some ways. The author has several other interesting projects.

See Awesome C++ for a less-biased list of parsers. You can also find other single file libraries at Single file libs.


None of these libraries fulfill all the above requirements, or really even come close. As you probably have already guessed, CLI11 does. So, this library was designed to provide a great syntax, good compiler compatibility, and minimal installation fuss.

Features not supported by this library

There are some other possible "features" that are intentionally not supported by this library:

  • Non-standard variations on syntax, like -long options. This is non-standard and should be avoided, so that is enforced by this library.
  • Completion of partial options, such as Python's argparse supplies for incomplete arguments. It's better not to guess. Most third party command line parsers for python actually reimplement command line parsing rather than using argparse because of this perceived design flaw.
  • Autocomplete: This might eventually be added to both Plumbum and CLI11, but it is not supported yet.
  • Wide strings / unicode: Since this uses the standard library only, it might be hard to properly implement, but I would be open to suggestions in how to do this.

Install

To use, there are several methods:

  1. All-in-one local header: Copy CLI11.hpp from the most recent release into your include directory, and you are set. This is combined from the source files for every release. This includes the entire command parser library, but does not include separate utilities (like Timer, AutoTimer). The utilities are completely self contained and can be copied separately.
  2. All-in-one global header: Like above, but copying the file to a shared folder location like /opt/CLI11. Then, the C++ include path has to be extended to point at this folder. With CMake, use include_directories(/opt/CLI11)
  3. Local headers and target: Use CLI/*.hpp files. You could check out the repository as a git submodule, for example. With CMake, you can use add_subdirectory and the CLI11::CLI11 interface target when linking. If not using a submodule, you must ensure that the copied files are located inside the same tree directory than your current project, to prevent an error with CMake and add_subdirectory.
  4. Global headers: Use CLI/*.hpp files stored in a shared folder. You could check out the git repository in a system-wide folder, for example /opt/. With CMake, you could add to the include path via:
if(NOT DEFINED CLI11_DIR)
set (CLI11_DIR "/opt/CLI11" CACHE STRING "CLI11 git repository")
endif()
include_directories(${CLI11_DIR}/include)

And then in the source code (adding several headers might be needed to prevent linker errors):

#include "CLI/App.hpp"
#include "CLI/Formatter.hpp"
#include "CLI/Config.hpp"
  1. Global headers and target: configuring and installing the project is required for linking CLI11 to your project in the same way as you would do with any other external library. With CMake, this step allows using find_package(CLI11 CONFIG REQUIRED) and then using the CLI11::CLI11 target when linking. If CMAKE_INSTALL_PREFIX was changed during install to a specific folder like /opt/CLI11, then you have to pass -DCLI11_DIR=/opt/CLI11 when building your current project. You can also use Conan.io or Hunter. (These are just conveniences to allow you to use your favorite method of managing packages; it's just header only so including the correct path and using C++11 is all you really need.)

To build the tests, checkout the repository and use CMake:

mkdir build
cd build
cmake ..
make
GTEST_COLOR=1 CTEST_OUTPUT_ON_FAILURE=1 make test
Note: Special instructions for GCC 8

If you are using GCC 8 and using it in C++17 mode with CLI11. CLI11 makes use of the <filesystem> header if available, but specifically for this compiler, the filesystem library is separate from the standard library and needs to be linked separately. So it is available but CLI11 doesn't use it by default.

Specifically libstdc++fs needs to be added to the linking list and CLI11_HAS_FILESYSTEM=1 has to be defined. Then the filesystem variant of the Validators could be used on GCC 8. GCC 9+ does not have this issue so the <filesystem> is used by default.

There may also be other cases where a specific library needs to be linked.

Defining CLI11_HAS_FILESYSTEM=0 which will remove the usage and hence any linking issue.

In some cases certain clang compilations may require linking against libc++fs. These situations have not been encountered so the specific situations requiring them are unknown yet.


Usage

Adding options

To set up, add options, and run, your main function will look something like this:

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

    std::string filename = "default";
    app.add_option("-f,--file", filename, "A help string");

    CLI11_PARSE(app, argc, argv);
    return 0;
}
Note: If you don't like macros, this is what that macro expands to: (click to expand)

try {
    app.parse(argc, argv);
} catch (const CLI::ParseError &e) {
    return app.exit(e);
}

The try/catch block ensures that -h,--help or a parse error will exit with the correct return code (selected from CLI::ExitCodes). (The return here should be inside main). You should not assume that the option values have been set inside the catch block; for example, help flags intentionally short-circuit all other processing for speed and to ensure required options and the like do not interfere.


The initialization is just one line, adding options is just two each. The parse macro is just one line (or 5 for the contents of the macro). After the app runs, the filename will be set to the correct value if it was passed, otherwise it will be set to the default. You can check to see if this was passed on the command line with app.count("--file").

Option types

While all options internally are the same type, there are several ways to add an option depending on what you need. The supported values are:

// Add options
app.add_option(option_name, help_str="")

app.add_option(option_name,
               variable_to_bind_to, // bool, char(see note)🚧, int, float, vector, enum, or string-like, or anything with a defined conversion from a string or that takes an int 🆕, double 🆕, or string in a constructor. Also allowed are tuples 🆕, std::array 🆕 or std::pair 🆕. Also supported are complex numbers🚧, wrapper types🚧, and containers besides vector🚧 of any other supported type.
               help_string="")

app.add_option_function<type>(option_name,
               function <void(const type &value)>, // type can be any type supported by add_option
               help_string="")

app.add_complex(... // Special case: support for complex numbers ⚠️. Complex numbers are now fully supported in the add_option so this function is redundant.

// char as an option type is supported before 2.0 but in 2.0 it defaulted to allowing single non numerical characters in addition to the numeric values.

// 🆕 There is a template overload which takes two template parameters the first is the type of object to assign the value to, the second is the conversion type.  The conversion type should have a known way to convert from a string, such as any of the types that work in the non-template version.  If XC is a std::pair and T is some non pair type.  Then a two argument constructor for T is called to assign the value.  For tuples or other multi element types, XC must be a single type or a tuple like object of the same size as the assignment type
app.add_option<typename T, typename XC>(option_name,
               T &output, // output must be assignable or constructible from a value of type XC
               help_string="")

// Add flags
app.add_flag(option_name,
             help_string="")

app.add_flag(option_name,
             variable_to_bind_to, // bool, int, float, complex, containers, enum, or string-like, or any singular object with a defined conversion from a string like add_option
             help_string="")

app.add_flag_function(option_name,
             function <void(std::int64_t count)>,
             help_string="")

app.add_flag_callback(option_name,function<void(void)>,help_string="")

// Add subcommands
App* subcom = app.add_subcommand(name, description);

Option_group *app.add_option_group(name,description);

An option name must start with a alphabetic character, underscore, a number, '?', or '@'. For long options, after the first character '.', and '-' are also valid characters. For the add_flag* functions '{' has special meaning. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using count, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on the help line for its positional form.

The add_option_function<type>(... function will typically require the template parameter be given unless a std::function object with an exact match is passed. The type can be any type supported by the add_option function. The function should throw an error (CLI::ConversionError or CLI::ValidationError possibly) if the value is not valid.

🆕 The two parameter template overload can be used in cases where you want to restrict the input such as

double val
app.add_option<double,unsigned int>("-v",val);

which would first verify the input is convertible to an unsigned int before assigning it. Or using some variant type

using vtype=std::variant<int, double, std::string>;
 vtype v1;
app.add_option<vtype,std:string>("--vs",v1);
app.add_option<vtype,int>("--vi",v1);
app.add_option<vtype,double>("--vf",v1);

otherwise the output would default to a string. The add_option can be used with any integral or floating point types, enumerations, or strings. Or any type that takes an int, double, or std::string in an assignment operator or constructor. If an object can take multiple varieties of those, std::string takes precedence, then double then int. To better control which one is used or to use another type for the underlying conversions use the two parameter template to directly specify the conversion type.

Types such as (std or boost) optional<int>, optional<double>, and optional<string> and any other wrapper types are supported directly. For purposes of CLI11 wrapper types are those which value_type definition. See CLI11 Advanced Topics/Custom Converters for information on how you can add your own converters for additional types.

Vector types can also be used in the two parameter template overload

std::vector<double> v1;
app.add_option<std::vector<double>,int>("--vs",v1);

would load a vector of doubles but ensure all values can be represented as integers.

Automatic direct capture of the default string is disabled when using the two parameter template. Use set_default_str(...) or ->default_function(std::string()) to set the default string or capture function directly for these cases.

Flag options specified through the add_flag* functions allow a syntax for the option names to default particular options to a false value or any other value if some flags are passed. For example:

app.add_flag("--flag,!--no-flag",result,"help for flag");

specifies that if --flag is passed on the command line result will be true or contain a value of 1. If --no-flag is passed result will contain false or -1 if result is a signed integer type, or 0 if it is an unsigned type. An alternative form of the syntax is more explicit: "--flag,--no-flag{false}"; this is equivalent to the previous example. This also works for short form options "-f,!-n" or "-f,-n{false}". If variable_to_bind_to is anything but an integer value the default behavior is to take the last value given, while if variable_to_bind_to is an integer type the behavior will be to sum all the given arguments and return the result. This can be modified if needed by changing the multi_option_policy on each flag (this is not inherited). The default value can be any value. For example if you wished to define a numerical flag:

app.add_flag("-1{1},-2{2},-3{3}",result,"numerical flag")

using any of those flags on the command line will result in the specified number in the output. Similar things can be done for string values, and enumerations, as long as the default value can be converted to the given type.

On a C++14 compiler, you can pass a callback function directly to .add_flag, while in C++11 mode you'll need to use .add_flag_function if you want a callback function. The function will be given the number of times the flag was passed. You can throw a relevant CLI::ParseError to signal a failure.

Example

  • "one,-o,--one": Valid as long as not a flag, would create an option that can be specified positionally, or with -o or --one
  • "this" Can only be passed positionally
  • "-a,-b,-c" No limit to the number of non-positional option names

The add commands return a pointer to an internally stored Option. This option can be used directly to check for the count (->count()) after parsing to avoid a string based lookup. ⚠️ Deprecated: The add_* commands have a final argument than can be set to true, which causes the default value to be captured and printed on the command line with the help flag. Since CLI11 1.8, you can simply add ->capture_default_str().

Option options

Before parsing, you can set the following options:

  • ->required(): The program will quit if this option is not present. This is mandatory in Plumbum, but required options seems to be a more standard term. For compatibility, ->mandatory() also works.
  • ->expected(N): Take N values instead of as many as possible, only for vector args. If negative, require at least -N; end with -- or another recognized option or subcommand.
  • ->type_name(typename): Set the name of an Option's type (type_name_fn allows a function instead)
  • ->type_size(N): Set the intrinsic size of an option. The parser will require multiples of this number if negative.
  • ->needs(opt): This option requires another option to also be present, opt is an Option pointer.
  • ->excludes(opt): This option cannot be given with opt present, opt is an Option pointer.
  • ->envname(name): Gets the value from the environment if present and not passed on the command line.
  • ->group(name): The help group to put the option in. No effect for positional options. Defaults to "Options". "" will not show up in the help print (hidden).
  • ->ignore_case(): Ignore the case on the command line (also works on subcommands, does not affect arguments).
  • ->ignore_underscore(): Ignore any underscores in the options names (also works on subcommands, does not affect arguments). For example "option_one" will match with "optionone". This does not apply to short form options since they only have one character
  • ->disable_flag_override(): From the command line long form flag options can be assigned a value on the command line using the = notation --flag=value. If this behavior is not desired, the disable_flag_override() disables it and will generate an exception if it is done on the command line. The = does not work with short form flag options.
  • ->allow_extra_args(true/false): 🚧 If set to true the option will take an unlimited number of arguments like a vector, if false it will limit the number of arguments to the size of the type used in the option. Default value depends on the nature of the type use, containers default to true, others default to false.
  • ->delimiter(char): Allows specification of a custom delimiter for separating single arguments into vector arguments, for example specifying ->delimiter(',') on an option would result in --opt=1,2,3 producing 3 elements of a vector and the equivalent of --opt 1 2 3 assuming opt is a vector value.
  • ->description(str): Set/change the description.
  • ->multi_option_policy(CLI::MultiOptionPolicy::Throw): Set the multi-option policy. Shortcuts available: ->take_last(), ->take_first(),->take_all(), and ->join(). This will only affect options expecting 1 argument or bool flags (which do not inherit their default but always start with a specific policy).
  • ->check(std::string(const std::string &), validator_name="",validator_description=""): Define a check function. The function should return a non empty string with the error message if the check fails
  • ->check(Validator): Use a Validator object to do the check see Validators for a description of available Validators and how to create new ones.
  • ->transform(std::string(std::string &), validator_name="",validator_description="): Converts the input string into the output string, in-place in the parsed options.
  • ->transform(Validator): Uses a Validator object to do the transformation see Validators for a description of available Validators and how to create new ones.
  • ->each(void(const std::string &)>: Run this function on each value received, as it is received. It should throw a ValidationError if an error is encountered.
  • ->configurable(false): Disable this option from being in a configuration file. ->capture_default_str(): Store the current value attached and display it in the help string.
  • ->default_function(std::string()): Advanced: Change the function that capture_default_str() uses.
  • ->always_capture_default(): Always run capture_default_str() when creating new options. Only useful on an App's option_defaults.
  • default_str(string): Set the default string directly. This string will also be used as a default value if no arguments are passed and the value is requested.
  • default_val(value): 🆕 Generate the default string from a value and validate that the value is also valid. For options that assign directly to a value type the value in that type is also updated. Value must be convertible to a string(one of known types or have a stream operator).
  • ->option_text(string): Sets the text between the option name and description.

These options return the Option pointer, so you can chain them together, and even skip storing the pointer entirely. The each function takes any function that has the signature void(const std::string&); it should throw a ValidationError when validation fails. The help message will have the name of the parent option prepended. Since each, check and transform use the same underlying mechanism, you can chain as many as you want, and they will be executed in order. Operations added through transform are executed first in reverse order of addition, and check and each are run following the transform functions in order of addition. If you just want to see the unconverted values, use .results() to get the std::vector<std::string> of results.

On the command line, options can be given as:

  • -a (flag)
  • -abc (flags can be combined)
  • -f filename (option)
  • -ffilename (no space required)
  • -abcf filename (flags and option can be combined)
  • --long (long flag)
  • --long_flag=true (long flag with equals to override default value)
  • --file filename (space)
  • --file=filename (equals)

If allow_windows_style_options() is specified in the application or subcommand options can also be given as:

  • /a (flag)
  • /f filename (option)
  • /long (long flag)
  • /file filename (space)
  • /file:filename (colon)
  • /long_flag:false (long flag with : to override the default value) = Windows style options do not allow combining short options or values not separated from the short option like with - options

Long flag options may be given with an =<value> to allow specifying a false value, or some other value to the flag. See config files for details on the values supported. NOTE: only the = or : for windows-style options may be used for this, using a space will result in the argument being interpreted as a positional argument. This syntax can override the default values, and can be disabled by using disable_flag_override().

Extra positional arguments will cause the program to exit, so at least one positional option with a vector is recommended if you want to allow extraneous arguments. If you set .allow_extras() on the main App, you will not get an error. You can access the missing options using remaining (if you have subcommands, app.remaining(true) will get all remaining options, subcommands included). If the remaining arguments are to processed by another App then the function remaining_for_passthrough() can be used to get the remaining arguments in reverse order such that app.parse(vector) works directly and could even be used inside a subcommand callback.

You can access a vector of pointers to the parsed options in the original order using parse_order(). If -- is present in the command line that does not end an unlimited option, then everything after that is positional only.

Validators

Validators are structures to check or modify inputs, they can be used to verify that an input meets certain criteria or transform it into another value. They are added through the check or transform functions. The differences between the two function are that checks do not modify the input whereas transforms can and are executed before any Validators added through check.

CLI11 has several Validators built-in that perform some common checks

  • CLI::IsMember(...): Require an option be a member of a given set. See Transforming Validators for more details.
  • CLI::Transformer(...): Modify the input using a map. See Transforming Validators for more details.
  • CLI::CheckedTransformer(...): Modify the input using a map, and require that the input is either in the set or already one of the outputs of the set. See Transforming Validators for more details.
  • CLI::AsNumberWithUnit(...): Modify the <NUMBER> <UNIT> pair by matching the unit and multiplying the number by the corresponding factor. It can be used as a base for transformers, that accept things like size values (1 KB) or durations (0.33 ms).
  • CLI::AsSizeValue(...): Convert inputs like 100b, 42 KB, 101 Mb, 11 Mib to absolute values. KB can be configured to be interpreted as 10^3 or 2^10.
  • CLI::ExistingFile: Requires that the file exists if given.
  • CLI::ExistingDirectory: Requires that the directory exists.
  • CLI::ExistingPath: Requires that the path (file or directory) exists.
  • CLI::NonexistentPath: Requires that the path does not exist.
  • CLI::Range(min,max): Requires that the option be between min and max (make sure to use floating point if needed). Min defaults to 0.
  • CLI::Bounded(min,max): Modify the input such that it is always between min and max (make sure to use floating point if needed). Min defaults to 0. Will produce an error if conversion is not possible.
  • CLI::PositiveNumber: Requires the number be greater than 0
  • CLI::NonNegativeNumber: Requires the number be greater or equal to 0
  • CLI::Number: Requires the input be a number.
  • CLI::ValidIPV4: Requires that the option be a valid IPv4 string e.g. '255.255.255.255', '10.1.1.7'.
  • CLI::TypeValidator<TYPE>: 🚧 Requires that the option be convertible to the specified type e.g. CLI::TypeValidator<unsigned int>() would require that the input be convertible to an unsigned int regardless of the end conversion.

These Validators can be used by simply passing the name into the check or transform methods on an option

->check(CLI::ExistingFile);
->check(CLI::Range(0,10));

Validators can be merged using & and | and inverted using !. For example:

->check(CLI::Range(0,10)|CLI::Range(20,30));

will produce a check to ensure a value is between 0 and 10 or 20 and 30.

->check(!CLI::PositiveNumber);

will produce a check for a number less than or equal to 0.

Transforming Validators

There are a few built in Validators that let you transform values if used with the transform function. If they also do some checks then they can be used check but some may do nothing in that case.

  • CLI::Bounded(min,max) will bound values between min and max and values outside of that range are limited to min or max, it will fail if the value cannot be converted and produce a ValidationError

  • The IsMember Validator lets you specify a set of predefined options. You can pass any container or copyable pointer (including std::shared_ptr) to a container to this Validator; the container just needs to be iterable and have a ::value_type. The key type should be convertible from a string, You can use an initializer list directly if you like. If you need to modify the set later, the pointer form lets you do that; the type message and check will correctly refer to the current version of the set. The container passed in can be a set, vector, or a map like structure. If used in the transform method the output value will be the matching key as it could be modified by filters. After specifying a set of options, you can also specify "filter" functions of the form T(T), where T is the type of the values. The most common choices probably will be CLI::ignore_case an CLI::ignore_underscore, and CLI::ignore_space. These all work on strings but it is possible to define functions that work on other types. Here are some examples of IsMember:

  • CLI::IsMember({"choice1", "choice2"}): Select from exact match to choices.

  • CLI::IsMember({"choice1", "choice2"}, CLI::ignore_case, CLI::ignore_underscore): Match things like Choice_1, too.

  • CLI::IsMember(std::set<int>({2,3,4})): Most containers and types work; you just need std::begin, std::end, and ::value_type.

  • CLI::IsMember(std::map<std::string, TYPE>({{"one", 1}, {"two", 2}})): You can use maps; in ->transform() these replace the matched value with the matched key. The value member of the map is not used in IsMember, so it can be any type.

  • auto p = std::make_shared<std::vector<std::string>>(std::initializer_list<std::string>("one", "two")); CLI::IsMember(p): You can modify p later.

  • The Transformer and CheckedTransformer Validators transform one value into another. Any container or copyable pointer (including std::shared_ptr) to a container that generates pairs of values can be passed to these Validator's; the container just needs to be iterable and have a ::value_type that consists of pairs. The key type should be convertible from a string, and the value type should be convertible to a string You can use an initializer list directly if you like. If you need to modify the map later, the pointer form lets you do that; the description message will correctly refer to the current version of the map. Transformer does not do any checking so values not in the map are ignored. CheckedTransformer takes an extra step of verifying that the value is either one of the map key values, in which case it is transformed, or one of the expected output values, and if not will generate a ValidationError. A Transformer placed using check will not do anything. After specifying a map of options, you can also specify "filter" just like in CLI::IsMember. Here are some examples (Transformer and CheckedTransformer are interchangeable in the examples) of Transformer:

  • CLI::Transformer({{"key1", "map1"},{"key2","map2"}}): Select from key values and produce map values.

  • CLI::Transformer(std::map<std::string,int>({"two",2},{"three",3},{"four",4}})): most maplike containers work, the ::value_type needs to produce a pair of some kind.

  • CLI::CheckedTransformer(std::map<std::string, int>({{"one", 1}, {"two", 2}})): You can use maps; in ->transform() these replace the matched key with the value. CheckedTransformer also requires that the value either match one of the keys or match one of known outputs.

  • auto p = std::make_shared<CLI::TransformPairs<std::string>>(std::initializer_list<std::pair<std::string,std::string>>({"key1", "map1"},{"key2","map2"})); CLI::Transformer(p): You can modify p later. TransformPairs<T> is an alias for std::vector<std::pair<<std::string,T>>

NOTES: If the container used in IsMember, Transformer, or CheckedTransformer has a find function like std::unordered_map or std::map then that function is used to do the searching. If it does not have a find function a linear search is performed. If there are filters present, the fast search is performed first, and if that fails a linear search with the filters on the key values is performed.

Validator operations

Validators are copyable and have a few operations that can be performed on them to alter settings. Most of the built in Validators have a default description that is displayed in the help. This can be altered via .description(validator_description). The name of a Validator, which is useful for later reference from the get_validator(name) method of an Option can be set via .name(validator_name) The operation function of a Validator can be set via .operation(std::function<std::string(std::string &>). The .active() function can activate or deactivate a Validator from the operation. A validator can be set to apply only to a specific element of the output. For example in a pair option std::pair<int, std::string> the first element may need to be a positive integer while the second may need to be a valid file. The .application_index(int) 🆕 function can specify this. It is zero based and negative indices apply to all values.

opt->check(CLI::Validator(CLI::PositiveNumber).application_index(0));
opt->check(CLI::Validator(CLI::ExistingFile).application_index(1));

All the validator operation functions return a Validator reference allowing them to be chained. For example

opt->check(CLI::Range(10,20).description("range is limited to sensible values").active(false).name("range"));

will specify a check on an option with a name "range", but deactivate it for the time being. The check can later be activated through

opt->get_validator("range")->active();
Custom Validators

A validator object with a custom function can be created via

CLI::Validator(std::function<std::string(std::string &)>,validator_description,validator_name="");

or if the operation function is set later they can be created with

CLI::Validator(validator_description);

It is also possible to create a subclass of CLI::Validator, in which case it can also set a custom description function, and operation function.

Querying Validators

Once loaded into an Option, a pointer to a named Validator can be retrieved via

opt->get_validator(name);

This will retrieve a Validator with the given name or throw a CLI::OptionNotFound error. If no name is given or name is empty the first unnamed Validator will be returned or the first Validator if there is only one.

or 🆕

opt->get_validator(index);

Which will return a validator in the index it is applied which isn't necessarily the order in which was defined. The pointer can be nullptr if an invalid index is given. Validators have a few functions to query the current values

  • get_description(): Will return a description string
  • get_name(): Will return the Validator name
  • get_active(): Will return the current active state, true if the Validator is active.
  • get_application_index(): 🆕 Will return the current application index.
  • get_modifying(): Will return true if the Validator is allowed to modify the input, this can be controlled via the non_modifying() method, though it is recommended to let check and transform option methods manipulate it if needed.

Getting results

In most cases, the fastest and easiest way is to return the results through a callback or variable specified in one of the add_* functions. But there are situations where this is not possible or desired. For these cases the results may be obtained through one of the following functions. Please note that these functions will do any type conversions and processing during the call so should not used in performance critical code:

  • results(): Retrieves a vector of strings with all the results in the order they were given.
  • results(variable_to_bind_to): Gets the results according to the MultiOptionPolicy and converts them just like the add_option_function with a variable.
  • Value=as<type>(): Returns the result or default value directly as the specified type if possible, can be vector to return all results, and a non-vector to get the result according to the MultiOptionPolicy in place.

Subcommands

Subcommands are supported, and can be nested infinitely. To add a subcommand, call the add_subcommand method with a name and an optional description. This gives a pointer to an App that behaves just like the main app, and can take options or further subcommands. Add ->ignore_case() to a subcommand to allow any variation of caps to also be accepted. ->ignore_underscore() is similar, but for underscores. Children inherit the current setting from the parent. You cannot add multiple matching subcommand names at the same level (including ignore_case and ignore_underscore).

If you want to require that at least one subcommand is given, use .require_subcommand() on the parent app. You can optionally give an exact number of subcommands to require, as well. If you give two arguments, that sets the min and max number allowed. 0 for the max number allowed will allow an unlimited number of subcommands. As a handy shortcut, a single negative value N will set "up to N" values. Limiting the maximum number allows you to keep arguments that match a previous subcommand name from matching.

If an App (main or subcommand) has been parsed on the command line, ->parsed will be true (or convert directly to bool). All Apps have a get_subcommands() method, which returns a list of pointers to the subcommands passed on the command line. A got_subcommand(App_or_name) method is also provided that will check to see if an App pointer or a string name was collected on the command line.

For many cases, however, using an app's callback capabilities may be easier. Every app has a set of callbacks that can be executed at various stages of parsing; a C++ lambda function (with capture to get parsed values) can be used as input to the callback definition function. If you throw CLI::Success or CLI::RuntimeError(return_value), you can even exit the program through the callback.

Multiple subcommands are allowed, to allow Click like series of commands (order is preserved). The same subcommand can be triggered multiple times but all positional arguments will take precedence over the second and future calls of the subcommand. ->count() on the subcommand will return the number of times the subcommand was called. The subcommand callback will only be triggered once unless the .immediate_callback() flag is set or the callback is specified through the parse_complete_callback() function. The final_callback() is triggered only once. In which case the callback executes on completion of the subcommand arguments but after the arguments for that subcommand have been parsed, and can be triggered multiple times.

Subcommands may also have an empty name either by calling add_subcommand with an empty string for the name or with no arguments. Nameless subcommands function a similarly to groups in the main App. See Option groups to see how this might work. If an option is not defined in the main App, all nameless subcommands are checked as well. This allows for the options to be defined in a composable group. The add_subcommand function has an overload for adding a shared_ptr<App> so the subcommand(s) could be defined in different components and merged into a main App, or possibly multiple Apps. Multiple nameless subcommands are allowed. Callbacks for nameless subcommands are only triggered if any options from the subcommand were parsed.

Subcommand options

There are several options that are supported on the main app and subcommands and option_groups. These are:

  • .ignore_case(): Ignore the case of this subcommand. Inherited by added subcommands, so is usually used on the main App.
  • .ignore_underscore(): Ignore any underscores in the subcommand name. Inherited by added subcommands, so is usually used on the main App.
  • .allow_windows_style_options(): Allow command line options to be parsed in the form of /s /long /file:file_name.ext This option does not change how options are specified in the add_option calls or the ability to process options in the form of -s --long --file=file_name.ext.
  • .fallthrough(): Allow extra unmatched options and positionals to "fall through" and be matched on a parent option. Subcommands always are allowed to "fall through" as in they will first attempt to match on the current subcommand and if they fail will progressively check parents for matching subcommands.
  • .configurable(): 🆕 Allow the subcommand to be triggered from a configuration file. By default subcommand options in a configuration file do not trigger a subcommand but will just update default values.
  • .disable(): Specify that the subcommand is disabled, if given with a bool value it will enable or disable the subcommand or option group.
  • .disabled_by_default(): Specify that at the start of parsing the subcommand/option_group should be disabled. This is useful for allowing some Subcommands to trigger others.
  • .enabled_by_default(): Specify that at the start of each parse the subcommand/option_group should be enabled. This is useful for allowing some Subcommands to disable others.
  • .silent(): 🚧 Specify that the subcommand is silent meaning that if used it won't show up in the subcommand list. This allows the use of subcommands as modifiers
  • .validate_positionals(): Specify that positionals should pass validation before matching. Validation is specified through transform, check, and each for an option. If an argument fails validation it is not an error and matching proceeds to the next available positional or extra arguments.
  • .excludes(option_or_subcommand): If given an option pointer or pointer to another subcommand, these subcommands cannot be given together. In the case of options, if the option is passed the subcommand cannot be used and will generate an error.
  • .needs(option_or_subcommand): 🆕 If given an option pointer or pointer to another subcommand, the subcommands will require the given option to have been given before this subcommand is validated which occurs prior to execution of any callback or after parsing is completed.
  • .require_option(): Require 1 or more options or option groups be used.
  • .require_option(N): Require N options or option groups, if N>0, or up to N if N<0. N=0 resets to the default to 0 or more.
  • .require_option(min, max): Explicitly set min and max allowed options or option groups. Setting max to 0 implies unlimited options.
  • .require_subcommand(): Require 1 or more subcommands.
  • .require_subcommand(N): Require N subcommands if N>0, or up to N if N<0. N=0 resets to the default to 0 or more.
  • .require_subcommand(min, max): Explicitly set min and max allowed subcommands. Setting max to 0 is unlimited.
  • .add_subcommand(name="", description=""): Add a subcommand, returns a pointer to the internally stored subcommand.
  • .add_subcommand(shared_ptr<App>): Add a subcommand by shared_ptr, returns a pointer to the internally stored subcommand.
  • .remove_subcommand(App): Remove a subcommand from the app or subcommand.
  • .got_subcommand(App_or_name): Check to see if a subcommand was received on the command line.
  • .get_subcommands(filter): The list of subcommands that match a particular filter function.
  • .add_option_group(name="", description=""): Add an option group to an App, an option group is specialized subcommand intended for containing groups of options or other groups for controlling how options interact.
  • .get_parent(): Get the parent App or nullptr if called on master App.
  • .get_option(name): Get an option pointer by option name will throw if the specified option is not available, nameless subcommands are also searched
  • .get_option_no_throw(name): Get an option pointer by option name. This function will return a nullptr instead of throwing if the option is not available.
  • .get_options(filter): Get the list of all defined option pointers (useful for processing the app for custom output formats).
  • .parse_order(): Get the list of option pointers in the order they were parsed (including duplicates).
  • .formatter(fmt): Set a formatter, with signature std::string(const App*, std::string, AppFormatMode). See Formatting for more details.
  • .description(str): Set/change the description.
  • .get_description(): Access the description.
  • .alias(str): 🆕 set an alias for the subcommand, this allows subcommands to be called by more than one name.
  • .parsed(): True if this subcommand was given on the command line.
  • .count(): Returns the number of times the subcommand was called.
  • .count(option_name): Returns the number of times a particular option was called.
  • .count_all(): Returns the total number of arguments a particular subcommand processed, on the master App it returns the total number of processed commands.
  • .name(name): Add or change the name.
  • .callback(void() function): Set the callback for an app. 🆕 either sets the pre_parse_callback or the final_callback depending on the value of immediate_callback. See Subcommand callbacks for some additional details.
  • .parse_complete_callback(void() function): 🆕 Set the callback that runs at the completion of parsing. for subcommands this is executed at the completion of the single subcommand and can be executed multiple times. See Subcommand callbacks for some additional details.
  • .final_callback(void() function): 🆕 Set the callback that runs at the end of all processing. This is the last thing that is executed before returning. See Subcommand callbacks for some additional details.
  • .immediate_callback(): Specifies whether the callback for a subcommand should be run as a parse_complete_callback(true) or final_callback(false). When used on the main app 🆕 it will execute the main app callback prior to the callbacks for a subcommand if they do not also have the immediate_callback flag set. 🆕 It is preferable to use the parse_complete_callback or final_callback directly instead of the callback and immediate_callback if one wishes to control the ordering and timing of callback. Though immediate_callback can be used to swap them if that is needed.
  • .pre_parse_callback(void(std::size_t) function): Set a callback that executes after the first argument of an application is processed. See Subcommand callbacks for some additional details.
  • .allow_extras(): Do not throw an error if extra arguments are left over.
  • .positionals_at_end(): Specify that positional arguments occur as the last arguments and throw an error if an unexpected positional is encountered.
  • .prefix_command(): Like allow_extras, but stop immediately on the first unrecognized item. It is ideal for allowing your app or subcommand to be a "prefix" to calling another app.
  • .footer(message): Set text to appear at the bottom of the help string.
  • .footer(std::string()): 🆕 Set a callback to generate a string that will appear at the end of the help string.
  • .set_help_flag(name, message): Set the help flag name and message, returns a pointer to the created option.
  • .set_help_all_flag(name, message): Set the help all flag name and message, returns a pointer to the created option. Expands subcommands.
  • .failure_message(func): Set the failure message function. Two provided: CLI::FailureMessage::help and CLI::FailureMessage::simple (the default).
  • .group(name): Set a group name, defaults to "Subcommands". Setting "" will be hide the subcommand.
  • [option_name]: retrieve a const pointer to an option given by option_name for Example app["--flag1"] will get a pointer to the option for the "--flag1" value, app["--flag1"]->as<bool>() will get the results of the command line for a flag. The operation will throw an exception if the option name is not valid.

Note: if you have a fixed number of required positional options, that will match before subcommand names. {} is an empty filter function, and any positional argument will match before repeated subcommand names.

Callbacks

A subcommand has three optional callbacks that are executed at different stages of processing. The preparse_callback is executed once after the first argument of a subcommand or application is processed and gives an argument for the number of remaining arguments to process. For the main app the first argument is considered the program name, for subcommands the first argument is the subcommand name. For Option groups and nameless subcommands the first argument is after the first argument or subcommand is processed from that group. The second callback is executed after parsing. This is known as the parse_complete_callback. For subcommands this is executed immediately after parsing and can be executed multiple times if a subcommand is called multiple times. On the main app this callback is executed after all the parse_complete_callbacks for the subcommands are executed but prior to any final_callback calls in the subcommand or option groups. If the main app or subcommand has a config file, no data from the config file will be reflected in parse_complete_callback on named subcommands 🆕 . For option_groups the parse_complete_callback is executed prior to the parse_complete_callback on the main app but after the config_file is loaded (if specified). The 🆕 final_callback is executed after all processing is complete. After the parse_complete_callback is executed on the main app, the used subcommand final_callback are executed followed by the "final callback" for option groups. The last thing to execute is the final_callback for the main_app. For example say an application was set up like

app.parse_complete_callback(ac1);
app.final_callback(ac2);
auto sub1=app.add_subcommand("sub1")->parse_complete_callback(c1)->preparse_callback(pc1);
auto sub2=app.add_subcommand("sub2")->final_callback(c2)->preparse_callback(pc2);
app.preparse_callback( pa);

... A bunch of other options

Then the command line is given as

program --opt1 opt1_val  sub1 --sub1opt --sub1optb val sub2 --sub2opt sub1 --sub1opt2 sub2 --sub2opt2 val
  • pa will be called prior to parsing any values with an argument of 13.
  • pc1 will be called immediately after processing the sub1 command with a value of 10.
  • c1 will be called when the sub2 command is encountered.
  • pc2 will be called with value of 6 after the sub2 command is encountered.
  • c1 will be called again after the second sub2 command is encountered.
  • ac1 will be called after processing of all arguments
  • c2 will be called once after processing all arguments.
  • ac2 will be called last after completing all lower level callbacks have been executed.

A subcommand is considered terminated when one of the following conditions are met.

  1. There are no more arguments to process
  2. Another subcommand is encountered that would not fit in an optional slot of the subcommand
  3. The positional_mark (--) is encountered and there are no available positional slots in the subcommand.
  4. The subcommand_terminator mark (++) is encountered

Prior to executed a parse_complete_callback all contained options are processed before the callback is triggered. If a subcommand with a parse_complete_callback is called again, then the contained options are reset, and can be triggered again.

Option groups

The subcommand method

.add_option_group(name,description)

Will create an option group, and return a pointer to it. The argument for description is optional and can be omitted. An option group allows creation of a collection of options, similar to the groups function on options, but with additional controls and requirements. They allow specific sets of options to be composed and controlled as a collective. For an example see range example. Option groups are a specialization of an App so all functions that work with an App or subcommand also work on option groups. Options can be created as part of an option group using the add functions just like a subcommand, or previously created options can be added through

ogroup->add_option(option_pointer);
ogroup->add_options(option_pointer);
ogroup->add_options(option1,option2,option3,...);

The option pointers used in this function must be options defined in the parent application of the option group otherwise an error will be generated. Subcommands can also be added via

ogroup->add_subcommand(subcom_pointer);

This results in the subcommand being moved from its parent into the option group.

Options in an option group are searched for a command line match after any options in the main app, so any positionals in the main app would be matched first. So care must be taken to make sure of the order when using positional arguments and option groups. Option groups work well with excludes and require_options methods, as an application will treat an option group as a single option for the purpose of counting and requirements, and an option group will be considered used if any of the options or subcommands contained in it are used. Option groups allow specifying requirements such as requiring 1 of 3 options in one group and 1 of 3 options in a different group. Option groups can contain other groups as well. Disabling an option group will turn off all options within the group.

The CLI::TriggerOn and CLI::TriggerOff methods are helper functions to allow the use of options/subcommands from one group to trigger another group on or off.

CLI::TriggerOn(group1_pointer, triggered_group);
CLI::TriggerOff(group2_pointer, disabled_group);

These functions make use of preparse_callback, enabled_by_default() and disabled_by_default. The triggered group may be a vector of group pointers. These methods should only be used once per group and will override any previous use of the underlying functions. More complex arrangements can be accomplished using similar methodology with a custom preparse_callback function that does more.

Additional helper functions deprecate_option 🆕 and retire_option 🆕 are available to deprecate or retire options

CLI::deprecate_option(option *, replacement_name="");
CLI::deprecate_option(App,option_name,replacement_name="");

will specify that the option is deprecated which will display a message in the help and a warning on first usage. Deprecated options function normally but will add a message in the help and display a warning on first use.

CLI::retire_option(App,option *);
CLI::retire_option(App,option_name);

will create an option that does nothing by default and will display a warning on first usage that the option is retired and has no effect. If the option exists it is replaces with a dummy option that takes the same arguments.

If an empty string is passed the option group name the entire group will be hidden in the help results. For example.

auto hidden_group=app.add_option_group("");

will create a group such that no options in that group are displayed in the help string.

Configuration file

app.set_config(option_name="",
               default_file_name="",
               help_string="Read an ini file",
               required=false)

If this is called with no arguments, it will remove the configuration file option (like set_help_flag). Setting a configuration option is special. If it is present, it will be read along with the normal command line arguments. The file will be read if it exists, and does not throw an error unless required is true. Configuration files are in [TOML] format by default 🚧 , though the default reader can also accept files in INI format as well 🆕 . It should be noted that CLI11 does not contain a full TOML parser but can read strings from most TOML file and run them through the CLI11 parser. Other formats can be added by an adept user, some variations are available through customization points in the default formatter. An example of a TOML file 🆕 :

# Comments are supported, using a #
# The default section is [default], case insensitive

value = 1
str = "A string"
vector = [1,2,3]
str_vector = ["one","two","and three"]

# Sections map to subcommands
[subcommand]
in_subcommand = Wow
sub.subcommand = true

or equivalently in INI format

; Comments are supported, using a ;
; The default section is [default], case insensitive

value = 1
str = "A string"
vector = 1 2 3
str_vector = "one" "two" "and three"

; Sections map to subcommands
[subcommand]
in_subcommand = Wow
sub.subcommand = true

Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be true, on, 1, yes, enable; or false, off, 0, no, disable (case insensitive). Sections (and . separated names) are treated as subcommands (note: this does not necessarily mean that subcommand was passed, it just sets the "defaults"). You cannot set positional-only arguments. 🆕 Subcommands can be triggered from configuration files if the configurable flag was set on the subcommand. Then the use of [subcommand] notation will trigger a subcommand and cause it to act as if it were on the command line.

To print a configuration file from the passed arguments, use .config_to_str(default_also=false, write_description=false), where default_also will also show any defaulted arguments, and write_description will include the app and option descriptions. See Config files for some additional details.

If it is desired that multiple configuration be allowed. Use

app.set_config("--config")->expected(1, X);

Where X is some positive number and will allow up to X configuration files to be specified by separate --config arguments.

Inheriting defaults

Many of the defaults for subcommands and even options are inherited from their creators. The inherited default values for subcommands are allow_extras, prefix_command, ignore_case, ignore_underscore, fallthrough, group, footer,immediate_callback and maximum number of required subcommands. The help flag existence, name, and description are inherited, as well.

Options have defaults for group, required, multi_option_policy, ignore_case, ignore_underscore, delimiter, and disable_flag_override. To set these defaults, you should set the option_defaults() object, for example:

app.option_defaults()->required();
// All future options will be required

The default settings for options are inherited to subcommands, as well.

Formatting

The job of formatting help printouts is delegated to a formatter callable object on Apps and Options. You are free to replace either formatter by calling formatter(fmt) on an App, where fmt is any copyable callable with the correct signature. CLI11 comes with a default App formatter functional, Formatter. It is customizable; you can set label(key, value) to replace the default labels like REQUIRED, and column_width(n) to set the width of the columns before you add the functional to the app or option. You can also override almost any stage of the formatting process in a subclass of either formatter. If you want to make a new formatter from scratch, you can do that too; you just need to implement the correct signature. The first argument is a const pointer to the in question. The formatter will get a std::string usage name as the second option, and a AppFormatMode mode for the final option. It should return a std::string.

The AppFormatMode can be Normal, All, or Sub, and it indicates the situation the help was called in. Sub is optional, but the default formatter uses it to make sure expanded subcommands are called with their own formatter since you can't access anything but the call operator once a formatter has been set.

Subclassing

The App class was designed allow toolkits to subclass it, to provide preset default options (see above) and setup/teardown code. Subcommands remain an unsubclassed App, since those are not expected to need setup and teardown. The default App only adds a help flag, -h,--help, than can removed/replaced using .set_help_flag(name, help_string). You can also set a help-all flag with .set_help_all_flag(name, help_string); this will expand the subcommands (one level only). You can remove options if you have pointers to them using .remove_option(opt). You can add a pre_callback override to customize the after parse but before run behavior, while still giving the user freedom to callback on the main app.

The most important parse function is parse(std::vector<std::string>), which takes a reversed list of arguments (so that pop_back processes the args in the correct order). get_help_ptr and get_config_ptr give you access to the help/config option pointers. The standard parse manually sets the name from the first argument, so it should not be in this vector. You can also use parse(string, bool) to split up and parse a string; the optional boolean should be set to true if you are including the program name in the string, and false otherwise.

Also, in a related note, the App you get a pointer to is stored in the parent App in a shared_ptrs (similar to Options) and are deleted when the main App goes out of scope unless the object has another owner.

How it works

Every add_ option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of strings, so it knows how many times an option was passed or how many arguments it received. The lambda returns true if it could validate the option strings, and false if it failed.

Other values can be added as long as they support operator>> (and defaults can be printed if they support operator<<). To add a new type, for example, provide a custom operator>> with an istream (inside the CLI namespace is fine if you don't want to interfere with an existing operator>>).

If you wanted to extend this to support a completely new type, use a lambda or add a specialization of the lexical_cast function template in the namespace CLI::detail with the type you need to convert to. Some examples of some new parsers for complex<double> that support all of the features of a standard add_options call are in one of the tests. A simpler example is shown below:

Example

app.add_option("--fancy-count", [](std::vector<std::string> val){
    std::cout << "This option was given " << val.size() << " times." << std::endl;
    return true;
    });

Utilities

There are a few other utilities that are often useful in CLI programming. These are in separate headers, and do not appear in CLI11.hpp, but are completely independent and can be used as needed. The Timer/AutoTimer class allows you to easily time a block of code, with custom print output.

{
CLI::AutoTimer timer {"My Long Process", CLI::Timer::Big};
some_long_running_process();
}

This will create a timer with a title (default: Timer), and will customize the output using the predefined Big output (default: Simple). Because it is an AutoTimer, it will print out the time elapsed when the timer is destroyed at the end of the block. If you use Timer instead, you can use to_string or std::cout << timer << std::endl; to print the time. The print function can be any function that takes two strings, the title and the time, and returns a formatted string for printing.

Other libraries

If you use the excellent Rang library to add color to your terminal in a safe, multi-platform way, you can combine it with CLI11 nicely:

std::atexit([](){std::cout << rang::style::reset;});
try {
    app.parse(argc, argv);
} catch (const CLI::ParseError &e) {
    std::cout << (e.get_exit_code()==0 ? rang::fg::blue : rang::fg::red);
    return app.exit(e);
}

This will print help in blue, errors in red, and will reset before returning the terminal to the user.

If you are on a Unix-like system, and you'd like to handle control-c and color, you can add:

 #include <csignal>
 void signal_handler(int s) {
     std::cout << std::endl << rang::style::reset << rang::fg::red << rang::fg::bold;
     std::cout << "Control-C detected, exiting..." << rang::style::reset << std::endl;
     std::exit(1); // will call the correct exit func, no unwinding of the stack though
 }

And, in your main function:

     // Nice Control-C
     struct sigaction sigIntHandler;
     sigIntHandler.sa_handler = signal_handler;
     sigemptyset(&sigIntHandler.sa_mask);
     sigIntHandler.sa_flags = 0;
     sigaction(SIGINT, &sigIntHandler, nullptr);

API

The API is documented here. Also see the CLI11 tutorial GitBook.

Examples

Several short examples of different features are included in the repository. A brief description of each is included here

  • callback_passthrough: Example of directly passing remaining arguments through to a callback function which generates a CLI11 application based on existing arguments.
  • digit_args: Based on Issue #123, uses digit flags to pass a value
  • enum: Using enumerations in an option, and the use of CheckedTransformer
  • enum_ostream: In addition to the contents of example enum.cpp, this example shows how a custom ostream operator overrides CLI11's enum streaming.
  • formatter: Illustrating usage of a custom formatter
  • groups: Example using groups of options for help grouping and a the timer helper class
  • inter_argument_order: An app to practice mixing unlimited arguments, but still recover the original order.
  • json: Using JSON as a config file parser
  • modhelp: How to modify the help flag to do something other than default
  • nested: Nested subcommands
  • option_groups: illustrating the use of option groups and a required number of options. based on Issue #88 to set interacting groups of options
  • positional_arity: Illustrating use of preparse_callback to handle situations where the number of arguments can determine which should get parsed, Based on Issue #166
  • positional_validation: Example of how positional arguments are validated using the validate_positional flag, also based on Issue #166
  • prefix_command: illustrating use of the prefix_command flag.
  • ranges: App to demonstrate exclusionary option groups based on Issue #88
  • shapes: illustrating how to set up repeated subcommands Based on gitter discussion
  • simple: a simple example of how to set up a CLI11 Application with different flags and options
  • subcom_help: configuring help for subcommands
  • subcom_partitioned: Example with a timer and subcommands generated separately and added to the main app later.
  • subcommands: Short example of subcommands
  • validators: Example illustrating use of validators

Contribute

To contribute, open an issue or pull request on GitHub, or ask a question on gitter. There is also a short note to contributors here. This readme roughly follows the Standard Readme Style and includes a mention of almost every feature of the library. More complex features are documented in more detail in the CLI11 tutorial GitBook.

This project was created by Henry Schreiner and major features were added by Philip Top. Special thanks to all the contributors (emoji key):


Henry Schreiner

🐛 📖 💻

Philip Top

🐛 📖 💻

Christoph Bachhuber

💡 💻

Marcus Brinkmann

🐛 💻

Jonas Nilsson

🐛 💻

Doug Johnston

🐛 💻

Lucas Czech

🐛 💻

Rafi Wiener

🐛 💻

Daniel Mensinger

📦

Jesus Briales

💻 🐛

Sean Fisk

🐛 💻

fpeng1985

💻

almikhayl

💻 📦

Andrew Hardin

💻

Anton

💻

Fred Helmesjö

🐛 💻

Kannan

🐛 💻

Khem Raj

💻

Mak Kolybabi

📖

Mathias Soeken

📖

Nathan Hourt

🐛 💻

Paul le Roux

💻 📦

Paweł Bylica

📦

Peter Azmanov

💻

Stéphane Del Pino

💻

Viacheslav Kroilov

💻

christos

💻

deining

📖

elszon

💻

ncihnegn

💻

nurelin

💻

ryan4729

⚠️

Isabella Muerte

📦

KOLANICH

📦

James Gerity

📖

Josh Soref

🔧

geir-t

📦

Ondřej Čertík

🐛

Sam Hocevar

💻

Ryan Curtin

📖

Michael Hall

📖

ferdymercury

📖

Jakob Lover

💻

Dominik Steinberger

💻

D. Fleury

💻

Dan Barowy

📖

This project follows the all-contributors specification. Contributions of any kind welcome!

License

As of version 1.0, this library is available under a 3-Clause BSD license. See the LICENSE file for details.

CLI11 was developed at the University of Cincinnati to support of the GooFit library under NSF Award 1414736. Version 0.9 was featured in a DIANA/HEP meeting at CERN (see the slides). Please give it a try! Feedback is always welcome.

Comments
  • CLI::IsMember

    CLI::IsMember

    This implements CLI::IsMember, and deprecates the default add_set* options . This fixes the set lifetime and mutability issues in #170 and makes sets easy to modify after adding if you use a (shared) pointer. It also combines case insensitivity and underscore ignoring into validators, without the massive number of methods on App needed now. You can use any iterable that supports std::begin, std::end, and has ::value_type, allowing a vector (for example) to be chosen to keep definition order - first item matches.

    New features:

    • Single new validator, no longer a massive list of functions in App
    • Shared pointers supported, clear pointer vs. copy semantics
    • Combinable custom filter functions
    • All types support filter functions
    • Other containers, including ordered containers allowed

    Changes:

    • The error for not being found in a set is now CLI::ValidationError
    • All add_set* functions use the new backend, and are deprecated, planned removal of most of them in 1.9, and all of them after that. mutable versions may be removed even in 1.8.

    Ideas:

    A ->choices(...) shortcut could be added, but the syntax is still up for debate, so not in this PR. Feel free to make suggestions.

    Example of use:

    // Simple sets
    app.add_option("--name", name)->check(CLI::IsMember({"tom", "harry"}));
    
    // Sets can be modified later. `ignore_case` and `ignore_underscores` is addable.
    std::set<std::string> names = {"tom", "harry"};
    app.add_option("--name", name)->check(CLI::IsMember(&names, CLI::ignore_case));
    names->insert("john");
    
    // Shared pointers are supported, and different types. And ordered containers.
    auto vals = std::make_shared<std::vector<int>>({1,2});
    app.add_option("--val", val)->check(CLI::IsMember(&vals));
    names->push_back(3);
    

    You can use std::shared_ptr (that's internally what's used if you don't give a pointer-like). You can list CLI::ignore_case or CLI::ignore_underscore (or any other function that will be applied to both sides).

    Still to do:

    • [x] Deprecate old add_set* methods (can't be done on all of them because some are templates.)
    • [x] Provide new versions of all the tests (coexist for a little while)
    • Think about combined name + number style options (might not be part of this PR)
    • [x] Add test with non-string function, like abs
    • [x] Needs docs and examples
    • [x] Fix ignore_underscore (no ending s) in the README.
    opened by henryiii 25
  • meson: Basic meson support

    meson: Basic meson support

    With this patch, CLI11 can be used as a meson subproject: http://mesonbuild.com/Subprojects.html

    However, CMake is still required for testing and installation. The current meson.build is not a complete replacement.

    opened by mensinda 21
  • Allow general flag types

    Allow general flag types

    If merged this pull request will allow general flag values to be used, along with customized default values. It also introduces a shortcut syntax for retrieving flag and option values. Which is useful for allowing options with no storage variables.

    app["--flag"].as<std::string>() 
    

    this is similar notation to some other Command line libraries and could make transitioning to CLI easier

    It also allows numbers to be used as short flags, so -7 and similar is now allowed

    This could be specified to have a default value like -7{7} in which case if the value -7 were passed it would produce a result of 7 in the output.

    This PR addresses #123 and #124.

    opened by phlptp 18
  • Add/remove new possible choices after a call to add_set

    Add/remove new possible choices after a call to add_set

    Hi CLI11 team,

    Great job with this library, I really enjoy the simplicity !

    I'm trying to use CLI11 in AFF3CT, here is a code example:

    CLI::App app{"App description"};
    
    std::string type;
    auto opt = app.add_set("--type", type, {"TYPE1","TYPE2","TYPE3","TYPE4","TYPE5"}, "A type");
    
    // I would like to do something like this to add a choice
    opt->add_choices({"TYPE6", "TYPE7"});
    
    // and something like this to remove a choice
    opt->remove_choices({"TYPE1", "TYPE2"});
    

    Is it possible to do something like this with CLI11? If not, should it be possible to add this type of feature ?

    Many thanks, Adrien

    opened by kouchy 17
  • click-style boolean flags

    click-style boolean flags

    Add functionality similar to click style argument that allow specifying a false flag that when false generate a false result on the flag.

    See Issue #217

    after the discussion in #217 I started looking at our use cases and realized that I could probably eliminate 30% of the options if this was supported in some fashion. And since I am on paternity leave and can tinker mostly with what I find interesting, this seemed like an interesting challenge.

    This is by no means complete, needs quite a few test cases and documentation yet but enough is working to get started discussing it.

    After some tinkering what I ended up with is this.

    The add_flag and add_flag_function calls can take a syntax like "--flag|--no_flag, -f|-n" arguments after a | are considered false_flags. If they are passed they trigger a false response.
    I went with the '|' instead of '' like clicked since I didn't want to confuse with windows style options. I think it would be preferable to generate an error like it does now on that since CLI11 takes only -- and '-' arguments. and clicked seems to have a bunch of special conditions that deal with that and that seemed like it could cause trouble. '|' seemed like a nice alternative.

    It is also possible to specify the false_flags through a separate function false_flags This function checks against existing arguments and fills out the fnames_ vector which is automatically filled from | notation names.

    What happens is that the flags are checked for presence of '|' if so they extract the false flags separately and replace the '|' with a comma. All the arguments are moved into the appropriate lname or sname, so that checking doesn't change.

    Then if the argument takes 0 arguments the actual flag passed is checked against an fnames array. If it is present the flag is flipped.

    The output vector of strings either contains a "+" or "-" The counts are essentially number of "+" minus number of "-". So the signature of add_flag_function was changed so the std::function returned an int as the possibility exists it could be negative.

    opened by phlptp 16
  • meson: add support for testsuite

    meson: add support for testsuite

    As with CMakeLists.txt, this is disabled by default.

    • I have not implemented the examples/ directory because it uses some output regex feature to run the tests, and meson doesn't have any similar feature, so that would probably require some kind of wrapper program that runs the test binary and compares output.
    • I have not enabled doxygen documentation building, because it doesn't seem very useful in the same way that running tests under meson is; also, setting the output directory to be in the builddir requires either a python script to edit Doxyfile, or for Doxyfile to set @[email protected] that can be replaced (breaking usage without first running cmake or meson) or for me to stop being lazy and finally implement doxygen in a meson module. :D
    • I have not enabled CUDA tests, because I'm not sure if those are important?
    • Testing CLI11_SINGLE_FILE doesn't seem very useful, because it should behave exactly the same anyway, modulo speed of e.g. deduplicated includes
    • There are some features which I didn't bother to implement, because meson supports it out of the box:
      • sanitizers can be configured with meson using -Db_sanitize=, possible values include address, thread, undefined, memory, address,undefined. AFAIK this functionality is not tested for cmake in CI anyway.
      • a clang-tidy command is automatically set up by meson if the clang-tidy program is installed.
      • code coverage can be configured with meson using -Db_coverage=true
    opened by eli-schwartz 15
  • fix: commenting of descriptions with embedded newlines

    fix: commenting of descriptions with embedded newlines

    Anything written in write_descriptions-guarded code blocks should assume that whatever text is provided by library users may contain embedded newlines. This fixes the places where this wasn't done.

    opened by paddy-hack 15
  • Add cpplint to CI

    Add cpplint to CI

    Addressing #378: add cpplint to the CI pipeline with a set of checks that require small changes (<10 lines) in existing code.

    Currently, cpplint is expected to fail (solutions to these issues are already implemented, though not yet pushed). At this moment, this PR checks whether cpplint works in the azure pipeline and whether the return value of cpplint is used. Once that is verified, I'll push the code resolving the issues.

    You can run cpplint on your machine by checking out this PR and executing

    pip install cpplint
    cpplint --counting=detailed --recursive examples include/CLI
    

    Please review the checks that are so far excluded in file CPPLINT.cfg. We can discuss those checks in this or in future PRs.

    Advice on integrating cpplint into CI is welcome, I'm an azure pipeline beginner. Hints on running the CI pipeline on my local machine are welcome as well :)

    opened by cbachhuber 15
  • Support for size values (640 KB) and numbers with unit in general

    Support for size values (640 KB) and numbers with unit in general

    This PR adds infrastructure for accepting inputs in form <number> <unit>. This covers things like size inputs, durations, and many more. <suffix> may or may not be separated from the number with space, must contain only letters and optionally can be matched case-insensitively.

    CLI::AsNumberWithUnit takes a mapping from unit to factor. Transformation for durations may look like this:

    map<string, double> m = {{"ns", 1e-9}, {"us", 1e-6}, {"ms", 1e-3}, {"s", 1}, {"m", 60}};
    app.add_option("-d", duration)->transform(CLI::AsNumberWithUnit(mapping));
    

    Transformation for size is already provided:

    app.add_option("-s", size)->transform(CLI::AsSizeValue(true));
    
    opened by metopa 15
  • Plan for 2.0

    Plan for 2.0

    • Make more parts of the library optional, at least in multiheader mode (postponed)
    • Allow the library to be precompiled to address #194. (still will support header only / single header mode) - postponed to 2.x.
      • [x] New make single header tooling
    • [x] Drop deprecated add_set templated methods
    • [x] Drop deprecated extra true/false argument for capture default on add_option #597
    • [x] Drop add_complex (no longer required)
    • Allow compilation with exceptions turned off (might put off till 3.0)
    • [x] Change Config file output default to TOML
    opened by henryiii 14
  • Plan for precompiled mode

    Plan for precompiled mode

    Current idea:

    • All non-templated function/method bodies move to new files, such as option_fwd.inl.
    • inline gets replaced by CLI11_INLINE_DEF
    • If CLI11_COMPILE is not defined, CLI11_INLINE_DEF is inline and the .inl files get included at the end of option.hpp
    • If CLI11_COMPILE is defined, CLI11_INLINE_DEF is nothing. 0 or 1 selects whether this is the compiled file or a user.
    • The generation scripts need to be adjusted to handle this correctly; the .icc part will be wrapped in #ifs.

    The CMake files will automatically compile each header with an icc file, and link to that. A user not using CMake can add a file like this:

    #def CLI11_COMPILE 1
    #include "CLI11.hpp"
    

    Then use CLI11 like this:

    #def CLI11_COMPILE 0
    #include "CLI11.hpp"
    

    And get the benefits of compilation. If nothing is done, nothing changes and everything is header only.


    // option.hpp
    
    #include "option_fwd.hpp"
    #ifndef CLI11_COMPILE || CLI11_COMPILE==1
    #include "option.inl"
    #endif
    
    // option_fwd.hpp
    
    // Minimal required includes 
    // [cli11:preinc:includes]
    #include <fwd>
    // [cli11:preinc:end]
    
    // All files need this (has inline, etc)
    #include "macros.hpp"
    
    // Includes for other files in CLI11 (fwd only)
    #include "app_fwd.hpp"
    
    namespace CLI {
    // [cli11:app_fwd:code]
    
    class Option {
       // Definitions and templated functions only
    };
    CLI11_INLINE void f();
    
    // [cli11:app_fwd:end]
    }  // namespace CLI
    
    // option.inl
    
    // Currently not planning to include fwd here, since it is an inline file (depending on IDEs, possibly)
    
    // Compile only includes
    // [cli11:inc:includes]
    #include <algorithm>
    // [cli11:inc:end]
    
    namespace CLI {
    // [cli11:option_inl:code]
    Option::Option() {} // Definitions
    CLI11_INLINE void f() {} 
    // [cli11:option_inl:end]
    }  // namespace CLI
    
    // option.cpp
    #define CLI11_COMPILE 1 // Might as well force it here)
    #include <option.hpp>
    
    opened by henryiii 14
  • Getting map-like data from config

    Getting map-like data from config

    I have a map-like structure in config

    [map]
    a = 1
    b = 2
    

    Is it possible to get its contents in some readable form?

    I have added

    auto map = cfg.add_subcommand("map");
    map->allow_config_extras();
    

    but remaining() gives me only field names like "a", "b" without values. It appears also I cannot provide some 'global' subcommand callback for more options.

    Interesting that at the same time when I provide map.a=1 map.b=2 from command line, app's remaining() returns the full form like "map.a=1"

    opened by siilky 0
  • Using ADL everywhere for lexical_cast

    Using ADL everywhere for lexical_cast

    Right now it's pretty much impossible to extend the library for custom template types because we can't have partial function template specializations in C++ (and thus cannot partially specialize CLI::detail::lexical_cast). Note that just throwing an overload into CLI::detail doesn't work because the overload should be visible at the call site, and to have that you'd have to first declare the overload, and only then include the CLI11 headers. Not very practical.

    This PR fixes it by making sure all calls to lexical_cast are done via argument-dependent lookup.

    opened by captainurist 3
  • Help messages of sibling subcommands

    Help messages of sibling subcommands

    Hello all,

    I am having troubles in getting the correct help messages depending on specified subcommands, especially if there a sibling subcommands.

    Assume the following small example.

    CLI::App app("Some nice discription");
    
    int x = 7;
    app.add_option("-x", x, "An integer value");
    
    std::string name;
    app.add_option("-n,--name", name, "Some required string");
    
    bool flag;
    app.add_flag("-f,--flag", flag, "A flag option");
    
    int y = 3;
    CLI::App* sub1 = app.add_subcommand("sub1", "Subcommand 1");
    sub1->add_option("--sub1_opt", y, "An integer value for sub1");
    
    int z = 4;
    CLI::App* sub2 = app.add_subcommand("sub2", "Subcommand 2");
    sub2->add_option("--sub2_opt", z, "An integer value for sub2");
    
    CLI11_PARSE(app, argc, argv);
    
    return 0;
    

    Here sub1 and sub2 are sibling subcommands.

    If I run the application (assume the application is called mainapp) using

    > mainapp --help
    

    I get the expected output

    Usage: mainapp [OPTIONS] [SUBCOMMAND]
    
    Options:
      -h,--help                   Print this help message and exit
      -x INT                      An integer value
      -n,--name TEXT              Some required string
      -f,--flag                   A flag option
    
    Subcommands:
      sub1                        Subcommand 1
      sub2                        Subcommand 2
    

    If I run the application using

    > mainapp sub1 --help
    

    I will also get the expected output

    Subcommand 1
    Usage: mainapp sub1 [OPTIONS]
    
    Options:
      -h,--help                   Print this help message and exit
      --sub1_opt INT              An integer value for sub1
    
    

    Using

    > mainapp sub2 --help
    

    gives me

    Subcommand 2
    Usage: mainapp sub2 [OPTIONS]
    
    Options:
      -h,--help                   Print this help message and exit
      --sub2_opt INT              An integer value for sub2
    

    what is also expected.

    When now both sibling subcommands are specified like for instance

    > mainapp sub1 --sub1_opt 3 sub2 --help
    

    I get the unexpected help message for subcommand sub1 instead that for subcommand sub2:

    Subcommand 1
    Usage: mainapp sub1 [OPTIONS]
    
    Options:
      -h,--help                   Print this help message and exit
      --sub1_opt INT              An integer value for sub1
    
    

    How can I achieve in that case to get the help message for subcommand sub2? For mainapp sub1 --sub1_opt 3 sub2 --help I would expect the output to be

    Subcommand 2
    Usage: mainapp sub1 --sub1_opt 3 sub2 [OPTIONS]
    
    Options:
      -h,--help                   Print this help message and exit
      --sub2_opt INT              An integer value for sub2
    
    

    Thank you and best regards Volker

    opened by VolkerChristian 3
  • clangd warnings on transitive includes

    clangd warnings on transitive includes

    In the README, it is recommended to include the following three headers in your application:

    #include "CLI/App.hpp" #include "CLI/Formatter.hpp" #include "CLI/Config.hpp"

    This works well, with the exception that clangd raises warning:

    image

    If I remove the two headers below, then I get a compilation error:

    /usr/bin/ld: CMakeFiles/bth.dir/bth.cpp.o: warning: relocation against `_ZTVN3CLI9FormatterE' in read-only section `.text._ZN3CLI9FormatterC2Ev[_ZN3CLI9FormatterC5Ev]'
    /usr/bin/ld: CMakeFiles/bth.dir/bth.cpp.o: in function `CLI::ConfigBase::ConfigBase()':
    /opt/CLI11/include/CLI/ConfigFwd.hpp:81: undefined reference to `vtable for CLI::ConfigBase'
    /usr/bin/ld: CMakeFiles/bth.dir/bth.cpp.o: in function `CLI::Formatter::Formatter()':
    /opt/CLI11/include/CLI/FormatterFwd.hpp:120: undefined reference to `vtable for CLI::Formatter'
    /usr/bin/ld: warning: creating DT_TEXTREL in a PIE
    collect2: error: ld returned 1 exit status
    

    It would be nice if the warnings raised by clangd were suppressed via IWYU pragma comments on the CLI11 header files: https://clangd.llvm.org/guides/include-cleaner#scenarios-and-solutions

    If I add #include "CLI/CLI.hpp" instead of the three above, I get a similar warning, because of the transitive includes.

    opened by ferdymercury 0
  • Unicode support

    Unicode support

    Fixes #14 as discussed.

    Some notes:

    • Since necessary facilities were already in place, I also added support for wide strings as options.
    • I had difficulties coming up with a good API for this. It would not be a good idea to conditionally throw away argc and argv in favor of GetCommandLineW, because argv passed in to parse may have been already modified. Instead, I figured out a way to retrieve "original" argv on other systems and made a parallel interface: app.parse(argc, argv) stays the same and app.parse() uses "original as launched" args.
    • I exposed the following useful functions to the user:
      • argc() and argv() on all systems for "original" args.
      • widen and narrow in case the user uses a wide-string API with our UTF-8 string.
      • to_path on all systems which creates a filesystem::path, widening the string on Windows.
    • I had to remove a test which checks existence of a file with Unicode in the name because:
      1. File needs to exist beforehand and not get created during test - Unicode can get corrupted the same way during creation and during checking, the test will erroneously pass.
      2. CI chokes trying to copy a unicode-named file to the build directory.
    • Some design decisions which I considered, let me know if you prefer these over what's in the PR:
      • app.parse(CLI::system_args) instead of app.parse(), where CLI::system_args is value of a tag type CLI::system_args_t (feel free to suggest a better name for the tag)
      • Initialize argc() and argv() as a global variable before main. This is already being done for macOS. Would improve syntax from (e.g. from CLI::argv()[1] to CLI::argv[1]). Would remove any performance costs during main but will push them on users who don't care about Unicode or convert Unicode themselves.
    • Both cpplint and clang-tidy raised a lot of warnings in preexisting code when running locally. Maybe I am doing something wrong? I had to exclude build/include_subdir from cpplint just to catch actual warnings in terminal.

    Also, I made some benchmarks to measure the performance impact of supporting Unicode, since this was a concern. Measuring with google benchmark, all benchmarks receive <program-name> --option1 1234 --option2 "hello world" as commandline:

    • simple_main - create a CLI::App, options, and parse the old way. Just for reference when judging performance.
    • get_global_args - call CLI::argv() (without caching into a static variable)
    • parse_normal - app.parse(argc, argv), i.e. old speed
    • parse_global - app.parse(), i.e. new speed

    Windows:

    Run on (24 X 3748.57 MHz CPU s)
    CPU Caches:
      L1 Data 32 KiB (x12)
      L1 Instruction 32 KiB (x12)
      L2 Unified 512 KiB (x12)
      L3 Unified 32768 KiB (x2)
    ----------------------------------------------------------
    Benchmark                Time             CPU   Iterations
    ----------------------------------------------------------
    simple_main           4557 ns         4541 ns       144516
    get_global_args        566 ns          578 ns      1000000
    parse_normal           568 ns          578 ns      1000000
    parse_global          1262 ns         1256 ns       560000
    

    get_global_args and parse_normal being the same time is a little sus, I suspect that maybe there are some optimizations in the benchmark loop which I failed to prevent.

    Linux:

    Run on (24 X 3700.04 MHz CPU s)
    CPU Caches:
      L1 Data 32 KiB (x12)
      L1 Instruction 32 KiB (x12)
      L2 Unified 512 KiB (x12)
      L3 Unified 32768 KiB (x1)
    Load Average: 10.96, 3.19, 1.10
    ----------------------------------------------------------
    Benchmark                Time             CPU   Iterations
    ----------------------------------------------------------
    simple_main           2666 ns         2666 ns       259722
    get_global_args       2104 ns         2104 ns       340016
    parse_normal           521 ns          521 ns      1024941
    parse_global          2818 ns         2818 ns       248291
    

    Overall, for a function called once in the application, I think +2μs of time for Unicode support is acceptable.

    opened by andreasxp 8
  • [Question] How to allow flags in a multiple arguments option (or how to name the remaining() in the help)

    [Question] How to allow flags in a multiple arguments option (or how to name the remaining() in the help)

    I'm trying to have a subcommand that takes a file, and some extra args, and those extra args are passed down to that file for later processing. (I embed ruby & python, so I want a way to execute that ruby/python file with arguments).

    What I'm looking after:

    Usage: Products/os-cli11 execute_ruby_script [OPTIONS] path [arguments...]
    
    Positionals:
      path TEXT:FILE REQUIRED     Path to ruby file
      arguments args              Arguments to pass to the ruby file
    

    The issue is that if I pass execute_ruby_script myfile.rb arg1 arg2 it works fine, but execute_ruby_script myfile.rb -x arg2 doesn't: The following argument was not expected: -x

    How can I both:

    • Allow passing extra args that might be flags, AND
    • Explicitly say so in the help message?

    Thanks a lot for the great lib!

    Original code

    Original code, also available here: https://godbolt.org/z/vasGMPrrs

    Click to Expand Original code
    #include <CLI/CLI.hpp>
    #include <fmt/format.h>
    #include <fmt/std.h>     // Formatting std::filesystem::path
    #include <fmt/ranges.h>  // Formatting std::vector
    
    #include <filesystem>
    namespace fs = std::filesystem;
    
    
    int main(int argc, char* argv[]) {
      CLI::App app{"My CLI"};
      app.require_subcommand(1);
    
      auto* execute_ruby_scriptCommand = app.add_subcommand("execute_ruby_script", "Executes a ruby file");
      fs::path rubyScriptPath;
      execute_ruby_scriptCommand->add_option("path", rubyScriptPath, "Path to ruby file")->required(true)->check(CLI::ExistingFile);
      std::vector<std::string> executeRubyScriptCommandArgs;
      execute_ruby_scriptCommand->add_option("arguments", executeRubyScriptCommandArgs, "Arguments to pass to the ruby file")
         ->required(false)
         ->option_text("args");
      execute_ruby_scriptCommand->callback([&] {
        fmt::print("rubyScriptPath={}\n", rubyScriptPath);
        fmt::print("executeRubyScriptCommandArgs=[{}]\n", executeRubyScriptCommandArgs);
        for (const auto& arg : execute_ruby_scriptCommand->remaining()) {
          fmt::print("Remaining arg: {}\n", arg);
        }
      });
    
      CLI11_PARSE(app, argc, argv);
    
    }
    
    $ oscli11 execute_ruby_script myfile.rb -x arg2
    The following argument was not expected: -x
    Run with --help for more information.
    

    Remaining args: it works to forward, but the help doesn't mention it

    https://godbolt.org/z/c13db5WvY

    It works:

    $ oscli11 execute_ruby_script myfile.rb -x arg2
    rubyScriptPath="myfile.rb"
    remaining=["-x", "arg2"]
    

    But the help doesn't mention it:

    $ oscli11 execute_ruby_script --help
    Executes a ruby file
    Usage: build/oscli11 execute_ruby_script [OPTIONS] path
    
    Positionals:
      path TEXT REQUIRED          Path to ruby file
    
    Options:
      -h,--help                   Print this help message and exit
    
    Click to expand remaining args version
    int main(int argc, char* argv[]) {
      CLI::App app{"My CLI"};
      app.require_subcommand(1);
    
      auto* execute_ruby_scriptCommand = app.add_subcommand("execute_ruby_script", "Executes a ruby file");
      fs::path rubyScriptPath;
      execute_ruby_scriptCommand->add_option("path", rubyScriptPath, "Path to ruby file")->required(true); // ->check(CLI::ExistingFile);
      execute_ruby_scriptCommand->allow_extras(true);
      execute_ruby_scriptCommand->callback([&] {
        fmt::print("rubyScriptPath={}\n", rubyScriptPath);
        fmt::print("remaining=[{}]\n", execute_ruby_scriptCommand->remaining());
      });
    
      CLI11_PARSE(app, argc, argv);
    }
    
    opened by jmarrec 3
Releases(v2.3.1)
  • v2.3.1(Nov 1, 2022)

    A function implementation was missing after the pre-compile move, missed due to the fact we lost 100% after losing coverage checking. We are working on filling out 100% coverage again to ensure this doesn't happen again!

    • Bugfix: App::get_option_group implementation missing #793
    • Bugfix: Fix spacing when setting an empty footer #796
    • Bugfix: Address Klocwork static analysis checking issues #785
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(361.09 KB)
  • v2.3.0(Oct 6, 2022)

    This version adds a pre-compiled mode to CLI11, which allows you to precompile the library, saving time on incremental rebuilds, making CLI11 more competitive on compile time with classic compiled CLI libraries. The header-only mode is still default, and is not yet distributed via binaries.

    • Add CLI11_PRECOMPILED as an option. #762
    • Bugfix: Include <functional> in FormatterFwd #727
    • Bugfix: Add missing Macros.hpp to Error.hpp #755
    • Bugfix: Fix subcommand callback trigger #733
    • Bugfix: Variable rename to avoid warning #734
    • Bugfix: split_program_name single file name error #740
    • Bugfix: Better support for min/max overrides on MSVC #741
    • Bugfix: Support MSVC 2022 #748
    • Bugfix: Support negated flag in config file #775
    • Bugfix: Better errors for some confusing config file situations #781
    • Backend: Restore coverage testing (lost with Travis CI) #747

    New Contributors

    • @shameekganguly made their first contribution in https://github.com/CLIUtils/CLI11/pull/727
    • @PeteAudinate made their first contribution in https://github.com/CLIUtils/CLI11/pull/734
    • @dherrera-fb made their first contribution in https://github.com/CLIUtils/CLI11/pull/762

    Full Changelog: https://github.com/CLIUtils/CLI11/compare/v2.2.0...v2.3.0

    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(360.55 KB)
  • v2.2.0(Mar 27, 2022)

    New features include support for output of an empty vector, a summing option policy that can be applied more broadly, and an option to validate optional arguments to discriminate from positional arguments. A new validator to check for files on a default path is included to allow one or more default paths for configuration files or other file arguments. A number of bug fixes and code cleanup for various build configurations. Clean up of some error outputs and extension of existing capability to new types or situations.

    There is a possible minor breaking change in behavior of certain types which wrapped an integer, such as std::atomic<int> or std::optional<int> when used in a flag. The default behavior is now as a single argument value vs. summing all the arguments. The default summing behavior is now restricted to pure integral types, int64_t, int, uint32_t, etc. Use the new sum multi option policy to revert to the older behavior. The summing behavior on wrapper types was not originally intended.

    • Add MultiOptionPolicy::Sum and refactor the add_flag to fix a bug when using std::optional<bool> as type. #709
    • Add support for an empty vector result in TOML and as a default string. #660
    • Add .validate_optional_arguments() to support discriminating positional arguments from vector option arguments. #668
    • Add CLI::FileOnDefaultPath to check for files on a specified default path. #698
    • Change default value display in help messages from =XXXX to [XXXXX] to make it clearer. #666
    • Modify the Range Validator to support additional types and clean up the error output. #690
    • Bugfix: The trigger on parse modifier did not work on positional arguments. #713
    • Bugfix: The single header file generation was missing custom namespace generation. #707
    • Bugfix: Clean up File Error handling in the argument processing. #678
    • Bugfix: Fix a stack overflow error if nameless commands had fallthrough. #665
    • Bugfix: A subcommand callback could be executed multiple times if it was a member of an option group. #666
    • Bugfix: Fix an issue with vectors of multi argument types where partial argument sets did not result in an error. #661
    • Bugfix: Fix an issue with type the template matching on C++20 and add some CI builds for C++20. #663
    • Bugfix: Fix typo in C++20 detection on MSVC. #706
    • Bugfix: An issue where the detection of RTTI being disabled on certain MSVC platforms did not disable the use of dynamic cast calls. #666
    • Bugfix: Resolve strict-overflow warning on some GCC compilers. #666
    • Backend: Add additional tests concerning the use of aliases for option groups in config files. #666
    • Build: Add support for testing in meson and cleanup symbolic link generation. #701, #697
    • Build: Support building in WebAssembly. #679
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(351.24 KB)
  • v2.1.2(Oct 18, 2021)

  • v2.1.1(Sep 29, 2021)

  • v2.1.0(Sep 20, 2021)

    The name restrictions for options and subcommands are now much looser, allowing a wider variety of characters than before, even spaces can be used (use quotes to include a space in most shells). The default configuration parser was improved, allowing your configuration to sit in a larger file. And option callbacks have a few new settings, allowing them to be run even if the option is not passed, or every time the option is parsed.

    • Option/subcommand name restrictions have been relaxed. Most characters are now allowed. #627
    • The config parser can accept streams, specify a specific section, and inline comment characters are supported #630
    • force_callback & trigger_on_parse added, allowing a callback to always run on parse even if not present or every time the option is parsed #631
    • Bugfix(cmake): Only add CONFIGURE_DEPENDS if CLI11 is the main project #633
    • Bugfix(cmake): Ensure the cmake/pkg-config files install to a arch independent path #635
    • Bugfix: The single header file generation was missing the include guard. #620
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(347.06 KB)
  • v2.0.0(Jul 14, 2021)

    This version focuses on cleaning up deprecated functionality, and some minor default changes. The config processing is TOML compliant now. Atomics and complex numbers are directly supported, along with other container improvements. A new version flag option has finally been added. Subcommands are significantly improved with new features and bugfixes for corner cases. This release contains a lot of backend cleanup, including a complete overhaul of the testing system and single file generation system.

    • Built-in config format is TOML compliant now #435
      • Support multiline TOML #528
      • Support for configurable quotes #599
      • Support short/positional options in config mode #443
    • More powerful containers, support for %% separator #423
    • Support atomic types #520 and complex types natively #423
    • Add a type validator CLI::TypeValidator<TYPE> #526
    • Add a version flag easily #452, with help message #601
    • Support ->silent() on subcommands. #529
    • Add alias section to help for subcommands #545
    • Allow quotes to specify a program name #605
    • Backend: redesigned MakeSingleFiles to have a higher level of manual control, to support future features. #546
    • Backend: moved testing from GTest to Catch2 #574
    • Bugfix: avoid duplicated and missed calls to the final callback #584
    • Bugfix: support embedded newlines in more places #592
    • Bugfix: avoid listing helpall as a required flag #530
    • Bugfix: avoid a clash with WINDOWS define #563
    • Bugfix: the help flag didn't get processed when a config file was required #606
    • Bugfix: fix description of non-configurable subcommands in config #604
    • Build: support pkg-config #523

    Converting from CLI11 1.9:

    • Removed deprecated set commands, use validators instead. #565
    • The final "defaulted" bool has been removed, use ->capture_default_str() instead. Use app.option_defaults()->always_capture_default() to set this for all future options. #597
    • Use add_option on a complex number instead of add_complex, which has been removed.
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(341.67 KB)
  • v1.9.1(Jun 20, 2020)

  • v1.9.0(Jan 19, 2020)

    Config file handling was revamped to fix common issues, and now supports reading TOML.

    Adding options is significantly more powerful with support for things like std::tuple and std::array, including with transforms. Several new configuration options were added to facilitate a wider variety of apps. GCC 4.7 is no longer supported.

    • Config files refactored, supports TOML (may become default output in 2.0) #362
    • Added two template parameter form of add_option, allowing std::optional to be supported without a special import #285
    • string_view now supported in reasonable places #300, #285
    • immediate_callback, final_callback, and parse_complete_callback added to support controlling the App callback order #292, #313
    • Multiple positional arguments maintain order if positionals_at_end is set. #306
    • Pair/tuple/array now supported, and validators indexed to specific components in the objects #307, #310
    • Footer callbacks supported #309
    • Subcommands now support needs (including nameless subcommands) #317
    • More flexible type size, more useful add_complex #325, [#370][]
    • Added new validators CLI::NonNegativeNumber and CLI::PositiveNumber #342
    • Transform now supports arrays #349
    • Option groups can be hidden #356
    • Add CLI::deprecate_option and CLI::retire_option functions #358
    • More flexible and safer Option default_val [#387][]
    • Backend: Cleaner type traits #286
    • Backend: File checking updates [#341][]
    • Backend: Using pre-commit to format, checked in GitHub Actions #336
    • Backend: Clang-tidy checked again, CMake option now CL11_CLANG_TIDY #390
    • Backend: Warning cleanup, more checks from klocwork #350, Effective C++ #354, clang-tidy #360, CUDA NVCC #365, cross compile #373, sign conversion #382, and cpplint #400
    • Docs: CLI11 Tutorial now hosted in the same repository #304, #318, #374
    • Bugfix: Fixed undefined behavior in checked_multiply #290
    • Bugfix: ->check() was adding the name to the wrong validator #320
    • Bugfix: Resetting config option works properly #301
    • Bugfix: Hidden flags were showing up in error printout #333
    • Bugfix: Enum conversion no longer broken if stream operator added #348
    • Build: The meson build system supported #299
    • Build: GCC 4.7 is no longer supported, due mostly to GoogleTest. GCC 4.8+ is now required. #160
    • Build: Restructured significant portions of CMake build system #394

    Converting from CLI11 1.8:

    • Some deprecated methods dropped
      • add_set* should be replaced with ->check/->transform and CLI::IsMember since 1.8
      • get_defaultval was replaced by get_default_str in 1.8
    • The true/false 4th argument to add_option is expected to be removed in 2.0, use ->capture_default_str() since 1.8
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(308.89 KB)
  • v1.8.0(May 20, 2019)

    Set handling has been completely replaced by a new backend that works as a Validator or Transformer. This provides a single interface instead of the 16 different functions in App. It also allows ordered collections to be used, custom functions for filtering, and better help and error messages. You can also use a collection of pairs (like std::map) to transform the match into an output. Also new are inverted flags, which can cancel or reduce the count of flags, and can also support general flag types. A new add_option_fn lets you more easily program CLI11 options with the types you choose. Vector options now support a custom separator. Apps can now be composed with unnamed subcommand support. The final bool "defaults" flag when creating options has been replaced by ->capture_default_str() (ending an old limitation in construction made this possible); the old method is still available but may be removed in future versions.

    • Replaced default help capture: .add_option("name", value, "", True) becomes .add_option("name", value)->capture_default_str() #242
    • Added .always_capture_default() #242
    • New CLI::IsMember validator replaces set validation #222
    • IsMember also supports container of pairs, transform allows modification of result #228
    • Added new Transformers, CLI::AsNumberWithUnit and CLI::AsSizeValue #253
    • Much more powerful flags with different values #211, general types #235
    • add_option now supports bool due to unified bool handling #211
    • Support for composable unnamed subcommands #216
    • Reparsing is better supported with .remaining_for_passthrough() #265
    • Custom vector separator using ->delimiter(char) #209, #221, #240
    • Validators added for IP4 addresses and positive numbers #210 and numbers #262
    • Minimum required Boost for optional Optionals has been corrected to 1.61 #226
    • Positionals can stop options from being parsed with app.positionals_at_end() #223
    • Added validate_positionals #262
    • Positional parsing is much more powerful #251, duplicates supported []#247]
    • Validators can be negated with ! #230, and now handle tname functions #228
    • Better enum support and streaming helper #233 and #228
    • Cleanup for shadow warnings #232
    • Better alignment on multiline descriptions #269
    • Better support for aarch64 #266
    • Respect BUILD_TESTING only if CLI11 is the main project; otherwise, CLI11_TESTING must be used #277
    • Drop auto-detection of experimental optional and boost::optional; must be enabled explicitly (too fragile) #277 #279

    Converting from CLI11 1.7:

    • .add_option(..., true) should be replaced by .add_option(...)->capture_default_str() or app.option_defaults()->always_capture_default() can be used
    • app.add_set("--name", value, {"choice1", "choice2"}) should become app.add_option("--name", value)->check(CLI::IsMember({"choice1", "choice2"}))
    • The _ignore_case version of this can be replaced by adding CLI::ignore_case to the argument list in IsMember
    • The _ignore_underscore version of this can be replaced by adding CLI::ignore_underscore to the argument list in IsMember
    • The _ignore_case_underscore version of this can be replaced by adding both functions listed above to the argument list in IsMember
    • If you want an exact match to the original choice after one of the modifier functions matches, use ->transform instead of ->check
    • The _mutable versions of this can be replaced by passing a pointer or shared pointer into IsMember
    • An error with sets now produces a ValidationError instead of a ConversionError
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(251.24 KB)
  • v1.7.1(Jan 30, 2019)

  • v1.7.0(Jan 24, 2019)

    The parsing procedure now maps much more sensibly to complex, nested subcommand structures. Each phase of the parsing happens on all subcommands before moving on with the next phase of the parse. This allows several features, like required environment variables, to work properly even through subcommand boundaries. Passing the same subcommand multiple times is better supported. Several new features were added as well, including Windows style option support, parsing strings directly, and ignoring underscores in names. Adding a set that you plan to change later must now be done with add_mutable_set.

    • Support Windows style options with ->allow_windows_style_options. #187 On by default on Windows. #190
    • Added parse(string) to split up and parse a command-line style string directly. #186
    • Added ignore_underscore and related functions, to ignore underscores when matching names. #185
    • The default INI Config will now add quotes to strings with spaces #195
    • The default message now will mention the help-all flag also if present #197
    • Added ->description to set Option descriptions #199
    • Mutating sets (introduced in Version 1.6) now have a clear add method, add_mutable_set*, since the set reference should not expire #200
    • Subcommands now track how many times they were parsed in a parsing process. count() with no arguments will return the number of times a subcommand was encountered. #179
    • Parsing is now done in phases: shortcurcuits, ini, env, callbacks, and requirements; all subcommands complete a phase before moving on. #179
    • Calling parse multiple times is now officially supported without clear (automatic). #179
    • Dropped the mostly undocumented short_circuit property, as help flag parsing is a bit more complex, and the default callback behavior of options now works properly. #179
    • Use the standard BUILD_TESTING over CLI11_TESTING if defined (CLI11_TESTING may eventually be removed) #183
    • Cleanup warnings #191
    • Remove deprecated names: set_footer, set_name, set_callback, and set_type_name. Use without the set_ instead. #192

    Converting from CLI11 1.6:

    • ->short_circuit() is no longer needed, just remove it if you were using it - raising an exception will happen in the proper place now without it.
    • ->add_set* becomes ->add_mutable_set* if you were using the editable set feature
    • footer, name, callback, and type_name must be used instead of the set_* versions (deprecated previously).
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(165.39 KB)
  • v1.6.2(Nov 24, 2018)

    This version fixes some formatting bugs with help-all. It also adds fixes for several warnings, including an experimental optional error on Clang 7. Several smaller fixes.

    • Fixed help-all formatting #163
      • Printing help-all on nested command now fixed (App)
      • Missing space after help-all restored (Default formatter)
      • More detail printed on help all (Default formatter)
      • Help-all subcommands get indented with inner blank lines removed (Default formatter)
      • detail::find_and_replace added to utilities
    • Fixed CMake install as subproject with CLI11_INSTALL flag. #156
    • Fixed warning about local variable hiding class member with MSVC #157
    • Fixed compile error with default settings on Clang 7 and libc++ #158
    • Fixed special case of --help on subcommands (general fix planned for 1.7) #168
    • Removing an option with links #179
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(142.02 KB)
  • v1.6.1(Jul 30, 2018)

    This version provides a few fixes for special cases, such as mixing with Windows.h and better defaults for systems like Hunter. The one new feature is the ability to produce "branded" single file output for providing custom namespaces or custom macro names.

    • Added fix and test for including Windows.h #145
    • No longer build single file by default if main project, supports systems stuck on Python 2.6 #149, #151
    • Branding support for single file output #150
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(139.73 KB)
  • v1.6.0(Jun 28, 2018)

    Added a new formatting system #109. You can now set the formatter on Apps. This has also simplified the internals of Apps and Options a bit by separating most formatting code.

    • Added CLI::Formatter and formatter slot for apps, inherited.
    • FormatterBase is the minimum required.
    • FormatterLambda provides for the easy addition of an arbitrary function.
    • Added help_all support (not added by default).

    Changes to the help system (most normal users will not notice this):

    • Renamed single_name to get_name(false, false) (the default).
    • The old get_name() is now get_name(false, true).
    • The old get_pname() is now get_name(true, false).
    • Removed help_* functions.
    • Protected function _has_help_positional removed.
    • format_help can now be chained.
    • Added getters for the missing parts of options (help no longer uses any private parts).
    • Help flags now use new short_circuit property to simplify parsing. #121

    New for Config file reading and writing #121:

    • Overridable, bidirectional Config.
    • ConfigINI provided and used by default.
    • Renamed ini to config in many places.
    • Has config_formatter() and get_config_formatter().
    • Dropped prefix argument from config_to_str.
    • Added ConfigItem.
    • Added an example of a custom config format using nlohmann/json. #138

    Validators are now much more powerful #118, all built in validators upgraded to the new form:

    • A subclass of CLI::Validator is now also accepted.
    • They now can set the type name to things like PATH and INT in [1-4].
    • Validators can be combined with & and |.
    • Old form simple validators are still accepted.

    Other changes:

    • Fixing parse(args)'s args setting and ordering after parse. #141
    • Replaced set_custom_option with type_name and type_size instead of set_custom_option. Methods return this. [#136]
    • Dropped set_ on Option's type_name, default_str, and default_val. [#136]
    • Removed set_ from App's failure_message, footer, callback, and name. [#136]
    • Fixed support N<-1 for type_size. #140
    • Added ->each() to make adding custom callbacks easier. #126
    • Allow empty options add_option("-n",{}) to be edited later with each #142
    • Added filter argument to get_subcommands, get_options; use empty filter {} to avoid filtering.
    • Added get_groups() to get groups.
    • Better support for manual options with get_option, set_results, and empty. #119
    • lname and sname have getters, added const get_parent. #120
    • Using add_set will now capture L-values for sets, allowing further modification. #113
    • Dropped duplicate way to run get_type_name (get_typeval).
    • Removed requires in favor of needs (deprecated in last version). #112
    • Const added to argv. #126

    Backend and testing changes:

    • Internally, type_name is now a lambda function; for sets, this reads the set live. #116
    • Cleaner tests without app.reset() (and reset is now clear). #141
    • Better CMake policy handling. #110
    • Includes are properly sorted. #120
    • Testing (only) now uses submodules. #111
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(138.21 KB)
  • v1.5.4(Jun 14, 2018)

  • v1.5.3(Apr 19, 2018)

  • v1.5.2(Apr 17, 2018)

  • v1.5.1(Apr 12, 2018)

    This patch release adds better access to the App progromatically, to assist with writing custom converters to other formats. It also improves the help output, and uses a new feature in CLI11 1.5 to fix an old "quirk" in the way unlimited options and positionals interact.

    • Make mixing unlimited positionals and options more intuitive #102
    • Add missing getters get_options and get_description to App #105
    • The app name now can be set, and will override the auto name if present #105
    • Add (REQUIRED) for required options #104
    • Print simple name for Needs/Excludes #104
    • Use Needs instead of Requires in help print #104
    • Groups now are listed in the original definition order #106
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(111.09 KB)
  • v1.5.0(Apr 9, 2018)

    This version introduced support for optionals, along with clarification and examples of custom conversion overloads. Enums now have been dropped from the automatic conversion system, allowing explicit protection for out-of-range ints (or a completely custom conversion). This version has some internal cleanup and improved support for the newest compilers. Several bugs were fixed, as well.

    Note: This is the final release with requires, please switch to needs.

    • Fix unlimited short options eating two values before checking for positionals when no space present #90
    • Symmetric exclude text when excluding options, exclude can be called multiple times #64
    • Support for std::optional, std::experimental::optional, and boost::optional added if __has_include is supported #95
    • All macros/CMake variables now start with CLI11_ instead of just CLI_ #95
    • The internal stream was not being cleared before use in some cases. Fixed. #95
    • Using an emum now requires explicit conversion overload #97
    • The separator -- now is removed when it ends unlimited arguments #100

    Other, non-user facing changes:

    • Added Macros.hpp with better C++ mode discovery #95
    • Deprecated macros added for all platforms
    • C++17 is now tested on supported platforms #95
    • Informational printout now added to CTest #95
    • Better single file generation #95
    • Added support for GTest on MSVC 2017 (but not in C++17 mode, will need next version of GTest)
    • Types now have a specific size, separate from the expected number - cleaner and more powerful internally #92
    • Examples now run as part of testing #99
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(110.37 KB)
  • v1.4.0(Mar 10, 2018)

    This version adds lots of smaller fixes and additions after the refactor in version 1.3. More ways to download and use CLI11 in CMake have been added. INI files have improved support.

    • Lexical cast is now more strict than before #68 and fails on overflow #84
    • Added get_parent() to access the parent from a subcommand
    • Added ExistingPath validator #73
    • app.allow_ini_extras() added to allow extras in INI files #70
    • Multiline INI comments now supported
    • Descriptions can now be written with config_to_str #66
    • Double printing of error message fixed #77
    • Renamed requires to needs to avoid C++20 keyword #75, #82
    • MakeSingleHeader now works if outside of git #78
    • Adding install support for CMake #79, improved support for find_package #83, #84
    • Added support for Conan.io #83
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(104.47 KB)
  • v1.3.0(Dec 1, 2017)

    This version focused on refactoring several key systems to ensure correct behavior in the interaction of different settings. Most caveats about features only working on the main App have been addressed, and extra arguments have been reworked. Inheritance of defaults makes configuring CLI11 much easier without having to subclass. Policies add new ways to handle multiple arguments to match your favorite CLI programs. Error messages and help messages are better and more flexible. Several bugs and odd behaviors in the parser have been fixed.

    • Added a version macro, CLI11_VERSION, along with *_MAJOR, *_MINOR, and *_PATCH, for programmatic access to the version.
    • Reworked the way defaults are set and inherited; explicit control given to user with ->option_defaults() #48
    • Hidden options now are based on an empty group name, instead of special "hidden" keyword #48
    • parse no longer returns (so CLI11_PARSE is always usable) #37
    • Added remaining() and remaining_size() #37
    • allow_extras and prefix_command are now valid on subcommands #37
    • Added take_last to only take last value passed #40
    • Added multi_option_policy and shortcuts to provide more control than just a take last policy #59
    • More detailed error messages in a few cases #41
    • Footers can be added to help #42
    • Help flags are easier to customize #43
    • Subcommand now support groups #46
    • CLI::RuntimeError added, for easy exit with error codes #45
    • The clang-format script is now no longer "hidden" #48
    • The order is now preserved for subcommands (list and callbacks) #49
    • Tests now run individually, utilizing CMake 3.10 additions if possible #50
    • Failure messages are now customizable, with a shorter default #52
    • Some improvements to error codes #53
    • require_subcommand now offers a two-argument form and negative values on the one-argument form are more useful #51
    • Subcommands no longer match after the max required number is obtained #51
    • Unlimited options no longer prioritize over remaining/unlimited positionals #51
    • Added ->transform which modifies the string parsed #54
    • Changed of API in validators to void(std::string &) (const for users), throwing providing nicer errors #54
    • Added CLI::ArgumentMismatch #56 and fixed missing failure if one arg expected #55
    • Support for minimum unlimited expected arguments #56
    • Single internal arg parse function #56
    • Allow options to be disabled from INI file, rename add_config to set_config #60

    Converting from CLI11 1.2:

    • app.parse no longer returns a vector. Instead, use app.remaining(true).
    • "hidden" is no longer a special group name, instead use ""
    • Validators API has changed to return an error string; use .empty() to get the old bool back
    • Use .set_help_flag instead of accessing the help pointer directly (discouraged, but not removed yet)
    • add_config has been renamed to set_config
    • Errors thrown in some cases are slightly more specific
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(100.02 KB)
  • v1.2.0(Sep 23, 2017)

    This release focuses on making CLI11 behave properly in corner cases, and with config files on the command line. This includes fixes for a variety of reported issues. A few features were added to make life easier, as well; such as a new flag callback and a macro for the parse command.

    • Added functional form of flag #33, automatic on C++14
    • Fixed Config file search if passed on command line #30
    • Added CLI11_PARSE(app, argc, argv) macro for simple parse commands (does not support returning arg)
    • The name string can now contain spaces around commas #29
    • set_default_str now only sets string, and set_default_val will evaluate the default string given #26
    • Required positionals now take priority over subcommands #23
    • Extra requirements enforced by Travis
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(81.70 KB)
  • v1.1.0(Jun 9, 2017)

    This release incorporates feedback from the release announcement. The examples are slowly being expanded, some corner cases improved, and some new functionality for tricky parsing situations.

    • Added simple support for enumerations, allow non-printable objects #12
    • Added app.parse_order() with original parse order (#13, #16)
    • Added prefix_command(), which is like allow_extras but instantly stops and returns. (#8, #17)
    • Removed Windows error (#10, #20)
    • Some improvements to CMake, detect Python and no dependencies on Python 2 (like Python 3) (#18, #21)
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(79.21 KB)
  • v1.0.0(Jun 1, 2017)

    This is the first stable release for CLI11. Future releases will try to remain backward compatible and will follow semantic versioning if possible. There were a few small changes since version 0.9:

    • Cleanup using clang-tidy and clang-format
    • Small improvements to Timers, easier to subclass Error
    • Move to 3-Clause BSD license
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(73.63 KB)
  • v0.9(Apr 24, 2017)

    This release focused on cleaning up the most exotic compiler warnings, fixing a few oddities of the config parser, and added a more natural method to check subcommands.

    • Better CMake named target (CLI11)
    • More warnings added, fixed
    • Ini output now includes =false when default_also is true
    • Ini no longer lists the help pointer
    • Added test for inclusion in multiple files and linking, fixed issues (rarely needed for CLI, but nice for tools)
    • Support for complex numbers
    • Subcommands now test true/false directly or with ->parsed(), cleaner parse
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(73.27 KB)
  • v0.8(Mar 25, 2017)

  • v0.7(Mar 23, 2017)

    Lots of small bugs fixed when adding code coverage, better in edge cases. Much more powerful ini support.

    • Allow comments in ini files (lines starting with ;)
    • Ini files support flags, vectors, subcommands
    • Added CodeCov code coverage reports
    • Lots of small bugfixes related to adding tests to increase coverage to 100%
    • Error handling now uses scoped enum in errors
    • Reparsing rules changed a little to accommodate Ini files. Callbacks are now called when parsing INI, and reset any time results are added.
    • Adding extra utilities in full version only, Timer (not needed for parsing, but useful for general CLI applications).
    • Better support for custom add_options like functions.
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(71.10 KB)
  • v0.6(Mar 2, 2017)

    Lots of cleanup and docs additions made it into this release. Parsing is simpler and more robust; fall through option added and works as expected; much more consistent variable names internally.

    • Simplified parsing to use vector<string> only
    • Fixed fallthrough, made it optional as well (default: off): .fallthrough().
    • Added string versions of ->requires() and ->excludes() for consistency.
    • Renamed protected members for internal consistency, grouped docs.
    • Added the ability to add a number to .require_subcommand().
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(60.51 KB)
  • v0.5(Feb 22, 2017)

    • Allow Hidden options.
    • Throw OptionAlreadyAdded errors for matching subcommands or options, with ignore-case included, tests
    • ->ignore_case() added to subcommands, options, and add_set_ignore_case. Subcommands inherit setting from parent App on creation.
    • Subcommands now can be "chained", that is, left over arguments can now include subcommands that then get parsed. Subcommands are now a list (get_subcommands). Added got_subcommand(App_or_name) to check for subcommands.
    • Added .allow_extras() to disable error on failure. Parse returns a vector of leftover options. Renamed error to ExtrasError, and now triggers on extra options too.
    • Added require_subcommand to App, to simplify forcing subcommands. Do not do add_subcommand()->require_subcommand, since that is the subcommand, not the master App.
    • Added printout of ini file text given parsed options, skips flags.
    • Support for quotes and spaces in ini files
    • Fixes to allow support for Windows (added Appveyor) (Uses -, not / syntax)
    Source code(tar.gz)
    Source code(zip)
    CLI11.hpp(55.64 KB)
A simple to use, composable, command line parser for C++ 11 and beyond

Lyra A simple to use, composing, header only, command line arguments parser for C++ 11 and beyond. Obtain License Standards Stats Tests License Distri

Build Frameworks Group 388 Dec 22, 2022
EAMain provides a multi-platform entry point used for platforms that don't support console output, return codes and command-line arguments.

EAMain provides a multi-platform entry point used for platforms that don't support console output, return codes and command-line arguments.

Electronic Arts 34 Oct 1, 2022
Lightweight C++ command line option parser

Release versions Note that master is generally a work in progress, and you probably want to use a tagged release version. Version 3 breaking changes I

null 3.3k Dec 30, 2022
Tiny command-line parser for C / C++

tinyargs Another commandline argument parser for C / C++. This one is tiny, source only, and builds cleanly with -Wall -pedantic under C99 and C++11 o

Erik Agsjö 7 Aug 22, 2022
led is a line-oriented text editor in command line

led is a line-oriented text editor in command line. This editor is similar to the standard program on unix systems - GNU ed. But i'm not going to make an exact clone of that program, it's just a pet project.

Artem Mironov 16 Dec 27, 2022
CLIp is a clipboard emulator for a command line interface written in 100% standard C only. Pipe to it to copy, pipe from it to paste.

CLIp v2 About CLIp is a powerful yet easy to use and minimal clipboard manager for a command line environment, with no dependencies or bloat. Usage Sy

A.P. Jo. 12 Sep 18, 2021
Add a command-line interface to any C++ program

Add a command-line interface to any C++ program

Empirical Software Solutions, LLC 421 Dec 31, 2022
A Command-Line-Interface Debugger for 64-bit Windows written in C.

Debugger-For-Windows A command-line-interface debugger for 64-bit Windows. [email protected]:/mnt/c/Projects/C/Debugger$ ./Debugger.exe ./Tests/test.ex

Tomer Gibor 1 Nov 3, 2021
Simple command line utilities for extracting data from Fallout 4 and 76 files

fo76utils Simple command line utilities for extracting data from Fallout 4 and 76 files. baunpack - list the contents of, or extract from .BA2 archive

null 15 Dec 6, 2022
Simple command line tool that processes image files using the FidelityFX Super Resolution (FSR) or Contrast Adaptive Sharpening (CAS) shader systems.

Simple command line tool that processes image files using the FidelityFX Super Resolution (FSR) or Contrast Adaptive Sharpening (CAS) shader systems.

GPUOpen Effects 190 Dec 12, 2022
Simple, command line based player toolkit for the Ironsworn tabletop RPG

isscrolls - Command line based player toolkit for the Ironsworn tabletop RPG isscrolls is a simple toolkit for players of the Ironsworn tabletop RPG.

null 7 Sep 9, 2022
A simple command line application in order to create new Code workspaces.

mkcws Summary A simple command line application in order to create new Code workspaces. License This project's license is GPL 2. The whole license tex

Kevin Matthes 0 Apr 1, 2022
Simple command line tools to create/extract X4 .cat+.dat files

x4cat Simple command line tools to to create/extract X4 .cat+.dat files x4encat Usage: x4encat <archive name> Looks for a directory named <archive nam

Alexander Sago 1 Oct 31, 2021
Simple Driver loading command-line utility.

lddrv Simple Driver loading command-line utility. Command Line Load a driver: "lddrv.exe -operation create -binpath C:\Dev\TestDriver.sys -svcname Tes

Josh S. 3 Sep 8, 2022
udmp-parser: A Windows user minidump C++ parser library.

udmp-parser: A Windows user minidump C++ parser library. This is a cross-platform (Windows / Linux / OSX / x86 / x64) C++ library that parses Windows

Axel Souchet 95 Dec 13, 2022
A single header C++ library for parsing command line arguments and options with minimal amount of code

Quick Arg Parser Tired of unwieldy tools like getopt or argp? Quick Arg Parser is a single header C++ library for parsing command line arguments

null 47 Dec 21, 2022
null 77 Dec 27, 2022
Rizin - UNIX-like reverse engineering framework and command-line toolset.

Rizin - UNIX-like reverse engineering framework and command-line toolset.

Rizin Organization 1.7k Dec 30, 2022
A command line tool for numerically computing Out-of-time-ordered correlations for N=4 supersymmetric Yang-Mills theory and Beta deformed N=4 SYM.

A command line tool to compute OTOC for N=4 supersymmetric Yang–Mills theory This is a command line tool to numerically compute Out-of-time-ordered co

Gaoli Chen 1 Oct 16, 2021