Я хотел бы реализовать подкоманды для моей программы. Мне также нужна возможность иметь разные параметры аргумента для разных подкоманд. Каков наилучший способ сделать это с помощью Boost.Program_options?
Подкоманды используются в таких программах, как svn, git и apt-get.
Например, в GIT доступны некоторые подкоманды:
git status
git push
git add
git pull
Мой вопрос в основном такой же, как у этого парня: http://boost.2283326.n4.nabble.com/subcommands-with-program-options-like-svn-command-td2585537.html
Если я правильно понимаю проблему, вы хотите проанализировать параметры командной строки следующей формы:
[--generic-option ...] cmd [--cmd-specific-option ... ]
Вот мой пример решения. Для ясности я собираюсь опустить любой проверочный код, но, надеюсь, вы увидите, как он будет добавлен довольно просто.
В этом примере у нас есть подкоманда «ls» и, возможно, другие. Каждая подкоманда имеет определенные параметры, а также есть общие параметры. Итак, давайте начнем с анализа общих параметров и имени команды.
po::options_description global("Global options");
global.add_options()
("debug", "Turn on debug output")
("command", po::value<std::string>(), "command to execute")
("subargs", po::value<std::vector<std::string> >(), "Arguments for command");
po::positional_options_description pos;
pos.add("command", 1).
add("subargs", -1);
po::variables_map vm;
po::parsed_options parsed = po::command_line_parser(argc, argv).
options(global).
positional(pos).
allow_unregistered().
run();
po::store(parsed, vm);
Обратите внимание, что мы создали один позиционный параметр для имени команды и несколько позиционных параметров для параметров команды.
Теперь мы ответим на соответствующее имя команды и проведем повторный анализ. Вместо того, чтобы передать в оригинале argc
а также argv
Теперь мы передаем нераспознанные параметры в виде массива строк. collect_unrecognized
функция может обеспечить это — все, что нам нужно сделать, это удалить (позиционное) имя команды и повторно проанализировать с соответствующим options_description
,
std::string cmd = vm["command"].as<std::string>();
if (cmd == "ls")
{
// ls command has the following options:
po::options_description ls_desc("ls options");
ls_desc.add_options()
("hidden", "Show hidden files")
("path", po::value<std::string>(), "Path to list");
// Collect all the unrecognized options from the first pass. This will include the
// (positional) command name, so we need to erase that.
std::vector<std::string> opts = po::collect_unrecognized(parsed.options, po::include_positional);
opts.erase(opts.begin());
// Parse again...
po::store(po::command_line_parser(opts).options(ls_desc).run(), vm);
Обратите внимание, что мы использовали то же самое variables_map
для специфичных для команды опций как для общих. Из этого мы можем выполнить соответствующие действия.
Фрагменты кода здесь взяты из скомпилированного исходного файла, который включает в себя некоторые модульные тесты. Вы можете найти это в сущности Вот. Пожалуйста, не стесняйтесь скачать и играть с ним.
Вы можете удалить имя подкоманды из командной строки, используя позиционные варианты — увидеть этот урок.
Кажется, нет никакой встроенной поддержки подкоманд — вам нужно будет установить allow_unregistered
в парсере верхнего уровня найдите имя команды, затем запустите его через второй парсер, чтобы получить какие-либо специфичные для подкоманды опции.