I need to pass some specific arguments from one programm to another using boost::program_options and boost::process. Here is a simple example. In this example I need to pass all args stored in vm_slave to child process, but in common case I wanna pass one or more specific args from vm_slave.
#include <iostream>
#include <boost/process.hpp>
#include <boost/program_options.hpp>
using namespace std;
namespace po = boost::program_options;
int main(int argc, char* argv[]) {
po::options_description tester_options("Tester options");
po::options_description slave_options("Slave options");
tester_options.add_options()
("help,h", "Show help")
("iter,i", po::value<short>()->default_value(1), "TODO")
("modules,m", po::value<std::vector<string>>()->multitoken(), "TODO");
slave_options.add_options()
("size,s", po::value<size_t>()->required(), "TODO")
("threads,t", po::value<short>()->default_value(1), "TODO");
po::variables_map vm;
po::variables_map vm_slave;
auto p0 = po::command_line_parser(argc, argv).options(tester_options).allow_unregistered().run();
auto p1 = po::command_line_parser(argc, argv).options(slave_options).allow_unregistered().run();
po::store(p0, vm);
po::store(p1, vm);
po::store(p1, vm_slave);
// Do some stuff such as write help if needed
// ...
// I need call child process with all (or specific) args from vm_slave
boost::process::ipstream pipe;
boost::process::child cp(
"slave" /* + vm_slave args */,
boost::process::std_err > pipe,
boost::process::std_out > pipe
);
cp.wait();
return 0;
}
Of course I can do something like this:
ostringstream args;
for (const auto& arg : p1.options) {
if (vm_slave.count(arg.string_key) == 0)
continue;
args << arg.string_key << " ";
for (const auto& val : arg.value)
args << val << " ";
}
string cmd_args = args.str();
But in this case some args stored in vm_slave by default is lost.
Or I can do this:
ostringstream args;
for (const auto& arg : vm_slave) {
args << arg.first << " ";
const auto& any_val = arg.second.value();
if (boost::any_cast<size_t>(any_val))
args << to_string(boost::any_cast<size_t>(any_val));
else if (boost::any_cast<short>(any_val))
args << to_string(boost::any_cast<size_t>(any_val));
// And more and more casts...
args << " ";
}
But now we have many any_cast...
If I just pass argv
to child process, the child might fail because extra args presented (args like iter
not intended for this application).
All this attempts seem bad to me.
What is the proper way to convert parsed arguments back to command line?
There is no "proper way" - as composing command lines is not a feature of the library (neither is writing config-files).
I would use the parsed options. Unless you need to interpret the options you don't have to notify/store into a variable map at all:
Demoing, using
printf
instead ofslave
:See it Compiler Explorer
running
./sotest -i 1000 -m some modules to follow -h
running
./sotest -i 1000 -m some modules to follow -s=89 -t42
running
./sotest -i 1000 -m some modules to follow --size 89 --threads=42
running
./sotest -i 1000 -m some modules to follow -s 89 -t 42