Reputation: 13664
Imagine I have a program that takes the following command-line option:
$ prog1 --foo 1
I also have a configuration file that is in this hierarchical format, with the foo
parameter within the prog1
scope:
[prog1]
foo = 42
My understanding of Boost::program_options is that the command-line option is defined similar to:
description.add_options()
("foo", "Set foo value");
However I want the value in the config file to be a default value (as an outcome of calling store()
twice, first with the command-line description, then the config file description), able to be overriden by the command-line option, but I believe the config file option has to be declared as:
description.add_options()
("prog1.foo", "Set foo value");
Note the use of prog1.foo
here, especially the prog1.
prefix.
So my question is, if you use hierarchical config-file options, how do you associate these with command line options? I.e. how do I make --foo
and prog1.foo
represent the same configuration value in the Storage object?
Upvotes: 0
Views: 615
Reputation: 13664
I've learned enough to answer my own question. Hopefully this will help someone one day, because the Boost::Program_Options documentation does not cover this.
If you create a hierarchical config option like this (this is documented):
config_only_opts.add_options()
("section.option", po::bool_switch(), "Some option");
And pass it to both parse_command_line()
and parse_config_file()
.
Then the config file would look like this:
[section]
option=1
And the command-line option would look like this (this is not documented):
--section.option
So the hierarchical options translate into dotted command-line options. Therefore I'd expect this:
[one.two]
three=4
To be equivalant to the following config option:
--one.two.three=4
Defaults that are applied to the command-line or config file options apply in the way you'd expect, depending on the order that store()
is called.
If you want to associate an arbitrary command-line option, such as --foo
, with a hierarchical (or flat) config file value like bar.baz
, then you can register the former with parse_command_line()
and the latter with parse_config_file()
, but reference the same storage variable for each:
bool foo;
po::options_description cmdline_opts;
cmdline_only_opts.add_options()
("foo", po::value<bool>(&foo), "Foo")
;
po::options_description config_file_opts;
config_only_opts.add_options()
("bar.baz", po::value<bool>(&foo))
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, cmdline_opts), vm);
po::store(po::parse_config_file("config.file", config_file_opts, true /* allow unregistered */), vm);
po::notify(vm);
Now you can use --foo
or
[bar]
baz=X
to set the variable foo
. The only caveat to be careful about is that you can no longer use vm[XXX].as<T>()
where "XXX" is "foo" or "bar.baz" to access the value - just use the referenced storage variable instead.
Upvotes: 0