|
Option++
2.0
C++ library for reading command-line options
|
A guide to setting up and using Option++
First you need to download the library. There are two versions: a single-header version and a standard version.
For the single-header version, just download optionpp.hpp and put it in a directory named optionpp somewhere within your project directory.
For the single-header version only, you must add
to exactly one of the source files where you #include <optionpp/optionpp.hpp>. This is necessary to avoid multiple definition errors.
Note: the single-header version is automatically generated from a script by stitching together all the source and header files in the library. During this process the files are stripped of comments and the result is not particularly readable or easy to navigate. As a result, if you want to read the code or modify Option++ itself, you should look in the src and include directories for the original files.
Binaries are not yet provided, so the easiest way to obtain the library is to clone the repository and build it locally. Instructions on how to do that can be found on the Build Instructions page.
The header files are located in the include directory of the repository.
To make sure everything is set up correctly, try building the simple program below. Note that if you are using the single-header version, you will need to add #define OPTIONPP_MAIN at the top of the file.
This program does very little, but compiling it successfully will help verify that things are working as they should. To see more examples, look on the Example Programs page.
Now let's use Option++ to do some command-line parsing.
To use the library, we need to #include the header file optionpp/optionpp.hpp (for the single-header version of the library, this will be a big file, but for the standard version it is a small header that simply includes the other needed headers).
optionpp::parser is the primary class we will be working with, so let's construct an instance of this class:
First the parser needs to know what the valid program options are. For example, we can add a --help option like this:
The add_option method returns a reference to a newly-created option object, to which we assigned the long option name help. Now, when the parser encounters --help on the command line, it will know that this is a valid option for our program.
--help is an example of a long option. In many cases, we want our options to also accept a short option name. For example, we can add a short name -? to our help option by doing
In fact, this line would work even if we hadn't previously created the help option. So the subscript operator provides another way for us to add options.
The option methods like long_name and short_name also return references to their class instance, which allows us to chain calls together. For example, let's add a --verbose option with a short name of -v and we'll give it a description that will appear in our help message:
We can also add options that take arguments. The option::argument method takes a string giving the name of the argument (this is used in the help message) and an optional bool value that indicates whether the argument is mandatory or optional. For example,
would add a --file option with short name -f that takes a mandatory argument called "FILE" (argument names are usually uppercase). This tells the parser to always look for a string argument following the --file option.
Once we have registered all of our program's options, we can run the parser to read and evaluate the arguments that were sent to our program:
There is an overloaded form of the parse method that takes a string, so you could use Option++ to process arbitrary strings from somewhere other than the command line, like in an initialization file.
parse returns a parser_result containing the parsed data. A parser_result is a container of parsed_entrys.
Every command line argument is turned into a parsed_entry (usually; in some cases, two arguments might be combined to one entry or one argument might be split into several entries). Each parsed data entry is an instance of a struct with several fields that are set by the parser:
original_text contains the original text that was entered on the command line,is_option is true if the entry represents an option and false if it is just a normal command-line argument,long_name and short_name are the long and short option names and argument is the argument that was given, if any.For example, in our program we might iterate over the results and process them like this:
We can actually avoid the switch statement in the code above by using another feature of Option++ that allows us to bind variables directly to options. When the parser reads a particular option, it sets the bound variable automatically and even handles type conversion and validation.
For example, suppose our program, which we'll call solve, was using an iterative method to solve numerical problems like finding roots of nonlinear equations. We might want the user to be able to specify the number of iterations of the algorithm to perform. We can accept the number of iterations as an option argument. Since we can't perform a negative number of iterations, we'll use an unsigned variable. We can bind that variable to a --num-iterations option like this:
If the user calls our program with the command
then, after we call my_parser.parse, the parser will set the num_iterations variable to 200.
For options that don't take arguments, we can use bind_bool to bind a boolean variable. If the option is present, the variable is set to true, and if it is not the variable is set to false.
Using variable binding, we don't really need to examine the option entries themselves. We can iterate over only the non-option arguments using a non_option_iterator or a non_option_const_iterator (there is also an option_iterator and an option_const_iterator if we wanted to do the opposite and iterate over only option arguments). Our loop might look something like this:
If the user entered
we would get the output
Another thing we can do with Option++ is to respond to the --help option by displaying a useful summary of all the options available. This is easily done using parser::print_help. This method will print a properly formatted list of options onto an output stream:
If we run solve --help we might get output that looks like this:
The option description text will automatically be word-wrapped if it is too long to fit in one line (by default the maximum line length is 78 characters, which is close to the default width of most terminals; this can be changed in the arguments to parser::print_help).
As your program grows in size and your users' needs grow more diverse, you may find that you need to accept many, many different options. For programs with dozens or hundreds of options, it is helpful to group certain options together so that you can display more organized help messages. Option++ lets you do this with the parser::group method.
Instead of doing my_parser.add_option().long_name("my-option");, we can do something like
Or, using the option_group subscript operator, we could also write
We can add multiple options to the same group. Going back to our solve program, we might write
When displaying the help message using parser::print_help, all options belonging to the same group will appear together in a block. The name or description of the group that is passed to parser::group is displayed on a line before the option block:
Notice that all the math options are together, in the order we originally specified them. If you prefer the options to be sorted within each group, you can call parser::sort_options before calling parser::print_help.
This concludes the tutorial. For additional help or for more details, please consult the documentation. Now go and have fun writing the command-line program of your dreams!
1.8.17