- Notifications
You must be signed in to change notification settings - Fork0
CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface.
License
MethanePowered/CLI11
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
What's new •Documentation •APIReference
CLI11 is a command line parser for C++11 and beyond that provides a rich featureset with a simple and intuitive interface.
- CLI11: Command line parser for C++11
Features that were added in the last released minor version are marked with"🆕". Features only available in main are marked with "🚧".
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 headeronly, and comes in a single file form for easy inclusion in projects. It is easyto use for small projects, but powerful enough for complex command lineprojects, and can be customized for frameworks. It is tested onAzure andGitHub Actions, and was originally used by theGooFit GPUfitting framework. It was inspired byplumbum.cli forPython. CLI11 has a user friendly introduction in this README, a more in-depthtutorialGitBook, as well asAPI documentation generated byTravis. See thechangelog orGitHub Releases for detailsfor current and past releases. Also see theVersion 1.0 post,Version 1.3post,Version 1.6 post, orVersion 2.0 post for more information.
You can be notified when new releases are made by subscribing tohttps://github.com/CLIUtils/CLI11/releases.atom on an RSS reader, like Feedly,or use the releases mode of the GitHub watching tool.
An acceptable CLI parser library should be all of the following:
- Easy to include (i.e., header only, one file if possible,no externalrequirements).
- Short, simple syntax: This is one of the main reasons to use a CLI parser, itshould make variables from the command line nearly as easy to define as anyother variables. If most of your program is hidden in CLI parsing, this is aproblem for readability.
- C++11 or better: Should work with GCC 4.8+ (default on CentOS/RHEL 7), Clang3.4+, AppleClang 7+, NVCC 7.0+, or MSVC 2015+.
- Work on Linux, macOS, and Windows.
- Well tested on all common platforms and compilers. "Well" is defined as havinggood coverage measured byCodeCov.
- Clear help printing.
- Nice error messages.
- Standard shell idioms supported naturally, like grouping flags, a positionalseparator, etc.
- Easy to execute, with help, parse errors, etc. providing correct exit anddetails.
- Easy to extend as part of a framework that provides "applications" to users.
- Usable subcommand syntax, with support for multiple subcommands, nestedsubcommands, option groups, and optional fallthrough (explained later).
- Ability to add a configuration file (
TOML,INI, or custom format), andproduce it as well. - Produce real values that can be used directly in code, not something you havepay compute time to look up, for HPC applications.
- Work with common types, simple custom types, and extensible to exotic types.
- Permissively licensed.
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 thefmt library, and the try-catch statement looks familiar. 👍 Doesn't seem to support subcommands. |
| Clara | Simple library built for the excellentCatch 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. |
| lyra | a simple header only parser with composable options. Might work well for simple standardized parsing |
SeeAwesome C++ for a less-biased list of parsers. You can also find othersingle file libraries atSingle file libs.
None of these libraries fulfill all the above requirements, or really even comeclose. As you probably have already guessed, CLI11 does. So, this library wasdesigned to provide a great syntax, good compiler compatibility, and minimalinstallation fuss.
There are some other possible "features" that are intentionally not supported bythis library:
- Completion of partial options, such as Python's
argparsesupplies forincomplete arguments. It's better not to guess. Most third party command lineparsers for python actually reimplement command line parsing rather than usingargparse because of this perceived design flaw (recent versions do have anoption to disable it). Recent releases of CLI11 do include partial optionmatching for option prefixes 🆕. This is enabled by.allow_subcommand_prefix_matching(), along with an example that generatessuggested close matches. - Autocomplete: This might eventually be added to both Plumbum and CLI11, but itis not supported yet.
- While not recommended, CLI11 does now support non standard option names suchas
-option. This is enabled throughallow_non_standard_option_names()modifier on an app.
To use, the most common methods are described here additional methods anddetails are available atinstallation:
- All-in-one local header: Copy
CLI11.hppfrom themost recentrelease into your include directory, and you are set. Thisis combined from the source files for every release. This includes the entirecommand parser library, but does not include separate utilities (likeTimer,AutoTimer). The utilities are completely self contained and can be copiedseparately. - All-in-one global header: Like above, but copying the file to a shared folderlocation like
/opt/CLI11. Then, the C++ include path has to be extended topoint at this folder. With CMake 3.10+, useinclude_directories(/opt/CLI11) - For other methods including using CMake, conan or vcpkg and some specificinstructions for GCC 8 or WASI seeinstallation.
To set up, add options, and run, your main function will look something likethis:
intmain(int argc,char** argv) { CLI::App app{"App description"}; argv = app.ensure_utf8(argv); std::string filename ="default"; app.add_option("-f,--file", filename,"A help string");CLI11_PARSE(app, argc, argv);return0;}
When adding options the names should not conflict with each other, if an optionis added, or a modifier changed that would cause naming conflicts a run timeerror will be thrown in the add_option method. This includes default options forhelp-h, --help. For more information aboutensure_utf8 the section onUnicode support below.
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 thecorrect return code (selected fromCLI::ExitCodes). (The return here should beinsidemain). You should not assume that the option values have been setinside the catch block; for example, help flags intentionally short-circuit allother processing for speed and to ensure required options and the like do notinterfere.
The initialization is just one line, adding options is just two each. The parsemacro 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 itwill be set to the default. You can check to see if this was passed on thecommand line withapp.count("--file").
While all options internally are the same type, there are several ways to add anoption depending on what you need. The supported values are:
// Add optionsapp.add_option(option_name, help_str="")app.add_option(option_name, variable_to_bind_to,// bool, char(see note), int, float, vector, enum, std::atomic, 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 vectors 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="")// 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 typeapp.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 flagsapp.add_flag(option_name, help_string="")app.add_flag(option_name, variable_to_bind_to,// bool, int, float, complex, containers, enum, std::atomic, 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 subcommandsApp* subcom = app.add_subcommand(name, description);Option_group *app.add_option_group(name,description);
An option name may start with any character except ('-', ' ', '\n', and '!').For long options, after the first character all characters are allowed except('=',':','{',' ', '\n'). For theadd_flag* functions '{' and '!' have specialmeaning which is why they are not allowed. Names are given as a comma separatedstring, with the dash or dashes. An option or flag can have as many names as youwant, and afterward, usingcount, you can use any of the names, with dashes asneeded, to count the options. One of the names is allowed to be given withoutproceeding dash(es); if present the option is a positional option, and that namewill be used on the help line for its positional form. The string++ is alsonot allowed as option name due to its use as an array separator and marker onconfig files.
Theadd_option_function<type>(... function will typically require the templateparameter be given unless astd::function object with an exact match ispassed. The type can be any type supported by theadd_option function. Thefunction should throw an error (CLI::ConversionError orCLI::ValidationErrorpossibly) if the value is not valid.
The two parameter template overload can be used in cases where you want torestrict the input such as
double valapp.add_option<double,unsignedint>("-v",val);
which would first verify the input is convertible to anunsigned int beforeassigning 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. Theadd_option can be usedwith any integral or floating point types, enumerations, or strings. Or any typethat takes an int, double, or std::string in an assignment operator orconstructor. If an object can take multiple varieties of those, std::stringtakes precedence, then double then int. To better control which one is used orto use another type for the underlying conversions use the two parametertemplate to directly specify the conversion type.
Types such as (std or boost)optional<int>,optional<double>, andoptional<string> and any other wrapper types are supported directly. Forpurposes of CLI11 wrapper types are those whichvalue_type definition. SeeCLI11 Advanced Topics/Custom Converters for information on how you can addyour 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 asintegers.
Automatic direct capture of the default string is disabled when using the twoparameter template. Useset_default_str(...) or->default_function(std::string()) to set the default string or capturefunction directly for these cases.
Flag options specified through theadd_flag* functions allow a syntax for theoption names to default particular options to a false value or any other valueif 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 orcontain a value of 1. If--no-flag is passedresult will contain false or -1ifresult is a signed integer type, or 0 if it is an unsigned type. Analternative form of the syntax is more explicit:"--flag,--no-flag{false}";this is equivalent to the previous example. This also works for short formoptions"-f,!-n" or"-f,-n{false}". Ifvariable_to_bind_to is anything butan integer value the default behavior is to take the last value given, while ifvariable_to_bind_to is an integer type the behavior will be to sum all thegiven arguments and return the result. This can be modified if needed bychanging themulti_option_policy on each flag (this is not inherited). Thedefault value can be any value. For example if you wished to define a numericalflag:
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 numberin 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 aC++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 acallback function. The function will be given the number of times the flag waspassed. You can throw a relevantCLI::ParseError to signal a failure.
"one,-o,--one": Valid as long as not a flag, would create an option that canbe specified positionally, or with-oor--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 storedOption. This optioncan be used directly to check for the count (->count()) after parsing to avoida string based lookup.
Before parsing, you can set the following options:
->required(): The program will quit if this option is not present. This ismandatoryin Plumbum, but required options seems to be a more standard term.For compatibility,->mandatory()also works.->expected(N): TakeNvalues instead of as many as possible, only forvector args. If negative, require at least-N; end with--or anotherrecognized option or subcommand.->expected(MIN,MAX): Set a range of expected values to accompany an option.expected(0,1)is the equivalent of making a flag.->type_name(typename): Set the name of an Option's type (type_name_fnallows a function instead)->type_size(N): Set the intrinsic size of an option value. The parser willrequire multiples of this number if negative. Most of the time this isdetected automatically though can be modified for specific use cases.->type_size(MIN,MAX): Set the intrinsic size of an option to a range.->needs(opt): This option requires another option to also be present, opt isanOptionpointer. Options can be removed from theneedswithremove_needs(opt). The option can also be specified with a string containingthe name of the option->excludes(opt): This option cannot be given withoptpresent, opt is anOptionpointer. Can also be given as a string containing the name of theoption. Options can be removed from the excludes list with->remove_excludes(opt)->envname(name): Gets the value from the environment if present and notpassed on the command line. The value must also pass any validators to beused.->group(name): The help group to put the option in. No effect for positionaloptions. Defaults to"Options". Options given an empty string will not showup in the help print (hidden).->ignore_case(): Ignore the case on the command line (also works onsubcommands, does not affect arguments).->ignore_underscore(): Ignore any underscores in the options names (alsoworks on subcommands, does not affect arguments). For example "option_one"will match with "optionone". This does not apply to short form options sincethey only have one character->disable_flag_override(): From the command line long form flag options canbe assigned a value on the command line using the=notation--flag=value.If this behavior is not desired, thedisable_flag_override()disables it andwill generate an exception if it is done on the command line. The=does notwork with short form flag options.->allow_extra_args(true/false): If set to true the option will take anunlimited number of arguments like a vector, if false it will limit the numberof arguments to the size of the type used in the option. Default value dependson the nature of the type use, containers default to true, others default tofalse.->delimiter(char): Allows specification of a custom delimiter for separatingsingle arguments into vector arguments, for example specifying->delimiter(',')on an option would result in--opt=1,2,3producing 3elements of a vector and the equivalent of --opt 1 2 3 assuming opt is avector value.->description(str): Set/change the description.->multi_option_policy(CLI::MultiOptionPolicy::Throw): Set the multi-optionpolicy. Shortcuts available:->take_last(),->take_first(),->take_all(),and->join(). This will only affect options expecting 1 argument or boolflags (which do not inherit their default but always start with a specificpolicy).->join(delim)can also be used to join with a specific delimiter.This equivalent to calling->delimiter(delim)and->join(). Valid valuesareCLI::MultiOptionPolicy::Throw,CLI::MultiOptionPolicy::Throw,CLI::MultiOptionPolicy::TakeLast,CLI::MultiOptionPolicy::TakeFirst,CLI::MultiOptionPolicy::Join,CLI::MultiOptionPolicy::TakeAll,CLI::MultiOptionPolicy::Sum, andCLI::MultiOptionPolicy::Reverse.->check(std::string(const std::string &), validator_name="",validator_description=""):Define a check function. The function should return a non empty string withthe error message if the check fails->check(Validator): Use a Validator object to do the check seeValidators for a description of available Validators and how tocreate new ones.->transform(std::string(std::string &), validator_name="",validator_description="):Converts the input string into the output string, in-place in the parsedoptions.->transform(Validator): Uses a Validator object to do the transformation seeValidators for a description of available Validators and how tocreate new ones.->each(void(const std::string &)>: Run this function on each value received,as it is received. It should throw aValidationErrorif an error isencountered.->configurable(false): Disable this option from being in a configurationfile.->capture_default_str(): Store the current value attached and display it inthe help string. This should work with almost any type thatadd_optioncanaccept.->default_function(std::string()): Advanced: Change the function thatcapture_default_str()uses.->always_capture_default(): Always runcapture_default_str()when creatingnew options. Only useful on an App'soption_defaults.->default_str(string): Set the default string directly (NO VALIDATION ORCALLBACKS). This string will also be used as a default value if no argumentsare passed and the value is requested.->default_val(value): Generate the default string from a value and validatethat the value is also valid. For options that assign directly to a value typethe value in that type is also updated. Value must be convertible to astring(one of known types or have a stream operator). The callback may betriggered if therun_callback_for_defaultis set.->run_callback_for_default(): This will force the option callback to beexecuted or the variable set when thedefault_valis set.->option_text(string): Sets the text between the option name anddescription.->force_callback(): Causes the option callback or value set to be triggeredeven if the option was not present in parsing.->trigger_on_parse(): If set, causes the callback and all associatedvalidation checks for the option to be executed when the option value isparsed vs. at the end of all parsing. This could cause the callback to beexecuted multiple times. Also works with positional options.->callback_priority(CallbackPriority priority): 🆕 changes the order inwhich the option callback is executed. Four principal callback call-points areavailable.CallbackPriority::Firstexecutes at the very beginning ofprocessing, before configuration files are read and environment variables areinterpreted.CallbackPriority::PreRequirementsCheckexecutes afterconfiguration and environment processing but before requirements checking.CallbackPriority::Normalexecutes after the requirements check but beforeany previously potentially raised exceptions are re-thrown.CallbackPriority::Lastexecutes after exception handling is completed. Foreach position, both ordinary option callbacks and help callbacks are invoked.The relative order between them can be controlled using the correspondingPreHelpvariants.CallbackPriority::FirstPreHelpexecutes ordinary optioncallbacks before help callbacks at the very beginning of processing.CallbackPriority::PreRequirementsCheckPreHelpexecutes ordinary optioncallbacks before help callbacks after configuration and environment processingbut before requirements checking.CallbackPriority::NormalPreHelpexecutesordinary option callbacks before help callbacks after the requirements checkbut before exception re-throwing.CallbackPriority::LastPreHelpexecutesordinary option callbacks before help callbacks after exception handling hascompleted. When using the standard priorities (CallbackPriority::First,CallbackPriority::PreRequirementsCheck,CallbackPriority::Normal,CallbackPriority::Last), help callbacks are executed before ordinary optioncallbacks. By default, help callbacks useCallbackPriority::First, andordinary option callbacks useCallbackPriority::Normal. This mechanismprovides fine-grained control over when option values are set and when help orrequirement checks occur, enabling precise customization of the processingsequence.
These options return theOption pointer, so you can chain them together, andeven skip storing the pointer entirely. Theeach function takes any functionthat has the signaturevoid(const std::string&); it should throw aValidationError when validation fails. The help message will have the name ofthe parent option prepended. Sinceeach,check andtransform use the sameunderlying mechanism, you can chain as many as you want, and they will beexecuted in order. Operations added throughtransform are executed first inreverse order of addition, andcheck andeach are run following thetransform functions in order of addition. If you just want to see theunconverted values, use.results() to get thestd::vector<std::string> ofresults.
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)
Ifallow_windows_style_options() is specified in the application or subcommandoptions 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 notseparated from the short option like with
-options
- Windows style options do not allow combining short options or values notseparated from the short option like with
Long flag options may be given with an=<value> to allow specifying a falsevalue, or some other value to the flag. Seeconfig filesfor details on the values supported. NOTE: only the= or: for windows-styleoptions may be used for this, using a space will result in the argument beinginterpreted as a positional argument. This syntax can override the defaultvalues, and can be disabled by usingdisable_flag_override().
Extra positional arguments will cause the program to exit, so at least onepositional option with a vector is recommended if you want to allow extraneousarguments. If you set.allow_extras() on the mainApp, you will not get anerror. You can access the missing options usingremaining (if you havesubcommands,app.remaining(true) will get all remaining options, subcommandsincluded). If the remaining arguments are to processed by anotherApp then thefunctionremaining_for_passthrough() can be used to get the remainingarguments in reverse order such thatapp.parse(vector) works directly andcould even be used inside a subcommand callback.
You can access a vector of pointers to the parsed options in the original orderusingparse_order(). If-- is present in the command line that does not endan unlimited option, then everything after that is positional only.
Validators are structures to check or modify inputs, they can be used to verifythat an input meets certain criteria or transform it into another value. Theyare added through thecheck ortransform functions. The differences betweenthe two function are that checks do not modify the input whereas transforms canand are executed before any Validators added throughcheck.
CLI11 has several Validators included that perform some common checks. Bydefault the most commonly used ones are available. 🆕 If some are not neededthey can be disabled by using
#defineCLI11_DISABLE_EXTRA_VALIDATORS1
These validators are always available regardless of definitions. These are usedinternally or are very commonly used, so will always remain available regardlessof flags.
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::FileOnDefaultPath: Best used as a transform, Will check that a fileexists either directly or in a default path and update the path appropriately.SeeTransforming Validators for more detailsCLI::Range(min,max): Requires that the option be between min and max (makesure to use floating point if needed). Min defaults to 0.CLI::PositiveNumber: Requires the number be greater than 0CLI::NonNegativeNumber: Requires the number be greater or equal to 0CLI::Number: Requires the input be a number.
Validators that may be disabled by settingCLI11_DISABLE_EXTRA_VALIDATORS to 1or enabled by settingCLI11_ENABLE_EXTRA_VALIDATORS to 1. By default they areenabled. In version 3.0 these will likely move to be disabled by default and becontrolled solely by theCLI11_ENABLE_EXTRA_VALIDATORS option. Thesevalidators are less commonly used or are template heavy and require additionalcomputation time that may not be valuable for some use cases.
CLI::IsMember(...): Require an option be a member of a given set. SeeTransforming Validators for more details.CLI::Transformer(...): Modify the input using a map. SeeTransforming Validators for more details.CLI::CheckedTransformer(...): Modify the input using a map, and require thatthe input is either in the set or already one of the outputs of the set. SeeTransforming Validators for more details.CLI::AsNumberWithUnit(...): Modify the<NUMBER> <UNIT>pair by matchingthe unit and multiplying the number by the corresponding factor. It can beused as a base for transformers, that accept things like size values (1 KB)or durations (0.33 ms).CLI::AsSizeValue(...): Convert inputs like100b,42 KB,101 Mb,11 Mibto absolute values.KBcan be configured to be interpreted as 10^3or 2^10.CLI::Bounded(min,max): Modify the input such that it is always between minand max (make sure to use floating point if needed). Min defaults to 0. Willproduce an error if conversion is not possible.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 thespecified type e.g.CLI::TypeValidator<unsigned int>()would require thatthe input be convertible to anunsigned intregardless of the endconversion.
New validators will go into code sections that must be explicitly enabled bysettingCLI11_ENABLE_EXTRA_VALIDATORS to 1
CLI::ReadPermission: Requires that the file or folder given exist and haveread permission. Requires C++17.CLI::WritePermission: Requires that the file or folder given exist and havewrite permission. Requires C++17.CLI::ExecPermission: Requires that the file given exist and have executionpermission. Requires C++17.
These Validators once enabled can be used by simply passing the name into thecheck ortransform 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.
There are a few built in Validators that let you transform values if used withthetransform function. If they also do some checks then they can be usedcheck but some may do nothing in that case.
CLI::Bounded(min,max)will bound values between min and max and valuesoutside of that range are limited to min or max, it will fail if the valuecannot be converted and produce aValidationError- The
IsMemberValidator lets you specify a set of predefined options. You canpass any container or copyable pointer (includingstd::shared_ptr) to acontainer to this Validator; the container just needs to be iterable and havea::value_type. The key type should be convertible from a string, You canuse an initializer list directly if you like. If you need to modify the setlater, the pointer form lets you do that; the type message and check willcorrectly refer to the current version of the set. The container passed in canbe a set, vector, or a map like structure. If used in thetransformmethodthe 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 ofthe formT(T), whereT is the type of the values. The most common choicesprobably will beCLI::ignore_case anCLI::ignore_underscore, andCLI::ignore_space. These all work on strings but it is possible to definefunctions that work on other types. Here are some examples ofIsMember:
CLI::IsMember({"choice1", "choice2"}): Select from exact match to choices.CLI::IsMember({"choice1", "choice2"}, CLI::ignore_case, CLI::ignore_underscore):Match things likeChoice_1, too.CLI::IsMember(std::set<int>({2,3,4})): Most containers and types work; youjust needstd::begin,std::end, and::value_type.CLI::IsMember(std::map<std::string, TYPE>({{"one", 1}, {"two", 2}})): Youcan use maps; in->transform()these replace the matched value with thematched key. The value member of the map is not used inIsMember, so it canbe any type.auto p = std::make_shared<std::vector<std::string>>(std::initializer_list<std::string>("one", "two")); CLI::IsMember(p):You can modifyplater.- The
TransformerandCheckedTransformerValidators transform one value intoanother. Any container or copyable pointer (includingstd::shared_ptr) to acontainer that generates pairs of values can be passed to theseValidator's;the container just needs to be iterable and have a::value_typethatconsists of pairs. The key type should be convertible from a string, and thevalue type should be convertible to a string You can use an initializer listdirectly if you like. If you need to modify the map later, the pointer formlets you do that; the description message will correctly refer to the currentversion of the map.Transformerdoes not do any checking so values not inthe map are ignored.CheckedTransformertakes an extra step of verifyingthat the value is either one of the map key values, in which case it istransformed, or one of the expected output values, and if not will generate aValidationError. A Transformer placed usingcheckwill not do anything.
After specifying a map of options, you can also specify "filter" just like inCLI::IsMember. Here are some examples (Transformer andCheckedTransformerare interchangeable in the examples) ofTransformer:
CLI::Transformer({{"key1", "map1"},{"key2","map2"}}): Select from key valuesand produce map values.CLI::Transformer(std::map<std::string,int>({"two",2},{"three",3},{"four",4}})):most maplike containers work, the::value_typeneeds to produce a pair ofsome kind.CLI::CheckedTransformer(std::map<std::string, int>({{"one", 1}, {"two", 2}})):You can use maps; in->transform()these replace the matched key with thevalue.CheckedTransformeralso requires that the value either match one ofthe 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 modifyplater.TransformPairs<T>is an alias forstd::vector<std::pair<<std::string,T>>
NOTES: If the container used inIsMember,Transformer, orCheckedTransformer has afind function likestd::unordered_map orstd::map then that function is used to do the searching. If it does not have afind function a linear search is performed. If there are filters present, thefast search is performed first, and if that fails a linear search with thefilters on the key values is performed.
CLI::FileOnDefaultPath(default_path): can be used to check for files in adefault path. If used as a transform it will first check that a file exists,if it does nothing further is done, if it does not it tries to add a defaultPath to the file and search there again. If the file does not exist an erroris returned normally but this can be disabled usingCLI::FileOnDefaultPath(default_path, false). This allows multiple paths tobe chained using multiple transform calls.CLI::EscapedString: can be used to process an escaped string. The processingis equivalent to that used for TOML config files, seeTOML strings. With 2 notable exceptions.` can also be used as a literal string notation, and it also allows binarystring notation seebinary strings.The escaped string processing will remove outer quotes if present,"willindicate a string with potential escape sequences,'and ` will indicate aliteral string and the quotes removed but no escape sequences will beprocessed. This is the same escape processing as used in config files.
Validators are copyable and have a few operations that can be performed on themto alter settings. Most of the built in Validators have a default descriptionthat is displayed in the help. This can be altered via.description(validator_description). The name of a Validator, which is usefulfor later reference from theget_validator(name) method of anOption can beset via.name(validator_name) The operation function of a Validator can be setvia.operation(std::function<std::string(std::string &>). The.active()function can activate or deactivate a Validator from the operation. A validatorcan be set to apply only to a specific element of the output. For example in apair optionstd::pair<int, std::string> the first element may need to be apositive integer while the second may need to be a valid file. The.application_index(int) function can specify this. It is zero based andnegative 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 themto 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 thetime being. The check can later be activated through
opt->get_validator("range")->active();
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 ofCLI::Validator, in which case itcan also set a custom description function, and operation function. One exampleof this is in thecustom validator example.example. Thecheck andtransform operations can also take a shared_ptr 🆕 toa validator if you wish to reuse the validator in multiple locations or it ismutating and the check is dependent on other operations or is variable. Notethat in this case it is not recommended to use the same object for both checkand transform operations, the check will modify some internal flags on theobject so it will not be usable for transform operations.
Once loaded into an Option, a pointer to a named Validator can be retrieved via
auto *validator = opt->get_validator(name);
This will retrieve a Validator with the given name or throw aCLI::OptionNotFound error. If no name is given or name is empty the firstunnamed Validator will be returned or the first Validator if there is only one.
or
auto *validator = opt->get_validator(index);
Which will return a validator in the index it is applied which isn't necessarilythe order in which was defined. The pointer can benullptr if an invalid indexis given. Validators have a few functions to query the current values:
get_description(): Will return a description stringget_name(): Will return the Validator nameget_active(): Will return the current active state, true if the Validator isactive.get_application_index(): Will return the current application index.get_modifying(): Will return true if the Validator is allowed to modify theinput, this can be controlled via thenon_modifying()method, though it isrecommended to letcheckandtransformoption methods manipulate it ifneeded.
In most cases, the fastest and easiest way is to return the results through acallback or variable specified in one of theadd_* functions. But there aresituations where this is not possible or desired. For these cases the resultsmay be obtained through one of the following functions. Please note that thesefunctions will do any type conversions and processing during the call so shouldnot used in performance critical code:
->results(): Retrieves a vector of strings with all the results in the orderthey were given.->results(variable_to_bind_to): Gets the results according to theMultiOptionPolicy and converts them just like theadd_option_functionwith avariable.Value=opt->as<type>(): Returns the result or default value directly as thespecified type if possible, can be vector to return all results, and anon-vector to get the result according to the MultiOptionPolicy in place. Ifit is expected that the results will be needed as a vector, it is suggestedthat->expected(CLI::details::expected_max_vector_size)orallow_extra_args()be used on the option to inform CLI11 that vector argsare expected and allowed.
Subcommands are keywords that invoke a new set of options and features. Forexample, thegit command has a long series of subcommands, likeadd andcommit. Each can have its own options and implementations. Subcommands aresupported in CLI11, and can be nested infinitely. To add a subcommand, call theadd_subcommand method with a name and an optional description. This gives apointer to anApp that behaves just like the main app, and can take options orfurther subcommands. Add->ignore_case() to a subcommand to allow anyvariation of caps to also be accepted.->ignore_underscore() is similar, butfor underscores. Children inherit the current setting from the parent. Youcannot add multiple matching subcommand names at the same level (includingignore_case andignore_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 exactnumber of subcommands to require, as well. If you give two arguments, that setsthe min and max number allowed. 0 for the max number allowed will allow anunlimited number of subcommands. As a handy shortcut, a single negative value Nwill set "up to N" values. Limiting the maximum number allows you to keeparguments that match a previous subcommand name from matching.
If anApp (main or subcommand) has been parsed on the command line,->parsedwill be true (or convert directly to bool). AllApps have aget_subcommands() method, which returns a list of pointers to the subcommandspassed on the command line. Agot_subcommand(App_or_name) method is alsoprovided that will check to see if anApp pointer or a string name wascollected 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 ofparsing; aC++ lambda function (with capture to get parsed values) can be usedas input to the callback definition function. If you throwCLI::Success orCLI::RuntimeError(return_value), you can even exit the program through thecallback.
Multiple subcommands are allowed, to allowClick like series ofcommands (order is preserved). The same subcommand can be triggered multipletimes but all positional arguments will take precedence over the second andfuture calls of the subcommand.->count() on the subcommand will return thenumber of times the subcommand was called. The subcommand callback will only betriggered once unless the.immediate_callback() flag is set or the callback isspecified through theparse_complete_callback() function. Thefinal_callback() is triggered only once. In which case the callback executeson completion of the subcommand arguments but after the arguments for thatsubcommand have been parsed, and can be triggered multiple times. Note that theparse_complete_callback() is executed prior to processing any config files.Thefinal_callback() is executed after config file processing.
Subcommands may also have an empty name either by callingadd_subcommand withan empty string for the name or with no arguments. Nameless subcommands functiona similarly to groups in the mainApp. SeeOption groups tosee how this might work. If an option is not defined in the main App, allnameless subcommands are checked as well. This allows for the options to bedefined in a composable group. Theadd_subcommand function has an overload foradding ashared_ptr<App> so the subcommand(s) could be defined in differentcomponents and merged into a mainApp, or possibly multipleApps. Multiplenameless subcommands are allowed. Callbacks for nameless subcommands are onlytriggered if any options from the subcommand were parsed. Subcommand names giventhrough theadd_subcommand method have the same restrictions as option names.
Options or flags in a subcommand may be directly specified using dot notation
--subcommand.long=val(long subcommand option)--subcommand.long val(long subcommand option)--subcommand.f=val(short form subcommand option)--subcommand.f val(short form subcommand option)--subcommand.f(short form subcommand flag)--subcommand1.subsub.f val(short form nested subcommand option)
The use of dot notation in this form is equivalent--subcommand.long <args> =>subcommand --long <args> ++. Nested subcommands also worksub1.subsub wouldtrigger the subsub subcommand insub1. This is equivalent to "sub1 subsub".Quotes around the subcommand names are permitted following the TOML standard forsuch specification. This includes allowing escape sequences. For example"subcommand".'f' or"subcommand.with.dots".arg1 = value.
There are several options that are supported on the main app and subcommands andoption_groups. These are:
.ignore_case(): Ignore the case of this subcommand. Inherited by addedsubcommands, so is usually used on the mainApp..ignore_underscore(): Ignore any underscores in the subcommand name.Inherited by added subcommands, so is usually used on the mainApp..allow_windows_style_options(): Allow command line options to be parsed inthe form of/s /long /file:file_name.extThis option does not change howoptions are specified in theadd_optioncalls or the ability to processoptions in the form of-s --long --file=file_name.ext..allow_non_standard_option_names(): Allow specification of single-longform option names. This is not recommended but is available to enablereworking of existing interfaces. If this modifier is enabled on an app orsubcommand, options or flags can be specified like normal but instead ofthrowing an exception, long form single dash option names will be allowed. Itis not allowed to have a single character short option starting with the samecharacter as a single dash long form name; for example,-sand-singlearenot allowed in the same application..allow_subcommand_prefix_matching():🆕 If this modifier is enabled,unambiguious prefix portions of a subcommand will match. For exampleupgrade_packagewould match onupgrade_,upg,uas long as no othersubcommand would also match. It also disallows subcommand names that are fullprefixes of another subcommand..fallthrough(): Allow extra unmatched options and positionals to "fallthrough" and be matched on a parent option. Subcommands by default are allowedto "fall through" as in they will first attempt to match on the currentsubcommand and if they fail will progressively check parents for matchingsubcommands. This can be disabled throughsubcommand_fallthrough(false)..subcommand_fallthrough(): Allow subcommands to "fall through" and bematched on a parent option. Disabling this prevents additional subcommands atthe same level from being matched. It can be useful in certain circumstanceswhere there might be ambiguity between subcommands and positionals. Thedefault is true..configurable(): Allow the subcommand to be triggered from a configurationfile. By default subcommand options in a configuration file do not trigger asubcommand but will just update default values..disable(): Specify that the subcommand is disabled, if given with a boolvalue it will enable or disable the subcommand or option group..disabled_by_default(): Specify that at the start of parsing thesubcommand/option_group should be disabled. This is useful for allowing someSubcommands to trigger others..enabled_by_default(): Specify that at the start of each parse thesubcommand/option_group should be enabled. This is useful for allowing someSubcommands to disable others..silent(): Specify that the subcommand is silent meaning that if used itwon't show up in the subcommand list. This allows the use of subcommands asmodifiers.validate_positionals(): Specify that positionals should pass validationbefore matching. Validation is specified throughtransform,check, andeachfor an option. If an argument fails validation it is not an error andmatching proceeds to the next available positional or extra arguments..validate_optional_arguments(): Specify that optional arguments should passvalidation before being assigned to an option. Validation is specified throughtransform,check, andeachfor an option. If an argument failsvalidation it is not an error and matching proceeds to the next availablepositional subcommand or extra arguments..excludes(option_or_subcommand): If given an option pointer or pointer toanother subcommand, these subcommands cannot be given together. In the case ofoptions, if the option is passed the subcommand cannot be used and willgenerate an error..needs(option_or_subcommand): If given an option pointer or pointer toanother subcommand, the subcommands will require the given option to have beengiven before this subcommand is validated which occurs prior to execution ofany callback or after parsing is completed..require_option(): Require 1 or more options or option groups be used..require_option(N): RequireNoptions or option groups, ifN>0, or up toNifN<0.N=0resets to the default to 0 or more..require_option(min, max): Explicitly set min and max allowed options oroption groups. Settingmaxto 0 implies unlimited options..require_subcommand(): Require 1 or more subcommands..require_subcommand(N): RequireNsubcommands ifN>0, or up toNifN<0.N=0resets to the default to 0 or more..require_subcommand(min, max): Explicitly set min and max allowedsubcommands. Settingmaxto 0 is unlimited..add_subcommand(name="", description=""): Add a subcommand, returns apointer to the internally stored subcommand..add_subcommand(shared_ptr<App>): Add a subcommand by shared_ptr, returns apointer 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 onthe command line..get_subcommands(filter): The list of subcommands that match a particularfilter function..add_option_group(name="", description=""): Add anoption group to an App, an option group is specializedsubcommand intended for containing groups of options or other groups forcontrolling how options interact..get_parent(): Get the parent App ornullptrif called on main App..get_option(name): Get an option pointer by option name will throw if thespecified option is not available, nameless subcommands are also searched.get_option_no_throw(name): Get an option pointer by option name. Thisfunction will return anullptrinstead of throwing if the option is notavailable..get_options(filter): Get the list of all defined option pointers (usefulfor processing the app for custom output formats)..parse_order(): Get the list of option pointers in the order they wereparsed (including duplicates)..formatter(std::shared_ptr<formatterBase> fmt): Set a custom formatter forhelp..formatter_fn(fmt), with signaturestd::string(const App*, std::string, AppFormatMode). Seeformatting formore details..config_formatter(std::shared_ptr<Config> fmt): set a custom configformatter for generating config files, more details available atConfigfiles.description(str): Set/change the description..get_description(): Access the description..alias(str): set an alias for the subcommand, this allows subcommands to becalled 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 wascalled..count_all(): Returns the total number of arguments a particular subcommandprocessed, on the main 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 thepre_parse_callbackor thefinal_callbackdepending on the value ofimmediate_callback. SeeSubcommand callbacks for someadditional details..parse_complete_callback(void() function): Set the callback that runs at thecompletion of parsing. For subcommands this is executed at the completion ofthe single subcommand and can be executed multiple times. SeeSubcommand callbacks for some additional details..final_callback(void() function): Set the callback that runs at the end ofall processing. This is the last thing that is executed before returning. SeeSubcommand callbacks for some additional details..immediate_callback(): Specifies whether the callback for a subcommandshould be run as aparse_complete_callback(true) orfinal_callback(false).When used on the main app it will execute the main app callback prior to thecallbacks for a subcommand if they do not also have theimmediate_callbackflag set. It is preferable to use theparse_complete_callbackorfinal_callbackdirectly instead of thecallbackandimmediate_callbackif one wishes to control the ordering and timing of callback. Thoughimmediate_callbackcan be used to swap them if that is needed..pre_parse_callback(void(std::size_t) function): Set a callback thatexecutes after the first argument of an application is processed. SeeSubcommand 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 lastarguments and throw an error if an unexpected positional is encountered..prefix_command(): Likeallow_extras, but stop processing immediately onthe first unrecognized item. All subsequent arguments are placed in theremaining_arg list. It is ideal for allowing your app or subcommand to be a"prefix" to calling another app..usage(message): Replace text to appear at the start of the help stringafter description..usage(std::string()): Set a callback to generate a string that will appearat the start of the help string after description..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 appearat the end of the help string..set_help_flag(name, message): Set the help flag name and message, returns apointer to the created option..set_version_flag(name, versionString or callback, help_message): Set theversion flag name and version string or callback and optional help 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::helpandCLI::FailureMessage::simple(the default)..group(name): Set a group name, defaults to"Subcommands". Setting anempty string for the name will be hide the subcommand.[option_name]: retrieve a const pointer to an option given byoption_namefor Exampleapp["--flag1"]will get a pointer to the option for the"--flag1" value,app["--flag1"]->as<bool>()will get the results of thecommand line for a flag. The operation will throw an exception if the optionname is not valid.
Note
If you have a fixed number of required positional options, that will matchbefore subcommand names.{} is an empty filter function, and any positionalargument will match before repeated subcommand names.
A subcommand has three optional callbacks that are executed at different stagesof processing. Thepreparse_callback is executed once after the first argumentof a subcommand or application is processed and gives an argument for the numberof remaining arguments to process. For the main app the first argument isconsidered the program name, for subcommands the first argument is thesubcommand name. For Option groups and nameless subcommands the first argumentis after the first argument or subcommand is processed from that group. Thesecond callback is executed after parsing. This is known as theparse_complete_callback. For subcommands this is executed immediately afterparsing and can be executed multiple times if a subcommand is called multipletimes. On the main app this callback is executed after all theparse_complete_callbacks for the subcommands are executed but prior to anyfinal_callback calls in the subcommand or option groups. If the main app orsubcommand has a config file, no data from the config file will be reflected inparse_complete_callback on named subcommands. Foroption_groups theparse_complete_callback is executed prior to theparse_complete_callback onthe main app but after theconfig_file is loaded (if specified). Thefinal_callback is executed after all processing is complete. After theparse_complete_callback is executed on the main app, the used subcommandfinal_callback are executed followed by the "final callback" for optiongroups. The last thing to execute is thefinal_callback for themain_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
pawill be called prior to parsing any values with an argument of 13.pc1will be called immediately after processing thesub1command with avalue of 10.c1will be called when thesub2command is encountered.pc2will be called with value of 6 after thesub2command is encountered.c1will be called again after the secondsub2command is encountered.ac1will be called after processing of all argumentsc2will be called once after processing all arguments.ac2will be called last after completing all lower level callbacks have beenexecuted.
A subcommand is considered terminated when one of the following conditions aremet.
- There are no more arguments to process
- Another subcommand is encountered that would not fit in an optionalpositional slot of the subcommand
- The
positional_mark(--) is encountered and there are no availablepositional slots in the subcommand. - The
subcommand_terminatormark (++) is encountered
Prior to executed aparse_complete_callback all contained options areprocessed before the callback is triggered. If a subcommand with aparse_complete_callback is called again, then the contained options are reset,and can be triggered again.
The subcommand method
.add_option_group(name,description)
Will create an option group, and return a pointer to it. The argument fordescription is optional and can be omitted. An option group allows creation ofa collection of options, similar to the groups function on options, but withadditional controls and requirements. They allow specific sets of options to becomposed and controlled as a collective. For an example seerange example.Option groups are a specialization of an App so allfunctions that work with an App or subcommand also workon option groups. Options can be created as part of an option group using theadd functions just like a subcommand, or previously created options can be addedthrough. The name given in an option group must not contain newlines or nullcharacters.
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 parentapplication 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 optiongroup.
Options in an option group are searched for a command line match after anyoptions in the main app, so any positionals in the main app would be matchedfirst. So care must be taken to make sure of the order when using positionalarguments and option groups. Option groups work well withexcludes andrequire_options methods, as an application will treat an option group as asingle option for the purpose of counting and requirements, and an option groupwill be considered used if any of the options or subcommands contained in it areused. Option groups allow specifying requirements such as requiring 1 of 3options in one group and 1 of 3 options in a different group. Option groups cancontain other groups as well. Disabling an option group will turn off alloptions within the group.
TheCLI::TriggerOn andCLI::TriggerOff methods are helper functions to allowthe use of options/subcommands from one group to trigger another group on oroff.
CLI::TriggerOn(group1_pointer, triggered_group);CLI::TriggerOff(group2_pointer, disabled_group);
These functions make use ofpreparse_callback,enabled_by_default() anddisabled_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 previoususe of the underlying functions. More complex arrangements can be accomplishedusing similar methodology with a custompreparse_callback function that doesmore.
Additional helper functionsdeprecate_option andretire_option are availableto 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 thehelp and a warning on first usage. Deprecated options function normally but willadd 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 onfirst usage that the option is retired and has no effect. If the option existsit 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 behidden 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 helpstring. For the purposes of help display, if the option group name starts with a'+' it is treated as if it were not in a group for help and get_options. Forexample:
auto added_group=app.add_option_group("+sub");
In this case the help output will not reference the option group and optionsinside of it will be treated for most purposes as if they were part of theparent.
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 fileoption (likeset_help_flag). Setting a configuration option is special. If itis present, it will be read along with the normal command line arguments. Thefile will be read if it exists, and does not throw an error unlessrequired istrue. Configuration files are inTOML format by default, though thedefault reader can also accept files in INI format as well. The config readercan read most aspects of TOML files including strings both literal and withpotential escape sequences, digit separators, and multi-line strings, and runthem through the CLI11 parser. Other formats can be added by an adept user, somevariations 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-insensitivevalue =1value2 =123_456# a string with separatorsstr ="A string"str2 ="A string\nwith new lines"str3 ='A literal "string"'vector = [1,2,3]str_vector = ["one","two","and three"]# Sections map to subcommands[subcommand]in_subcommand = Wowsub.subcommand =true"sub"."subcommand2" ="string_value"
or equivalently in INI format
; Comments are supported, using a ;; The default section is [default], case-insensitivevalue = 1str ="A string"vector = 1 2 3str_vector ="one""two""and three"; Sections map to subcommands[subcommand]in_subcommand = Wowsub.subcommand = true
Spaces before and after the name and argument are ignored. Multiple argumentsare separated by spaces. One set of quotes will be removed, preserving spaces(the same way the command line works). Boolean options can betrue,on,1,yes,enable; orfalse,off,0,no,disable (case-insensitive).Sections (and. separated names) are treated as subcommands (note: this doesnot necessarily mean that subcommand was passed, it just sets the "defaults").You cannot set positional-only arguments. Subcommands can be triggered fromconfiguration files if theconfigurable flag was set on the subcommand. Thenthe use of[subcommand] notation will trigger a subcommand and cause it to actas 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), wheredefault_also will also show any defaulted arguments, andwrite_descriptionwill include the app and option descriptions. SeeConfig files forsome additional details and customization points.
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 toX configuration files tobe specified by separate--config arguments. Value strings with quotecharacters in it will be printed with a single quote. All other arguments willuse double quote. Empty strings will use a double quoted argument. Numerical orboolean values are not quoted.
For options or flags which allow 0 arguments to be passed using an empty stringin the config file,{}, or[] will convert the result to the default valuespecified viadefault_str ordefault_val on the option. If no user specifieddefault is given the result is an empty string or the converted value of anempty string.
NOTE: Transforms and checks can be used with the option pointer returned fromset_config like any other option to validate the input if needed. It can also beused with the built in transformCLI::FileOnDefaultPath to look in a defaultpath as well as the current one. For example
app.set_config("--config")->transform(CLI::FileOnDefaultPath("/to/default/path/"));
SeeTransforming Validators for additional detailson this validator. Multiple transforms or validators can be used either bymultiple calls or using| operations with the transform.
Many of the defaults for subcommands and even options are inherited from theircreators. The inherited default values for subcommands areallow_extras,prefix_command,ignore_case,ignore_underscore,fallthrough,group,usage,footer,immediate_callback and maximum number of requiredsubcommands. The help flag existence, name, and description are inherited, aswell.
Options have defaults forgroup,required,multi_option_policy,ignore_case,ignore_underscore,delimiter, anddisable_flag_override. Toset these defaults, you should set theoption_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.
The job of formatting help printouts is delegated to a formatter object. You arefree to replace the formatter with a custom one by callingformatter(fmt) onanApp. CLI11 comes with a default App formatter,Formatter. You canretrieve the formatter via.get_formatter() this will return a pointer to thecurrentFormatter. It is customizable; you can setlabel(key, value) toreplace the default labels likeREQUIRED, andOPTIONS. You can also setcolumn_width(n) to set the width of the columns before you add the functionalto the app or option. Several other configuration options are also available intheFormatter. You can also override almost any stage of the formattingprocess in a subclass of either formatter. If you want to make a new formatterfrom scratch, you can do that too; you just need to implement the correctsignature. seeformatting for more details.
The App class was designed allow toolkits to subclass it, to provide presetdefault options (see above) and setup/teardown code. Subcommands remain anunsubclassedApp, since those are not expected to need setup and teardown. ThedefaultApp only adds a help flag,-h,--help, than can removed/replacedusing.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 (onelevel only). You can remove options if you have pointers to them using.remove_option(opt). You can add apre_callback override to customize theafter parse but before run behavior, while still giving the user freedom tocallback on the main app.
The most important parse function isparse(std::vector<std::string>), whichtakes a reversed list of arguments (so thatpop_back processes the args in thecorrect order).get_help_ptr andget_config_ptr give you access to thehelp/config option pointers. The standardparse manually sets the name fromthe first argument, so it should not be in this vector. You can also useparse(string, bool) to split up and parse a single string; the optionalboolean should be set to true if you are including the program name in thestring, and false otherwise. The program name can contain spaces if it is anexisting file, otherwise can be enclosed in quotes(single quote, double quote orbacktick). Embedded quote characters can be escaped with\.
Also, in a related note, theApp you get a pointer to is stored in the parentApp in ashared_ptrs (similar toOptions) and are deleted when the mainApp goes out of scope unless the object has another owner.
Everyadd_ option you have seen so far depends on one method that takes alambda function. Each of these methods is just making a different lambdafunction with capture to populate the option. The function has full access tothe vector of strings, so it knows how many times an option was passed or howmany arguments it received. The lambda returnstrue if it could validate theoption strings, andfalse if it failed.
Other values can be added as long as they supportoperator>> (and defaults canbe printed if they supportoperator<<). To add a new type, for example,provide a customoperator>> with anistream (inside the CLI namespace isfine if you don't want to interfere with an existingoperator>>).
If you wanted to extend this to support a completely new type, use a lambda oradd an overload of thelexical_cast function in the namespace of the type youneed to convert to. Some examples of some new parsers forcomplex<double> thatsupport all of the features of a standardadd_options call are inone of the tests. A simpler example is shown below:
app.add_option("--fancy-count", [](std::vector<std::string> val){ std::cout <<"This option was given" << val.size() <<" times." << std::endl;returntrue; });
CLI11 supports Unicode and wide strings as defined in theUTF-8 Everywhere manifesto. In particular:
- The library can parse a wide version of command-line arguments on Windows,which are converted internally to UTF-8 (more on this below);
- You can store option values in
std::wstring, in which case they will beconverted to a correct wide string encoding on your system (UTF-16 on Windowsand UTF-32 on most other systems); - Instead of storing wide strings, it is recommended to use provided
widenandnarrowfunctions to convert to and from wide strings when actually necessary(such as when calling into Windows APIs).
When using the command line on Windows with unicode arguments, yourmainfunction may already receive broken Unicode. Parsingargv at that point willnot give you a correct string. To fix this, you have three options; the first isrecommended for cross-platform support:
1. Replaceargv withapp.ensure_utf8(argv) before any arguments are parsed.ensure_utf8 will do nothing on systems whereargv is already in UTF-8 (Suchas Linux or macOS) and returnargv unmodified. On Windows, it will discardargv and replace it with a correctly decoded array or arguments from win32API.
intmain(int argc,char** argv) { CLI::App app; argv = app.ensure_utf8(argv);// new argv memory is held by app// ...CLI11_PARSE(app, argc, argv);}
Be sure you do not modifyargv before this function call, as the correctvalues will be reconstructed using Windows APIs and produced by this call. Ithas no effect on other platforms and just passes throughargv.
Other options (click to expand)
2. Use the Windows-only non-standardwmain function, which acceptswchar_t *argv[] instead ofchar* argv[]. Parsing this will allow CLI toconvert wide strings to UTF-8 without losing information.
intwmain(int argc,wchar_t *argv[]) { CLI::App app;// ...CLI11_PARSE(app, argc, argv);}
3. Retrieve arguments yourself by using Windows APIs likeCommandLineToArgvWand pass them to CLI. This is what the library is doing under the hood inensure_utf8.
The library provides functions to convert between UTF-8 and wide strings:
namespaceCLI { std::stringnarrow(const std::wstring &str); std::stringnarrow(constwchar_t *str); std::stringnarrow(constwchar_t *str, std::size_t size); std::stringnarrow(std::wstring_view str);// C++17 std::wstringwiden(const std::string &str); std::wstringwiden(constchar *str); std::wstringwiden(constchar *str, std::size_t size); std::wstringwiden(std::string_view str);// C++17}
When creating afilesystem::path from a UTF-8 path on Windows, you need toconvert it to a wide string first. CLI11 provides a platform-independentto_path function, which will convert a UTF-8 string to path, the right way:
std::string utf8_name ="Hello Halló Привет 你好 👩🚀❤️.txt";std::filesystem::path p = CLI::to_path(utf8_name);std::ifstreamstream(CLI::to_path(utf8_name));// etc.
There are a few other utilities that are often useful in CLI programming. Theseare in separate headers, and do not appear inCLI11.hpp, but are completelyindependent and can be used as needed. TheTimer/AutoTimer class allows youto 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 theoutput using the predefinedBig output (default:Simple). Because it is anAutoTimer, it will print out the time elapsed when the timer is destroyed atthe end of the block. If you useTimer instead, you can useto_string orstd::cout << timer << std::endl; to print the time. The print function can beany function that takes two strings, the title and the time, and returns aformatted string for printing.
If you use the excellentRang library to add color to your terminal in asafe, 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 theterminal 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>voidsignal_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-Cstructsigaction sigIntHandler; sigIntHandler.sa_handler = signal_handler;sigemptyset(&sigIntHandler.sa_mask); sigIntHandler.sa_flags =0;sigaction(SIGINT, &sigIntHandler,nullptr);
The API isdocumented here. Also see theCLI11 tutorialGitBook.
Several short examples of different features are included in the repository. Abrief description of each is included here
- arg_capture:Example of capturing all remaining arguments after a specific option, usingsubcommand and prefix_command() with an alias.
- callback_passthrough:Example of directly passing remaining arguments through to a callback functionwhich generates a CLI11 application based on existing arguments.
- custom_parse:Based onIssue #566, exampleof custom parser
- digit_args:Based onIssue #123, usesdigit flags to pass a value
- enum: Usingenumerations in an option, and the use ofCheckedTransformer
- enum_ostream:In addition to the contents of example enum.cpp, this example shows how acustom 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 timer helper class
- inter_argument_order:An app to practice mixing unlimited arguments, but still recover the originalorder.
- json: UsingJSON 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. BasedonIssue #88 to set interactinggroups of options
- positional_arity:Illustrating use of
preparse_callbackto handle situations where the numberof arguments can determine which should get parsed, Based onIssue #166 - positional_validation:Example of how positional arguments are validated using the
validate_positionalflag, also based onIssue #166 - prefix_command:Illustrating use of the
prefix_commandflag. - ranges: Appto demonstrate exclusionary option groups based onIssue #88
- shapes:Illustrating how to set up repeated subcommands Based ongitter discussion
- simple: Asimple example of how to set up a CLI11 Application with different flags andoptions
- subcom_help:Configuring help for subcommands
- subcom_partitioned:Example with a timer and subcommands generated separately and added to themain app later.
- subcommands:Short example of subcommands
- validators:Example illustrating use of validators
- custom validators:Example illustrating use of validators
- date validators:Example illustrating use of validators
To contribute, open anissue orpullrequest on GitHub, or ask a question ongitter. Thereis also ashort note to contributors. This readmeroughly follows theStandard Readme Style and includes a mention of almostevery feature of the library. More complex features are documented in moredetail in theCLI11 tutorial GitBook.
This project was created byHenry Schreiner andmajor features were added byPhilip Top. Specialthanks to all the contributors(emoji key):
This project follows theall-contributorsspecification. Contributions of any kind welcome!
As of version 1.0, this library is available under a 3-Clause BSD license. SeetheLICENSE file for details.
CLI11 was developed at theUniversity of Cincinnati to support of theGooFit library underNSF Award 1414736. Version 0.9 was featured in aDIANA/HEP meeting at CERN (see the slides). Please give it atry! Feedback is always welcome.
About
CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface.
Resources
License
Contributing
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Languages
- C++93.5%
- CMake5.2%
- Other1.3%
