Lightweight C++ command line option parser

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.

  • 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.

  • 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:.

  • 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.

  • 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

  • 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.

  • 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

  • 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.

  • 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

  • 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.

  • 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

  • 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.

  • 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: \,.

  • 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"}));
    
  • 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()));
    
  • 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.

  • 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.

MiWi RN Command Parser
 MiWi RN Command Parser

MiWi RN Command Parser "Wireless Made Easy!" - MiWi RN command parser based on SAMR30 and SAMR21 MiWi example code Devices: | ATSAMR30 | ATSAMR21 ⚠ Di

Sep 27, 2022
The command line interface for Piccolo
The command line interface for Piccolo

Piccolo programming language A fun, easy to embed high-level programming language. This repo contains the code for the Piccolo CLI. The core Piccolo c

Feb 14, 2022
A simple DPDK application that calculates stats for dropped and forwarded packets depending on the command line.

The DPDK Stats Description A small DPDK application that increments a basic packet counter for TCP or UDP packets depending on what's specified in the

Oct 24, 2022
Simple command-line program for sharing the display image on a local network.

XCast is a simple server/client command line program for sharing screen under X. With XCast you have the ability to either pull the display from a rem

Dec 12, 2021
LKM Command Line Parsing - Parte 2
LKM Command Line Parsing - Parte 2

LKM-Command-Line-Parsing ?? Hoje iremos falar sobre Command Line Parsing diretamente no LKM. Esse é a segunda parte da nossa série de estudos para Roo

May 11, 2022
Tuibox - A single-header terminal UI (TUI) library, capable of creating mouse-driven, interactive applications on the command line.
Tuibox - A single-header terminal UI (TUI) library, capable of creating mouse-driven, interactive applications on the command line.

tuibox tuibox ("toybox") is a single-header terminal UI library, capable of creating mouse-driven, interactive applications on the command line. It is

Dec 24, 2022
Icopack - A simple command line tool to create multi-frame ICO files from PNG source images
Icopack - A simple command line tool to create multi-frame ICO files from PNG source images

Optidash is a modern, AI-powered image optimization and processing API. We will drastically speed-up your websites and save you money on bandwidth and

Jul 27, 2022
Wave Function Collapse library in C, plus a command-line tool
Wave Function Collapse library in C, plus a command-line tool

wfc Single-file Wave Function Collapse library in C, plus a command-line tool License: MIT Version: 0.01 This is an early version that supports the ov

Dec 29, 2022
A small, fast codeforces command line tool for competitive programming.
A small, fast codeforces command line tool for competitive programming.

chainsaw: A Codeforces Commandline Tool chainsaw is a small and faster drop-in replacement for your copy and paste while attending Codeforces contests

Dec 8, 2022
A collection of command line tools for ARM devices with Allwinner SoCs.

sunxi-tools Copyright (C) 2012 Alejandro Mery [email protected] For a full list of contributors, see this link or use the command git shortlog -se --no-m

Jan 2, 2023
Command line tool for offline shader ISA inspection.

Intel Shader Analyzer Intel Shader Analyzer is a tool for offline static analysis of shaders for Intel GPU Architectures. It allows a user to compile

Jan 3, 2023
Command line C++ and Python VSTi Host library with MFCC, FFT, RMS and audio extraction and .wav writing.
Command line C++ and Python VSTi Host library with MFCC, FFT, RMS and audio extraction and .wav writing.

______ _ ___ ___ | ___ \ | | | \/ | | |_/ /___ _ __ __| | ___ _ __| . . | __ _ _ __

Dec 30, 2022
The command line app automatically determines your location using GeoIP and adjusts the color temperature depending on time

go-sct A color temperature setting library and CLI that operates in a similar way to f.lux and Redshift. The command line app automatically determines

Jan 25, 2022
Quick reference on command line tools and techniques

1. Introduction 1.1. Scope 1.2. Background 1.3. Purpose 1.4. Next steps 2. Basics 2.1. Common commands 2.2. Shortcuts 2.2.1. Navigation 2.2.2. Editing

Dec 7, 2022
OS X command line tool to inject Frameworks and dylibs on mach-o binaries (iOS & Mac Apps).

macho-inject OS X command line tool to inject Frameworks and dylibs on mach-o binaries. It does the injection of the framework and the codesigning. It

Nov 8, 2022
fx is a workspace tool manager. It allows you to create consistent, discoverable, language-neutral and developer friendly command line tools.
fx is a workspace tool manager. It allows you to create consistent, discoverable, language-neutral and developer friendly command line tools.

fx is a workspace tool manager. It allows you to create consistent, discoverable, language-neutral and developer friendly command line tools.

Aug 27, 2022
Get Next Line is a project at 42. It is a function that reads a file and allows you to read a line ending with a newline character from a file descriptor

Get Next Line is a project at 42. It is a function that reads a file and allows you to read a line ending with a newline character from a file descriptor. When you call the function again on the same file, it grabs the next line

Nov 15, 2022
A simple implementation of a parser and its use to calculate simple mathematical expressions

Calculator C Parser A simple implementation of a parser and its use to calculate simple mathematical expressions I haven't written a detailed descript

Nov 8, 2021
A header only library that provides parser combinators to C++

This is an experimental C++ library for rapidly building parsers. It is inspired by parser combinators in haskell such as attoparsec and, like those libraries, allows for the construction of fully fledged parsers in a few lines of code.

Jul 24, 2022