1. Introduction
Lyra is a simple to use, composing, command line parser for C++ 11 and beyond. It provides easy to use command line parsing for most use cases with a minimal source footprint. It doesn’t aim to provide all features for all users.
1.1. License
Distributed under the highly permissive Boost Software License, Version 1.0. (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1.2. Features
-
Header only with no external dependencies (except the
std
library). -
Define your interface once to get parsing, type conversions and usage strings with no redundancy.
-
Composing. Each
opt
orarg
is an independent parser. Combine these to produce a composite parser — this can be done in stages across multiple function calls — or even projects. -
Bind parsers directly to variables that will receive the results of the parse — no intermediate dictionaries to worry about.
-
Or can also bind parsers to lambdas for more custom handling.
-
Deduces types from bound variables or lambdas and performs type conversions (via
ostream <<
), with error handling, behind the scenes. -
Bind parsers to vectors for args that can have multiple values.
-
Uses result types for error propagation, rather than exceptions (doesn’t yet build with exceptions disabled, but that will be coming later)
-
Models POSIX standards for short and long opt behavior.
-
Customizable option syntax.
-
Specify cardinality of
arg
-s from one to many. -
Limit option values to a specified set of values.
2. Usage
To use, just #include <lyra/lyra.hpp>
2.1. Single Option
A parser for a single option can be created like this:
#include <cstdlib>
#include <iostream>
#include <lyra/lyra.hpp>
int main(int argc, const char** argv)
{
// Where we read in the argument value:
int width = 0;
// The parser with the one option argument:
auto cli = lyra::cli_parser()
| lyra::opt(width, "width")
["-w"]["--width"]("How wide should it be?");
// ...
You can use this parser by giving it the program arguments of main
:
// ...
// Parse the program arguments:
auto result = cli.parse({ argc, argv });
// Check that the arguments where valid:
if (!result)
{
std::cerr << "Error in command line: " << result.errorMessage() << std::endl;
std::exit(1);
}
std::cout << "width = " << width << "\n";
}
Which could be used as:
> example1 -w 10
width = 10
2.2. Multiple Options
It’s rare that we are interested in accepting a single option. To parse
multiple options we compose the options as alternatives with the or
operator (|
).
#include <cstdlib>
#include <iostream>
#include <lyra/lyra.hpp>
int main(int argc, const char** argv)
{
// Where we read in the argument values:
int width = 0;
std::string name;
bool doIt = false;
// The parser with the multiple option arguments. They are composed
// together by the "|" operator.
auto cli
= lyra::opt(width, "width")
["-w"]["--width"]("How wide should it be?")
| lyra::opt(name, "name")
["-n"]["--name"]("By what name should I be known")
| lyra::opt(doIt)
["-d"]["--doit"]("Do the thing");
// ...
You can use this parser by giving it the program arguments of main
:
// ...
// Parse the program arguments:
auto result = cli.parse({ argc, argv });
// Check that the arguments where valid:
if (!result)
{
std::cerr << "Error in command line: " << result.errorMessage() << std::endl;
std::exit(1);
}
std::cout << "width = " << width << ", name = " << name << ", doIt = " << doIt << "\n";
}
Which could be used as:
> example2 -w 10 --name=Lyra
width = 10, name = Lyra, doIt = 0
3. Help Option
From the specified arguments parser we also get convenient help output.
int main(int argc, const char** argv)
{
// Where we read in the argument values:
int width = 0;
std::string name;
bool doIt = false;
bool show_help = false; (1)
// The parser with the multiple option arguments and help option.
auto cli
= lyra::help(show_help) (2)
| lyra::opt(width, "width")
["-w"]["--width"]("How wide should it be?")
| lyra::opt(name, "name")
["-n"]["--name"]("By what name should I be known")
| lyra::opt(doIt)
["-d"]["--doit"]("Do the thing");
// ...
1 | Flag variable to indicate if we get the -h or --help option. |
2 | The help specific option parser. |
We need some changes when using the parser to check if the help option was specified:
// ...
// Parse the program arguments:
auto result = cli.parse({ argc, argv });
// Check that the arguments where valid:
if (!result)
{
std::cerr << "Error in command line: " << result.errorMessage() << std::endl;
std::cerr << cli << "\n"; (1)
exit(1);
}
// Show the help when asked for.
if (show_help) (2)
{
std::cout << cli << "\n";
exit(0);
}
std::cout << "width = " << width << ", name = " << name << ", doIt = " << doIt << "\n";
}
1 | We print out the help text on error. |
2 | And we also print it out when specified. |
4. Value Choices
For value arguments, i.e. --name=value
or positional arguments, one can
specify a set of allowed values. You can indicate the choices explicitly by
specifying them to the choices()
call:
#include <iostream>
#include <lyra/lyra.hpp>
int main(int argc, const char** argv)
{
std::string choice;
// Ex: <exe> --choice=red
auto cli = lyra::cli_parser()
| lyra::opt(choice, "-c")["--choice"]
.choices("red", "green", "blue");
auto result = cli.parse({ argc, argv });
if (result)
{
std::cout << "Your preferred color is " << choice << "\n";
}
else
{
std::cerr << result.errorMessage() << "\n";
}
}
Or you can specify a complex set of values by giving choices()
a function
that validates if a given value is allowed:
#include <iostream>
#include <lyra/lyra.hpp>
int main(int argc, const char** argv)
{
int choice = 5;
// Ex: <exe> --choice=3
auto cli = lyra::cli_parser()
| lyra::opt(choice, "-c")["--choice"]
.choices([](int value) { return 1 <= value && value <= 10; });
auto result = cli.parse({ argc, argv });
if (result)
{
std::cout << "Your number between one and ten is " << choice << "\n";
}
else
{
std::cerr << result.errorMessage() << "\n";
}
}
For either case the default, initial, value is only modified if a valid value is given.
5. Reference
5.1. lyra::parser_customization
Customization interface for parsing of options.
virtual std::string token_delimiters() const = 0;
Specifies the characters to use for splitting a cli argument into the option and its value (if any).
virtual std::string option_prefix() const = 0;
Specifies the characters to use as possible prefix, either single or double, for all options.
5.2. lyra::default_parser_customization
Is-a lyra::parser_customization
that defines token delimiters as space (" ")
or equal ("="). And specifies the option prefix character as dash ("-")
resulting in long options with --
and short options with -
.
This customization is used as the default if none is given.
5.5. lyra::bound_parser
Parser that binds a variable reference or callback to the value of an argument.
5.5.1. Construction
template <typename Derived>
template <typename Reference>
bound_parser<Derived>::bound_parser(Reference& ref, std::string const& hint);
template <typename Derived>
template <typename Lambda>
bound_parser<Derived>::bound_parser(Lambda const& ref, std::string const& hint);
Constructs a value option with a target typed variable or callback. These are
options that take a value as in --opt=value
. In the first form the given
ref
receives the value of the option after parsing. The second form the
callback is called during the parse with the given value. Both take a
hint
that is used in the help text. When the option can be specified
multiple times the callback will be called consecutively for each option value
given. And if a container is given as a reference on the first form it will
contain all the specified values.
5.5.2. Specification
5.5.2.1. lyra::bound_parser::operator(description)
template <typename Derived>
Derived& bound_parser<Derived>::operator()(std::string const& description);
Defines the help description of an argument.
5.5.2.2. lyra::bound_parser::optional
template <typename Derived>
Derived& bound_parser<Derived>::optional();
Indicates that the argument is optional. This is equivalent to specifying
cardinality(0, 1)
.
5.5.2.3. lyra::bound_parser::required(n)
template <typename Derived>
Derived& bound_parser<Derived>::required(size_t n);
Specifies that the argument needs to given the number of n
times
(defaults to 1).
5.5.2.4. lyra::bound_parser::cardinality(n, m)
template <typename Derived>
Derived& bound_parser<Derived>::cardinality(size_t n);
template <typename Derived>
Derived& bound_parser<Derived>::cardinality(size_t n, size_t m);
Specifies the number of times the argument can and needs to appear in the list
of arguments. In the first form the argument can appear exactly n
times. In
the second form it specifies that the argument can appear from n
to m
times
inclusive.
5.5.2.5. lyra::bound_parser::choices
template <typename Derived>
template <typename T, typename... Rest>
lyra::opt& lyra::bound_parser<Derived>::choices(T val0, T val1, Rest... rest)
template <typename Derived>
template <typename Lambda>
lyra::opt& lyra::bound_parser<Derived>::choices(Lambda const &check_choice)
Limit the allowed values of an argument. In the first form the value is
limited to the ones listed in the call (two or more values). In the second
form the check_choice
function is called with the parsed value and returns
true
if it’s an allowed value.
5.6. lyra::cli_parser
A Combined parser made up of any two or more other parsers. Creating and using one of these as a basis one can incrementally compose other parsers into this one. For example:
auto cli = lyra::cli_parser();
std::string what;
float when = 0;
cli |= lyra::opt(what, "what")["--make-it-so"]("Make it so.").required();
cli |= lyra::opt(when. "when")["--time"]("When to do <what>.").optional();
cli_parser::parse_result cli_parser::parse(
args const& args, parser_customization const& customize) const;
Parses given arguments args
and optional parser customization customize
.
The result indicates success or failure, and if failure what kind of failure
it was. The state of variables bound to options is unspecified and any bound
callbacks may have been called.
5.7. lyra::opt
A parser for one option with multiple possible names. The option value(s) are communicated through a reference to a variable, a container, or a callback.
Is-a lyra::bound_parser
.
5.7.1. Construction
5.7.1.1. Flags
lyra::opt::opt(bool& ref);
template <typename LambdaT>
lyra::opt::opt(LambdaT const& ref);
template <typename LambdaT>
lyra::opt::opt(LambdaT const& ref, std::string const& hint)
Constructs a flag option with a target bool
to indicate if the flag is
present. The first form takes a reference to a variable to receive the
bool
. The second takes a callback that is called with true
when the
option is present.
5.7.1.2. Values
template <typename T>
lyra::opt::opt(T& ref, std::string const& hint);
template <typename LambdaT>
lyra::opt::opt(LambdaT const& ref, std::string const& hint)
Constructs a flag option with a target bool
to indicate if the flag is
present. The first form takes a reference to a variable to receive the
bool
. The second takes a callback that is called with true
when the
option is present.
5.8. lyra::arg
A parser for regular arguments, i.e. not --
or -
prefixed. This is simply
a way to get values of arguments directly specified in the cli. For example:
#include <iostream>
#include <lyra/lyra.hpp>
int main(int argc, const char** argv)
{
int repeat = 0;
std::string message;
// Ex: <exe> --repeat=10 "Hello world."
auto cli
= lyra::opt(repeat, "-repeat")["--repeat"]
| lyra::arg(message, "message");
if (cli.parse({ argc, argv }))
{
for (int count= 0; count < repeat; ++count)
std::cout << message << "\n";
}
}
Is-a lyra::bound_parser
.
5.9. lyra::help
Utility function that defines a default --help
option. You can specify a
bool
flag to indicate if the help option was specified and that you could
display a help message.
The option accepts -?
, -h
, and --help
as allowed option names.
5.10. lyra::exe_name
Specifies the name of the executable.
Is-a lyra::composable_parser
.
5.10.1. Construction
exe_name::exe_name(std::string& ref)
Constructs with a target string to receive the name of the executable. When
the cli_parser
is run the target string will contain the exec name.
template <typename LambdaT>
exe_name::exe_name(LambdaT const& lambda)
Construct with a callback that is called with the value of the executable name
when the cli_parser
runs.
6. History
6.1. 1.1
Changes:
-
New: Add direct Meson Build use support. — RĂ©mi Gastaldi
-
New: Define argument value
choices()
as either a fixed set or checked by a custom lambda function. — Rene Rivera -
Fix being able to parse straight from
args
outside ofcli_parser
. Which resulted in misleading parsing behavior. Rene Rivera -
Fix use of
cardinality()
to correctly constrain bounded cardinality ranges like[0,n]
,[n,m]
,[n,n]
, and[0,0]
(unbounded). Rene Rivera -
Fix use of
required()
arguments such that the parse errors if they are absent. — girstsf -
Remove uses of
assert
macro to avoid internal aborts and make it easier to use as a library. — Rene Rivera -
Many documentation improvements. — Rene Rivera
-
Tested with Visual Studio 2015, VS 2017, VS 2019, MinGW-64 (gcc 8.1), Linux (clang 3.5, 3.6, 3.7, 3.8, 3.9, 4, 5, 6, 7, 8, 9; gcc 4.8, 4.9, 5, 6, 7, 8, 9), Xcode (9.0, 9.0.1, 9.1, 9.2, 9.3, 9.3.1, 9.4, 9.4.1, 10.0, 10.1, 10.2, 10.2.1, 10.3, 11.0), on Azure Pipelines.
6.2. 1.0
This is the initial base version based on Clara library. Changes from that library:
-
Documentation.
-
Zero dependencies, even internally, by removing TextFlow and Catch bundled libraries.
-
Conform to Pitchfork Layout R1.
-
Tested with Visual Studio 2015, VS 2017, MinGW (gcc 5.3), MinGW-64 (gcc 6.3, 7.3, 8.1), Linux (clang 3.5, 3.8, 3.9, 4, 5; gcc 4.8, 4.9, 5, 6, 7, 8), Xcode (8.3, 9, 9.1, 10.1).
-
Tested with C++ 11, 14, 17, and 2a.
-
New: customization of option prefix and separators.
-
New: support for repeated arguments, from one to many.