Take a look at some of the console programs, such as cp
in Linux. They all have a fancy help; their input parameters do not depend on any position and have a human-readable syntax. For example:
$ cp --help
Usage: cp [OPTION]... [-T] SOURCE DEST
-a, --archive same as -dR --preserve=all
-b like --backup but does not accept an argument
You can implement the same functionality for your program in 10 minutes. All you need is the Boost.ProgramOptions
library.
Basic knowledge of C++ is all you need for this recipe. Remember that this library is not only a header, so your program has to link against the libboost_program_options
library.
Let's start with a simple program that accepts the count of apples
and oranges
as input and counts the total number of fruits. We want to achieve the following result:
$ ./our_program.exe --apples=10 --oranges=20
Fruits count: 30
Perform the following steps:
- Include the
boost/program_options.hpp
header and make an alias for theboost::program_options
namespace (it is too long to type it!). We would also need an<iostream>
header:
#include <boost/program_options.hpp> #include <iostream> namespace opt = boost::program_options;
- Now, we are ready to describe our options in the
main()
function:
int main(int argc, char *argv[]) { // Constructing an options describing variable and giving // it a textual description "All options". opt::options_description desc("All options"); // When we are adding options, first parameter is a name // to be used in command line. Second parameter is a type // of that option, wrapped in value<> class. Third parameter // must be a short description of that option. desc.add_options() ("apples", opt::value<int>(), "how many apples do you have") ("oranges", opt::value<int>(), "how many oranges do you have") ("help", "produce help message") ;
- Let's parse the command line:
// Variable to store our command line arguments. opt::variables_map vm; // Parsing and storing arguments. opt::store(opt::parse_command_line(argc, argv, desc), vm); // Must be called after all the parsing and storing. opt::notify(vm);
- Let's add some code for processing the
help
option:
if (vm.count("help")) { std::cout << desc << "\n"; return 1; }
- Final step. Counting fruits may be implemented in the following way:
std::cout << "Fruits count: " << vm["apples"].as<int>() + vm["oranges"].as<int>() << std::endl; } // end of `main`
Now, if we call our program with the help
parameter, we'll get the following output:
All options:
--apples arg how many apples do you have
--oranges arg how many oranges do you have
--help produce help message
As you can see, we do not provide a type for the help
option's value, because we do not expect any values to be passed to it.
This example is pretty simple to understand from code and comments. Running it produces the expected result:
$ ./our_program.exe --apples=100 --oranges=20
Fruits count: 120
The C++ standard adopted many Boost libraries; however, you won't find Boost.ProgramOptions
even in C++17. Currently, there's no plan to adopt it into C++2a.
The ProgramOptions
library is very powerful and has many features. Here's how to:
- Parse configuration option values directly into a variable and make that option a required one:
int oranges_var = 0; desc.add_options() // ProgramOptions stores the option value into // the variable that is passed by pointer. Here value of // "--oranges" option will be stored into 'oranges_var'. ("oranges,o", opt::value<int>(&oranges_var)->required(), "oranges you have")
- Get some mandatory string option:
// 'name' option is not marked with 'required()', // so user may not provide it. ("name", opt::value<std::string>(), "your name")
- Add short name for apple, set
10
as a default value forapples
:
// 'a' is a short option name for apples. Use as '-a 10'. // If no value provided, then the default value is used. ("apples,a", opt::value<int>()->default_value(10), "apples that you have");
- Get the missing options from the configuration file:
opt::variables_map vm; // Parsing command line options and storing values to 'vm'. opt::store(opt::parse_command_line(argc, argv, desc), vm); // We can also parse environment variables. Just use // 'opt::store with' 'opt::parse_environment' function. // Adding missing options from "apples_oranges.cfg" config file. try { opt::store( opt::parse_config_file<char>("apples_oranges.cfg", desc), vm ); } catch (const opt::reading_file& e) { std::cout << "Error: " << e.what() << std::endl; }
Note
The configuration file syntax differs from the command-line syntax. We do not need to place minuses before the options. So, our apples_oranges.cfg
file must look like this:oranges=20
- Validate that all the required options were set:
try { // `opt::required_option` exception is thrown if // one of the required options was not set. opt::notify(vm); } catch (const opt::required_option& e) { std::cout << "Error: " << e.what() << std::endl; return 2; }
If we combine all the mentioned tips into a single executable, then its help
command will produce this output:
$ ./our_program.exe --help
All options:
-o [ --oranges ] arg oranges that you have
--name arg your name
-a [ --apples ] arg (=10) apples that you have
--help produce help message
Running it without a configuration file will produce the following output:
$ ./our_program.exe
Error: can not read options configuration file 'apples_oranges.cfg'
Error: the option '--oranges' is required but missing
Running the program with oranges=20
in the configuration file will generate ++, because the default value for apples is 10
:
$ ./our_program.exe
Fruits count: 30
- Boost's official documentation contains many more examples and tells us about more advanced features of
Boost.ProgramOptions
, such as position-dependent options, nonconventional syntax, and more; this is available at http://boost.org/libs/program_options - You can modify and run all the examples from this book online at http://apolukhin.github.io/Boost-Cookbook