Tutorial

In this section, we'll take a look at the most common usage scenarios
of the program_options library, starting with the simplest one. The examples
show only the interesting code parts, but the complete programs can be found
in the "BOOST_ROOT/libs/program_options/example" directory. Through all the
examples, we'll assume that the following namespace alias is in effect:

namespace po = boost::program_options;

Getting Started

The first example is the simplest possible: it only handles two
options. Here's the source code (the full program is in
"example/first.cpp"):

We start by declaring all allowed options using the
options_description class. The add_options method of that
class returns a special proxy object that defines
operator(). Calls to that operator actually declare
options. The parameters are option name, information about value, and option
description. In this example, the first option has no value, and the second
one has a value of type int.

After that, an object of class variables_map is
declared. That class is intended to store values of options, and can store
values of arbitrary types. Next, the calls to store,
parse_command_line and notify functions cause
vm to contain all the options found on the command
line.

And now, finally, we can use the options as we like. The
variables_map class can be used just like
std::map, except that values stored there must be retrieved
with the as method shown above. (If the type specified in the
call to the as method is different from the actually stored
type, an exception is thrown.)

It's now a good time to try compiling the code yourself, but if
you're not yet ready, here's an example session:

Option Details

An option value, surely, can have other types than int, and
can have other interesting properties, which we'll discuss right now. The
complete version of the code snipped below can be found in
example/options_description.cpp.

Imagine we're writing a compiler. It should take the optimization
level, a number of include paths, and a number of input files, and perform some
interesting work. Let's describe the options:

The "help" option should be familiar from
the previous example. It's a good idea to have this option in all cases.

The "optimization" option shows two new features. First, we specify
the address of the variable(&opt). After storing values, that
variable will have the value of the option. Second, we specify a default
value of 10, which will be used if no value is specified by the user.

The "include-path" option is an example of the
only case where the interface of the options_description
class serves only one
source -- the command line. Users typically like to use short option names
for common options, and the "include-path,I" name specifies that short
option name is "I". So, both "--include-path" and "-I" can be used.

Note also that the type of the "include-path"
option is std::vector. The library provides special
support for vectors -- it will be possible to specify the option several
times, and all specified values will be collected in one vector.

The "input-file" option specifies the list of files to
process. That's okay for a start, but, of course, writing something like:

compiler --input-file=a.cpp

is a little non-standard, compared with

compiler a.cpp

We'll address this in a moment.

The command line tokens which have no option name, as above, are
called "positional options" by this library. They can be handled
too. With a little help from the user, the library can decide that "a.cpp"
really means the same as "--input-file=a.cpp". Here's the additional code
we need:

The first two lines say that all positional options should be translated
into "input-file" options. Also note that we use the
command_line_parser class to parse the command
line, not the parse_command_line
function. The latter is a convenient wrapper for simple cases, but now we
need to pass additional information.

By now, all options are described and parsed. We'll save ourselves the
trouble of implementing the rest of the compiler logic and only print the
options:

Oops, there's a slight problem. It's still possible to specify the
"--input-file" option, and usage message says so, which can be confusing
for the user. It would be nice to hide this information, but let's wait
for the next example.

Multiple Sources

It's quite likely that specifying all options to our compiler on the
command line will annoy users. What if a user installs a new library and
wants to always pass an additional command line element? What if he has
made some choices which should be applied on every run? It's desirable to
create a config file with common settings which will be used together with
the command line.

Of course, there will be a need to combine the values from command
line and config file. For example, the optimization level specified on the
command line should override the value from the config file. On the other
hand, include paths should be combined.

Let's see the code now. The complete program is in
"examples/multiple_sources.cpp". The option definition has two interesting
details. First, we declare several instances of the
options_description class. The reason is that, in general,
not all options are alike. Some options, like "input-file" above, should
not be presented in an automatic help message. Some options make sense only
in the config file. Finally, it's nice to have some structure in the help message,
not just a long list of options. Let's declare several option groups:

// Declare a group of options that will be
// allowed only on command line
po::options_description generic("Generic options");
generic.add_options()
("version,v", "print version string")
("help", "produce help message")
;
// Declare a group of options that will be
// allowed both on command line and in
// config file
po::options_description config("Configuration");
config.add_options()
("optimization", po::value<int>(&opt)->default_value(10),
"optimization level")
("include-path,I",
po::value< vector<string> >()->composing(),
"include path")
;
// Hidden options, will be allowed both on command line and
// in config file, but will not be shown to the user.
po::options_description hidden("Hidden options");
hidden.add_options()
("input-file", po::value< vector<string> >(), "input file")
;

Note the call to the composing method in the declaration of the
"include-path" option. It tells the library that values from different sources
should be composed together, as we'll see shortly.

The add method of the options_description
class can be used to further group the options:

The parsing and storing of values follows the usual pattern, except that
we additionally call parse_config_file, and
call the store function twice. But what
happens if the same value is specified both on the command line and in
config file? Usually, the value stored first is preferred. This is what
happens for the "--optimization" option. For "composing" options, like
"include-file", the values are merged.

The first invocation uses values from the configuration file. The second
invocation also uses values from command line. As we see, the include
paths on the command line and in the configuration file are merged,
while optimization is taken from the command line.