While adding a new subcommand to our app and using excludes to setup mutual exclusivity with the other subcommands, we found the subcommands refuse to run, even when only one was specified at command line.
This seems to happen when force_callback is used, which sets a variable on the subcommand before the exclusion tests are performed.
Here is a minimal app to reproduce the issue. subcommand_1 has a forced callback, and prevents subcommand_2 to run, despite no parameters being passed for subcommand_1.
#include <iostream>
#include "CLI11.hpp" // v2.4.0
int main(int argc, char** argv)
{
CLI::App app{"CLI11-excludes-bug"};
auto subcommand_1 = app.add_subcommand("subcommand_1", "subcommand 1");
subcommand_1
->add_flag_function(
"-f",
[](bool f) {
std::cout << "subcommand_1 callback " << f << std::endl;
},
"subcommand_1 flag")
->force_callback();
auto subcommand_2 = app.add_subcommand("subcommand_2", "subcommand 2");
subcommand_1->excludes(subcommand_2);
CLI11_PARSE(app, argc, argv);
return 0;
}
Expected output:
>CLI11-excludes-bug.exe subcommand_2
subcomand_1 callback 0
[Exit Code 0]
Actual output:
>CLI11-excludes-bug.exe subcommand_2
subcommand_1 callback 0
subcommand_2 excludes subcommand_1
[Exit Code 108]
Basically, CLI11 is processing the forced callback for subcommand_1 first, which is setting the flag. Then, the requirements for subcommand_2 are processed; when it reaches the exclusion for subcommand_1, it sees a variable is set, and believes it is a conflict.
|
for(const auto &subc : exclude_subcommands_) { |
|
if(subc->count_all() > 0) { |
|
excluded = true; |
|
excluder = subc->get_display_name(); |
|
} |
|
} |
I don't know the best way of fixing this in the library, other than perhaps marking the variable as being set by a forced callback (and not explicitly set by the user/program otherwise), and ignore those when counting the variables only for the exclusion check?
Our workaround has involved removing the flag lambda entirely, and putting the logic into app.parse_complete_callback() instead. This works, but decouples the flag logic a bit.
While adding a new subcommand to our app and using
excludesto setup mutual exclusivity with the other subcommands, we found the subcommands refuse to run, even when only one was specified at command line.This seems to happen when
force_callbackis used, which sets a variable on the subcommand before the exclusion tests are performed.Here is a minimal app to reproduce the issue.
subcommand_1has a forced callback, and preventssubcommand_2to run, despite no parameters being passed forsubcommand_1.Expected output:
Actual output:
Basically, CLI11 is processing the forced callback for
subcommand_1first, which is setting the flag. Then, the requirements forsubcommand_2are processed; when it reaches the exclusion forsubcommand_1, it sees a variable is set, and believes it is a conflict.CLI11/include/CLI/impl/App_inl.hpp
Lines 1188 to 1193 in fd483ea
I don't know the best way of fixing this in the library, other than perhaps marking the variable as being set by a forced callback (and not explicitly set by the user/program otherwise), and ignore those when counting the variables only for the exclusion check?
Our workaround has involved removing the flag lambda entirely, and putting the logic into
app.parse_complete_callback()instead. This works, but decouples the flag logic a bit.