Skip to content

opokatech/options

Repository files navigation

Options

Cpp Standard Coverage Status

This is yet another alternative for parsing command line arguments in C++.

The main design criteria were:

  • Fast to recompile the main. The library has very small footprint as regards to implicitly included headers. The main using this library includes indirectly only string and cstdint.
  • Easily allows validation of passed values.
  • Ease of declaring options and accessing them.
  • Requires C++11 or higher.

How to use it

A simple example, without validation looks as follows:

#include <iostream>

#include "options/Parser.hpp"

int main(int argc, char *argv[])
{
    Options::Parser args_parser;

    args_parser.add_mandatory("config", 'c', "Configuration file");       // --config, -c
    args_parser.add_optional("count", "Number of iterations", "10");      // --count
    args_parser.add_optional("threshold", 't', "Some threshold", "3.14"); // --threshold, -t
    args_parser.add_flag("help", 'h', "This help is accessible via short and long option");

    using std::cout;
    using std::endl;

    if (!args_parser.parse(argc, argv) || args_parser.as_bool("help"))
    {
        cout << "Usage: " << argv[0] << " [options] [-- [positional arguments]]" << endl;
        cout << args_parser.get_possible_options() << endl;
        return -1;
    }

    // Print all options
    cout << std::boolalpha;
    cout << "Options:" << endl;
    cout << " config    : " << args_parser.as_string("config") << endl;
    cout << " count     : " << args_parser.as_int("count") << endl;
    cout << " threshold : " << args_parser.as_double("threshold") << endl;

    // positional arguments are all the strings after "--" separator, for example:
    // ./example_simple -c config_file.txt -- these strings are positional arguments
    if (args_parser.positional_count() > 0)
    {
        cout << "Positional parameters:" << endl;
        for (size_t i = 0; i < args_parser.positional_count(); ++i)
            cout << " [" << i << "]: " << args_parser.positional(i) << endl;
    }
    else
        cout << "No positional parameters." << endl;

    return 0;
}

An example "session" on the console may look like this:

./build_example_debug/example_simple
Usage: ./build_example_debug/example_simple [options] [-- [positional arguments]]
 -c, --config     M Configuration file
     --count        Number of iterations (default: 10)
 -t, --threshold    Some threshold (default: 3.14)
 -h, --help         This help is accessible via short and long option

./build_example_debug/example_simple -c some_file.cfg -- this is a string
Options:
 config    : some_file.cfg
 count     : 10
 threshold : 3.14
Positional parameters:
 [0]: this
 [1]: is
 [2]: a
 [3]: string


A similar example, but with validation of data can be found here.

How to compile it

This library can be used in a few ways:

Using cmake the easiest way seems to be using FetchContent mechanism:

include(FetchContent)

FetchContent_Declare(
    options
    GIT_REPOSITORY https://github.com/opokatech/options
    GIT_TAG v3.0.0
    GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE)
FetchContent_MakeAvailable(options)

# ....

add_executable(example my_main.cpp)
target_link_libraries(example PRIVATE options)

Another option is to clone the whole repository as a git submodule and add it via add_subdirectory:

git submodule add https://github.com/opokatech/options externals/options

# optionally checkout some particular version:
cd externals/options
git checkout v3.0.0

And then in your CMakeLists.txt:

add_subdirectory(external/options) # location of the cloned repository

add_executable(example my_main.cpp)
target_link_libraries(example PRIVATE options)

And there is of course the most simple and not recommended way: copying src/options directory to your project and adding the files from it to the compilation process. Either by hand OR by including only the options directory via add_subdirectory. After all the whole library consists of just 7 files.

Some notes

  • an option may have an argument or not. An option without an argument is a flag,

  • an option is always identified by a long name. A long name is used with 2 dashes in front of it, like so --something. It may have a single character short version which is then used with a single dash in front of it, like so -s.

  • an option can be mandatory - which means it must be specified,

  • it is not checked if the defined options are unique,

  • it is not checked if the default value passes the validation (if used).