使用 Boost.Program_options 创建前缀命令
Create a prefix command with Boost.Program_options
我想使用 Boost.Program_options 创建一个像 strace
这样的前缀程序。前缀的意思是我的程序放在另一个任意command [args]
的前面。因此,我的程序应该接受一些已定义的关键字参数/标志。第一个位置参数表示我作为前缀的命令。该命令本身可能会跟有我不知道的参数的任何组合,并且可能与我的程序的参数重叠。因此,第一个位置参数及其之后的任何内容都应以 std::vector<std::string>
:
结尾
./foo --bar 13 command1 # Should run fine
./foo command2 positional # Should run fine
./foo --bar 13 command3 --unknown argument # Should run fine
./foo --unknown command4 # should fail
./foo --bar 13 command5 --bar 42 # Should work but set bar to 13
./foo command6 --bar 42 # Should not set bar at all
./foo --bar 13 -- command7 --bar 42 --unknown argument # Should work
正确的用法是先指定任何已定义的关键字
基本上以正确的形式,首先有一些我定义的应该取任意数量的预定义
我试过两种方法:
1) 使用 allow_unregistered
:
#include <iostream>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
int main(int argc, const char** argv)
{
int bar = 0;
po::options_description desc("Allowed options");
desc.add_options()
("bar", po::value(&bar), "bar");
po::variables_map vm;
po::parsed_options parsed =
po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
po::store(parsed, vm);
po::notify(vm);
auto command = po::collect_unrecognized(parsed.options, po::include_positional);
std::cout << "bar: " << bar << ", command:";
for (const auto& c : command) std::cout << " " << c;
std::cout << std::endl;
}
命令 4、5、6 失败
2) 一个位置选项,出现次数不限
std::vector<std::string> command;
desc.add_options()
("bar", po::value(&bar), "bar")
("command", po::value(&command));
po::positional_options_description p;
p.add("command", -1);
po::variables_map vm;
po::parsed_options parsed =
po::command_line_parser(argc, argv).options(desc).positional(p).run();
po::store(parsed, vm);
po::notify(vm);
命令 3、5、6 失败。
在 Boost Trac 上有一个功能请求,包括补丁:https://svn.boost.org/trac/boost/ticket/6991。票证上没有太多变化,但补丁仍然适用于 Boost(截至 1.61.0,最新版本)。
如果您的构建系统允许,您可以将补丁应用到本地的 Boost 副本;否则,您可以从 cmdline.hpp
、detail/cmdline.hpp
和 cmdline.cpp
中提取 boost::program_options::detail::cmdline
到您自己的命名空间中,修补该组件,并使用您的修补组件代替 boost::program_options::cmdline
.
另一种选择是破解 boost::program_options::detail::cmdline
的行为,使用它的 extra_style_parser
参数:
po::detail::cmdline cmdline(argc, argv);
cmdline.set_options_description(desc);
cmdline.set_positional_options(p);
std::vector<po::detail::cmdline::style_parser> style_parsers{
[&](auto& args) { return cmdline.parse_long_option(args); },
[&](auto& args) { return cmdline.parse_short_option(args); }};
cmdline.extra_style_parser([&](std::vector<std::string>& args) {
auto const current_size = args.size();
std::vector<po::option> result;
for (auto const& parser : style_parsers) {
auto const next = parser(args);
result.insert(result.end(), next.begin(), next.end());
if (args.size() != current_size)
return result;
}
if (args.size() && args[0] != "--") args.insert(args.begin(), "--");
auto const next = cmdline.parse_terminator(args);
result.insert(result.end(), next.begin(), next.end());
return result;
});
po::parsed_options parsed{&desc};
parsed.options = cmdline.run();
po::store(parsed, vm);
po::notify(vm);
Example。 警告:这是对未记录的库内部结构的黑客攻击,随时可能崩溃。
我想使用 Boost.Program_options 创建一个像 strace
这样的前缀程序。前缀的意思是我的程序放在另一个任意command [args]
的前面。因此,我的程序应该接受一些已定义的关键字参数/标志。第一个位置参数表示我作为前缀的命令。该命令本身可能会跟有我不知道的参数的任何组合,并且可能与我的程序的参数重叠。因此,第一个位置参数及其之后的任何内容都应以 std::vector<std::string>
:
./foo --bar 13 command1 # Should run fine
./foo command2 positional # Should run fine
./foo --bar 13 command3 --unknown argument # Should run fine
./foo --unknown command4 # should fail
./foo --bar 13 command5 --bar 42 # Should work but set bar to 13
./foo command6 --bar 42 # Should not set bar at all
./foo --bar 13 -- command7 --bar 42 --unknown argument # Should work
正确的用法是先指定任何已定义的关键字 基本上以正确的形式,首先有一些我定义的应该取任意数量的预定义
我试过两种方法:
1) 使用 allow_unregistered
:
#include <iostream>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
int main(int argc, const char** argv)
{
int bar = 0;
po::options_description desc("Allowed options");
desc.add_options()
("bar", po::value(&bar), "bar");
po::variables_map vm;
po::parsed_options parsed =
po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
po::store(parsed, vm);
po::notify(vm);
auto command = po::collect_unrecognized(parsed.options, po::include_positional);
std::cout << "bar: " << bar << ", command:";
for (const auto& c : command) std::cout << " " << c;
std::cout << std::endl;
}
命令 4、5、6 失败
2) 一个位置选项,出现次数不限
std::vector<std::string> command;
desc.add_options()
("bar", po::value(&bar), "bar")
("command", po::value(&command));
po::positional_options_description p;
p.add("command", -1);
po::variables_map vm;
po::parsed_options parsed =
po::command_line_parser(argc, argv).options(desc).positional(p).run();
po::store(parsed, vm);
po::notify(vm);
命令 3、5、6 失败。
在 Boost Trac 上有一个功能请求,包括补丁:https://svn.boost.org/trac/boost/ticket/6991。票证上没有太多变化,但补丁仍然适用于 Boost(截至 1.61.0,最新版本)。
如果您的构建系统允许,您可以将补丁应用到本地的 Boost 副本;否则,您可以从 cmdline.hpp
、detail/cmdline.hpp
和 cmdline.cpp
中提取 boost::program_options::detail::cmdline
到您自己的命名空间中,修补该组件,并使用您的修补组件代替 boost::program_options::cmdline
.
另一种选择是破解 boost::program_options::detail::cmdline
的行为,使用它的 extra_style_parser
参数:
po::detail::cmdline cmdline(argc, argv);
cmdline.set_options_description(desc);
cmdline.set_positional_options(p);
std::vector<po::detail::cmdline::style_parser> style_parsers{
[&](auto& args) { return cmdline.parse_long_option(args); },
[&](auto& args) { return cmdline.parse_short_option(args); }};
cmdline.extra_style_parser([&](std::vector<std::string>& args) {
auto const current_size = args.size();
std::vector<po::option> result;
for (auto const& parser : style_parsers) {
auto const next = parser(args);
result.insert(result.end(), next.begin(), next.end());
if (args.size() != current_size)
return result;
}
if (args.size() && args[0] != "--") args.insert(args.begin(), "--");
auto const next = cmdline.parse_terminator(args);
result.insert(result.end(), next.begin(), next.end());
return result;
});
po::parsed_options parsed{&desc};
parsed.options = cmdline.run();
po::store(parsed, vm);
po::notify(vm);
Example。 警告:这是对未记录的库内部结构的黑客攻击,随时可能崩溃。