Lightweight C++ command line option parser

Overview

Build Status

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

If you have used version 2, there are a couple of breaking changes in (the as yet unreleased, current master) version 3 that you should be aware of. If you are new to cxxopts you can skip this section.

The parser no longer modifies its arguments, so you can pass a const argc and argv and expect them not to be changed.

The ParseResult object no longer depends on the parser. So it can be returned from a scope outside the parser and still work. Now that the inputs are not modified, ParseResult stores a list of the unmatched arguments. These are retrieved like follows:

auto result = options.parse(argc, argv);
result.unmatched(); // get the unmatched arguments

Quick start

This is a lightweight C++ option parser library, supporting the standard GNU style syntax for options.

Options can be given as:

--long
--long=argument
--long argument
-a
-ab
-abc argument

where c takes an argument, but a and b do not.

Additionally, anything after -- will be parsed as a positional argument.

Basics

#include <cxxopts.hpp>

Create a cxxopts::Options instance.

cxxopts::Options options("MyProgram", "One line description of MyProgram");

Then use add_options.

options.add_options()
  ("d,debug", "Enable debugging") // a bool parameter
  ("i,integer", "Int param", cxxopts::value<int>())
  ("f,file", "File name", cxxopts::value<std::string>())
  ("v,verbose", "Verbose output", cxxopts::value<bool>()->default_value("false"))
  ;

Options are declared with a long and an optional short option. A description must be provided. The third argument is the value, if omitted it is boolean. Any type can be given as long as it can be parsed, with operator>>.

To parse the command line do:

auto result = options.parse(argc, argv);

To retrieve an option use result.count("option") to get the number of times it appeared, and

result["opt"].as<type>()

to get its value. If "opt" doesn't exist, or isn't of the right type, then an exception will be thrown.

Note that the result of options.parse should only be used as long as the options object that created it is in scope.

Unrecognised arguments

You can allow unrecognised arguments to be skipped. This applies to both positional arguments that are not parsed into another option, and -- arguments that do not match an argument that you specify. This is done by calling:

options.allow_unrecognised_options();

and in the result object they are retrieved with:

result.unmatched()

Exceptions

Exceptional situations throw C++ exceptions. There are two types of exceptions: errors defining the options, and errors when parsing a list of arguments. All exceptions derive from cxxopts::OptionException. Errors defining options derive from cxxopts::OptionSpecException and errors parsing arguments derive from cxxopts::OptionParseException.

All exceptions define a what() function to get a printable string explaining the error.

Help groups

Options can be placed into groups for the purposes of displaying help messages. To place options in a group, pass the group as a string to add_options. Then, when displaying the help, pass the groups that you would like displayed as a vector to the help function.

Positional Arguments

Positional arguments can be optionally parsed into one or more options. To set up positional arguments, call

options.parse_positional({"first", "second", "last"})

where "last" should be the name of an option with a container type, and the others should have a single value.

Default and implicit values

An option can be declared with a default or an implicit value, or both.

A default value is the value that an option takes when it is not specified on the command line. The following specifies a default value for an option:

cxxopts::value<std::string>()->default_value("value")

An implicit value is the value that an option takes when it is given on the command line without an argument. The following specifies an implicit value:

cxxopts::value<std::string>()->implicit_value("implicit")

If an option had both, then not specifying it would give the value "value", writing it on the command line as --option would give the value "implicit", and writing --option=another would give it the value "another".

Note that the default and implicit value is always stored as a string, regardless of the type that you want to store it in. It will be parsed as though it was given on the command line.

Boolean values

Boolean options have a default implicit value of "true", which can be overridden. The effect is that writing -o by itself will set option o to true. However, they can also be written with various strings using =value. There is no way to disambiguate positional arguments from the value following a boolean, so we have chosen that they will be positional arguments, and therefore, -o false does not work.

std::vector<T> values

Parsing of list of values in form of an std::vector<T> is also supported, as long as T can be parsed. To separate single values in a list the definition CXXOPTS_VECTOR_DELIMITER is used, which is ',' by default. Ensure that you use no whitespaces between values because those would be interpreted as the next command line option. Example for a command line option that can be parsed as a std::vector<double>:

--my_list=1,-2.1,3,4.5

Options specified multiple times

The same option can be specified several times, with different arguments, which will all be recorded in order of appearance. An example:

--use train --use bus --use ferry

this is supported through the use of a vector of value for the option:

options.add_options()
  ("use", "Usable means of transport", cxxopts::value<std::vector<std::string>>())

Custom help

The string after the program name on the first line of the help can be completely replaced by calling options.custom_help. Note that you might also want to override the positional help by calling options.positional_help.

Example

Putting all together:

int main(int argc, char** argv)
{
    cxxopts::Options options("test", "A brief description");

    options.add_options()
        ("b,bar", "Param bar", cxxopts::value<std::string>())
        ("d,debug", "Enable debugging", cxxopts::value<bool>()->default_value("false"))
        ("f,foo", "Param foo", cxxopts::value<int>()->default_value("10"))
        ("h,help", "Print usage")
    ;

    auto result = options.parse(argc, argv);

    if (result.count("help"))
    {
      std::cout << options.help() << std::endl;
      exit(0);
    }
    bool debug = result["debug"].as<bool>();
    std::string bar;
    if (result.count("bar"))
      bar = result["bar"].as<std::string>();
    int foo = result["foo"].as<int>();

    return 0;
}

Linking

This is a header only library.

Requirements

The only build requirement is a C++ compiler that supports C++11 features such as:

  • regex
  • constexpr
  • default constructors

GCC >= 4.9 or clang >= 3.1 with libc++ are known to work.

The following compilers are known not to work:

  • MSVC 2013

TODO list

  • Allow unrecognised options.
Comments
  • options.help({}) doesn't show positional arguments sometimes

    options.help({}) doesn't show positional arguments sometimes

    Code sample:

    int main(int argc, char *argv[]) {
        try {
            cxxopts::Options options(argv[0], "Sample");
            options.positional_help("<Extra args>");
            
            options.add_options()
            ("s,set", "Set whatever.", cxxopts::value<std::vector<std::string>>())
            ("h,help", "Print help and exit.")
            ;
           
            options.parse(argc, argv);
            options.parse_positional({"file", "remove-label", "set-label"});
           
            // help
            if (options.count("help")) {
            cout << options.help({""}) << std::endl;
            exit(0);
            }
        } catch (const cxxopts::OptionException& e) {
            cout << "error parsing options: " << e.what() << std::endl;
            exit(-1);
            }
        return 0;
    }
    

    Expected: Show the "set" option in the help. Actual: Show only "help" option.

    opened by assapir 20
  • Why parsing empty text in parse_value ?

    Why parsing empty text in parse_value ?

    in template <typename T> void parse_value(const std::string& text, std::vector<T>& value) there is a branch for empty text like this:

          if (text.empty()) {
            T v;
            parse_value(text, v);
            value.emplace_back(std::move(v));
            return;
          }    
    

    Why would we ever want to parse empty text ? Why even emplacing back a value in the vector with an empty text ?

    This seems to fails and throw in certain cases.

    opened by mwestphal 17
  • Compiler error when calling parse function with mutable argv

    Compiler error when calling parse function with mutable argv

    Since #99 was merged (I’m using cxxopts 2.1.0 now), simple usage examples like the following fail:

    #include <cxxopts.hpp>
    
    int main(int argc, char *argv[])
    {
    	cxxopts::Options options("test");
    	options.parse(argc, argv);
    
    	return 0;
    }
    

    with the error message (g++ 7.3.1):

    test.cpp: In function ‘int main(int, char**)’:
    test.cpp:6:26: error: invalid conversion from ‘char**’ to ‘const char**’ [-fpermissive]
      options.parse(argc, argv);
                              ^
    In file included from test.cpp:1:0:
    cxxopts.hpp:1642:1: note:   initializing argument 2 of ‘cxxopts::ParseResult cxxopts::Options::parse(int&, const char**&)’
     Options::parse(int& argc, const char**& argv)
     ^~~~~~~
    test.cpp:6:26: error: cannot bind rvalue ‘(const char**)argv’ to ‘const char**&’
      options.parse(argc, argv);
    

    The reason is that char *argv[] (or char **argv) cannot be implicitly converted to const char **, which is used in all parse function signatures.

    I know that #99 added the const qualifier for a reason. I like the idea suggested by @vladimirgamalyan in #91 to turn const char **&argv in the parse function signatures into const char * const *&argv. However, I think that’s not possible right now, because argv is modified by cxxopts such as in:https://github.com/jarro2783/cxxopts/blob/0fe1dc892bcbef48b3911510209c7033f31ce05e/include/cxxopts.hpp#L1681

    Still, I think that this should be addressed, because int main(int argc, char *argv[]) is a standard main function signature, which should be supported by cxxopts. If that’s not feasible, it would be good to mention this in the readme at least :slightly_smiling_face:.

    opened by pluehne 17
  • my_program -DFOO=bar fails to parse

    my_program -DFOO=bar fails to parse

    I'm running the following program:

    #include <cxxopts/cxxopts.hpp>
    #include <vector>
    #include <string>
    
    int main(int argc, char** argv)
    {
        cxxopts::Options options { argv[0], "test program"};
        options.add_options()
            ("D,define", "description here", cxxopts::value<std::vector<std::string>>())
            ;
        options.parse(argc, argv);
    }
    

    and, when building with the master branch (or v3.0.0), I get this:

    $ ./my_program -DA_LITTLE_EXTRA=1
    terminate called after throwing an instance of 'cxxopts::option_syntax_exception'
      what():  Argument ‘-DA_LITTLE_EXTRA=1’ starts with a - but has incorrect syntax
    Aborted
    

    Despite the fact that, supposedly, #158 is fixed.

    opened by eyalroz 15
  • Making sure that the library can compile without warnings even when crazy pedantic flags are set

    Making sure that the library can compile without warnings even when crazy pedantic flags are set

    We use cxxopts in simdjson since some of our users get upset if they get warnings (sometimes calling these warnings 'bugs').

    We can disable the warnings on our end, but it might be nicer for everyone if cxxopts was also "warning free". This PR should help.

    It does two things:

    • It adds the "{}" suffix to class-type attributes that are not explicitly initialized by all constructors. This effectively makes sure that they are initialized with a default constructor.
    • It disables some specific GCC warning for the duration of the definition/declaration of a class.

    None of these changes should impact the performance or the functionality of the library.

    Note that it is not my claim that I am fixing defects. This is purely to save time in the long term by not getting warnings.

    cc @jkeiser


    This change is Reviewable

    opened by lemire 14
  • No support for short name argument with no space before value

    No support for short name argument with no space before value

    getopt supports the following syntax [link]:

    % testopt -cfoo
    aflag = 0, bflag = 0, cvalue = foo
    

    However cxxopts throws option_requires_argument_exception for the same construction.

    enhancement 
    opened by Qartar 14
  • Improve formatting of help descriptions

    Improve formatting of help descriptions

    • new function: cxxopts::Option::set_width(size_t width) Set the size of a helpline.
    • new function: cxxopts::Option::set_tab_expansion() Expand the tabs in descriptions. The tabsize 8 chars, base is start of description. The descriptions are not disturbed by adding additional options.
    • Allow newlines \n nad tabs \t in descriptions.

    Other changes (last commit/new commit):

    • 1453/1471: size_t for OPTION_LONGEST and OPTION_DESC_GAP. This prevents the static cast in 2086/2140.
    • 2088/2142: in case of small width the value of "width - longest - OPTION_DEC_GAP" becomes negative. Because size_t is unsigned the result is a big number, and the width of the column of the descriptions is not shortened.
    • new 2143: When the given width is too small, it is set to longest + OPTION_DESC_GAP + 10
    • new 1570: A long description is broken into multiple lines, and the iterator lastSpace remembers the begin of the last word. But when the iterator current reaches the end of line, the whole string from iterator is printed, which in soome cases is too long. Thats why one blank is added to the description to trigger the handling of lastSpace. Accordingly in 1574/1627 the line is shortened by one char.

    This change is Reviewable

    opened by wgahr123 13
  • Support option name aliases / multiple long options

    Support option name aliases / multiple long options

    (This is a feature I added to boost::program_options a couple of years back.)

    Right now, if you name an option "x,long-name-of-x,another-long-name-of-x" - you get an error:

    terminate called after throwing an instance of 'cxxopts::invalid_option_format_error'
      what():  Invalid option format 'x,long-name-of-x,another-long-name-of-x'
    

    instead, cxxopts should support having multiple aliases for the (first and primary) name of the option - all of which would be accepted on the command-line just as though the primary name were used.

    opened by eyalroz 12
  • error parsing options: Option ├óΓé¼╦£t├óΓé¼Γäó does not exist

    error parsing options: Option ‘t’ does not exist

    I get a strange strings when running this code without a valid option:

     options.add_options("")
    	("a,aaaa", "aaaa type", cxxopts::value<std::string>()->default_value("bbbb"), "bbbb or cccc")
    			("h,help", "Print help");
    	options.parse(argc, argv);
    	if (options.count("help"))
    	{
    		std::cout << options.help({ "", "Group" }) << std::endl;
    		exit(0);
    	}
    
    
    

    Build is on Windows with MSVC community 15

    opened by mulderp 12
  • Default and implicit values

    Default and implicit values

    This patch add support for default values and implicit values.

    They can be used like that:

      ("o,output", "Output file", cxxopts::value<std::string>()->default_value("a.out")->implicit_value("b.def"))
    

    You can specify either the default value or the implicit value or both. I took the same model as was done in Boost Program Options.

    While implementing this, I was wondering if the class Value was really useful, I think it would be better to directly expose default_value (renamed it to standard_value), don't you think ? It would make the code easier and it would remove the virtuality of the functions.

    I tried not to screw you code style, but my editor is not configured for that, so I may have made some mistakes on that side.

    opened by wichtounet 12
  • MACRO min/max under WINDOWS

    MACRO min/max under WINDOWS

    C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1342): error C2589: '(': illegal token on right side of '::' 
    C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1342): error C2062: type 'unknown-type' unexpected 
    C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1342): error C2059: syntax error: ')' 
    C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1346): error C2589: '(': illegal token on right side of '::' 
    C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1346): error C2062: type 'unknown-type' unexpected 
    C:\dev\workspace\z_eph\tool\utils\cxxopts.hpp(1346): error C2059: syntax error: ')' 
    
    

    the errors related with min and max in the library cxxopts.hpp:

                longest = std::max(longest, stringLength(s));
                format.push_back(std::make_pair(s, String()));
            }
    
            longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));
    
    

    the problem (Windows specifics) usually related with that there are macro definitions for min and max. this (below) solves the problem :

    image

    I'll perform some tests and if this woks okay and will raise a PR with WINDOWS only ifdef

    invalid 
    opened by amigo421 11
  • Support the use of std::optional's in cxxopts::ParseResult::as()

    Support the use of std::optional's in cxxopts::ParseResult::as()

    Suppose I define a non-boolean option of type T, without a default value, using cxxopts.

    I can't obtain this option using just cxxopts::ParseResults::as<T>() - because that might throw. Instead, I have to first use count(), like in the README example code:

    if (result.count("bar"))
      bar = result["bar"].as<std::string>();
    

    This is somewhat redundant. Why do I have to say "bar" twice? ... instead, I should be able to write:

    auto bar = result["bar"].as<std::optional<std::string>>()
    

    and get an optional which is nullopt if bar wasn't specified, and a boxed actual string if it was.

    Bonus points if you support std::experimental::optional when C++14 is used.

    opened by eyalroz 2
  • Comma Delimiter Breaking Quoted Strings

    Comma Delimiter Breaking Quoted Strings

    Parsing an argument into a vector using the CXXOPTS_VECTOR_DELIMITER interacts unexpectedly with arguments in quotes.

    Expected Result:

    Providing the argument --strings "string_one","string,two" would be parsed as a vector with two strings: "string_one" and "string,two".

    Actual Result:

    Providing the argument --strings "string_one","string,two" is parsed as a vector with three strings: "string_one", "string", and "two".

    It would be great if the delimiter was disabled when parsing an argument in quotes, or possibly the delimiter could be escaped with: \,.

    opened by DauntlessStudio 0
  • How about to limit the values of option with user specified value set?

    How about to limit the values of option with user specified value set?

    options.add_options()(
        "opt", "desc",
        cxxopts::value<std::string>()->limit_value(
            std::unordered_set<std::string>{"only", "these", "values", "are", "allowed"}));
    
    opened by mrbeardad 1
  • Throw exception in parse when there is no argument value for a positional option without default value

    Throw exception in parse when there is no argument value for a positional option without default value

    Current Behavior

      cxxopts::Options o{"", ""};
      o.add_options()("a", "", cxxopts::value<std::string>());
      o.parse_positional({"a"});
      std::vector<const char*> arg = {"a.out"};
      auto r = o.parse(arg.size(), arg.data());
      EXPECT_ANY_THROW(r["a"].as<std::string>());
    

    Expected Behavior

      cxxopts::Options o{"", ""};
      o.add_options()("a", "", cxxopts::value<std::string>());
      o.parse_positional({"a"});
      std::vector<const char*> arg = {"a.out"};
      EXPECT_ANY_THROW(o.parse(arg.size(), arg.data()));
    
    opened by mrbeardad 2
  • Exception when calling xxx.as<T>()...

    Exception when calling xxx.as()...

    I've a project under MSVC 2017. If CXXOPTS_NO_RTTI is not defined, any call to xxx.as<T>() produce an exception.

    Exception occurs at line 1458 of cxxopts.hpp, deeper at line 291 of rtti.cpp.

    Unhandled exception at 0x00007FFAB6D24FD9 in bla.exe: Microsoft C++ exception: std::__non_rtti_object at memory location 0x000000FEE92FE820.

    opened by FredM67 2
  • Please improve explanation of positional arguments

    Please improve explanation of positional arguments

    The readme is very inadequate. There is a line

    options.parse_positional({"script", "server", "filenames"})
    

    which 1. does not end in a semicolon 2. does not have argc/argv unlike the regular parse call, 3. does not assign its result to anything. My best guess

    auto kwresult = options.parse_positional( {"foo"} );
    

    has "incomplete type" according to gcc.

    Please clarify.

    opened by VictorEijkhout 3
Releases(v3.0.0)
  • v3.0.0(May 2, 2022)

    This is a major new release. The most significant change is that the parser now returns an object with the parse result, and does not modify argc or argv. The result object does not depend on the parser, so the following is now possible:

    auto result = options.parse(argc, argv);
    return result;
    

    What's Changed

    Changed

    • Only search for a C++ compiler in CMakeLists.txt.
    • Allow for exceptions to be disabled.
    • Fix duplicate default options when there is a short and long option.
    • Add CXXOPTS_NO_EXCEPTIONS to disable exceptions.
    • Fix char parsing for space and check for length.
    • Change argument type in Options::parse from char** to const char**.
    • Refactor parser to not change its arguments.
    • ParseResult doesn't depend on a reference to the parser.
    • Fixed several warnings and code quality issues.
    • Improved formatting for help descriptions.
    • Improve integer parsing.

    Added

    • A list of unmatched arguments is available in ParseResult.
    • Support single letter options with argument attached.
    • Use if it is present.

    Bug Fixes

    • Fix missing option name in exception.
    Source code(tar.gz)
    Source code(zip)
Owner
null
CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface.

CLI11: Command line parser for C++11 What's new • Documentation • API Reference CLI11 is a command line parser for C++11 and beyond that provides a ri

null 2.4k Dec 30, 2022
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
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
LwSHELL is lightweight, platform independent, command line shell for embedded systems.

LwSHELL is lightweight, platform independent, command line shell for embedded systems. It targets communication with embedded systems from remote terminal to quickly send commands and the retrieve data from the device.

Tilen Majerle 80 Dec 25, 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 library for interactive command line interfaces in modern C++

cli A cross-platform header only C++14 library for interactive command line interfaces (Cisco style) Features Header only Cross-platform (linux and wi

Daniele Pallastrelli 888 Dec 31, 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
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
pbr2gltf2 is a command line tool for converting PBR images to a glTF 2.0 material.

pbr2gltf2 is a command line tool for converting PBR images to a glTF 2.0 material. The tool is detecting depending on the filename, which PBR information is stored. It swizzles the images and does reassign the channels to a glTF 2.0 image. The tool stores the images plus a minimal, valid glTF 2.0 file containing the required material, textures and images.

UX3D GmbH 23 Jul 31, 2022
null 77 Dec 27, 2022
A command-line tool to display colorful distro information.

sjfetch A command-line tool to display colorful distro information.

Fikret Musk 6 Apr 6, 2022
Toybox: all-in-one Linux command line.

Toybox: all-in-one Linux command line.

Rob Landley 1.8k Dec 27, 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
Command-line flag parsing in C

flag.h Inspired by Go's flag module: https://pkg.go.dev/flag WARNING! The design of the library is not finished and may be a subject to change. Quick

Tsoding 41 Nov 10, 2022
A command line tool with no external dependencies to print information about an X server instance.

xinfo A command line tool with no external dependencies to print information about an X server instance. Building and running To build the code in thi

Jean-Michel Gorius 6 Jan 13, 2022
Windows command line program for Spleeter, written in pure C, no need of Python.

SpleeterMsvcExe is a Windows command line program for Spleeter, which can be used directly. It is written in pure C language, using ffmpeg to read and write audio files, and using Tensorflow C API to make use of Spleeter models. No need to install Python environment, and it does not contain anything related to Python.

Wudi 181 Dec 5, 2022
easy to use, powerful & expressive command line argument parsing for modern C++ / single header / usage & doc generation

clipp - command line interfaces for modern C++ Easy to use, powerful and expressive command line argument handling for C++11/14/17 contained in a sing

André Müller 977 Dec 29, 2022
Parse command line arguments by defining a struct

Parse command line arguments by defining a struct Quick Start #include <structopt/app.hpp> struct Options { // positional argument // e.g., .

Pranav 420 Dec 20, 2022