CommandLine: using cl::Positional with enum

 Hi,I've been trying to code through CommandLine the options I want my tool accepts, but I find quite impossible to achieve robustly what I need .Look, I want the tool accepts a list of arguments in a particular order. For this goal, I know the cl::Positional flag. But, the problem is that **the first argument must be one of a set of options** (like a kind of subcommand of the tool). In my case, only the three next commands are possible:
myTool option1myTool option2  arg1  arg2 myTool option3  arg1and I don't want a different order is possible, for instance, this is not permitted:myTool arg2 option2 arg1So, I thought about using an enum for this first argument:enum OptLevel{option1, option2, option3};cl::opt<OptLevel> OptionsLevel(cl::Positional, cl::desc("Choose one of these options:"),cl::values(clEnumVal(option1, "..."),clEnumVal(option2, "..."),clEnumVal(option3, "..."), clEnumValEnd),);After that, the rest of arguments are also particular of the option selected as the first argument, i.e, the rest of arguments are related with the first one. So I thought I could independently parse these arguments with:cl::list<std::string>  Argv (cl::ConsumeAfter, cl::desc("<program arguments>..."));But, doing this when I run:myTool option1 file.cpp --I got the next error:"error - this positional option will never be matched, because it does not Require a value and a cl::ConsumeAfter option is active!"So, I modify "OptionsLevelOptionsLevel" including the cl::Required flagThe error is now:"option: does not allow a value! option1 specified.option: must be specified at least once!option: must be specified at least once!option: must be specified at least once!"Then, I decided to use cl::PositionalEatsArgs instead of cl::ConsumeAfter. Then, this is the result:"option: does not allow a value! option1 specified."But, this time, the program continues. However, if I run "myTool option3 arg1 file.cpp --" it gives me a different problem:"warning: ../build/arg1: 'linker' input unusederror: unable to handle compilation, expected exactly one compiler job in ' '"But the program still goes on.Is there a way to accomplish what I have explained? I don't want those errors and warnings. Thanks,Pedro.

Hi,

Please try and format your e-mails better. Your e-mail is incredibly
hard to read due to its lack of new lines.

I don't think the designer of the CommandLine library ever intended for
cl::Positional to be used with cl::opt<T> where T is an enum.

e.g.

enum OptLevel {
  g, O1, O2, O3
};

cl::opt<OptLevel> OptimizationLevel(cl::desc("Choose optimization level:"),
  cl::values(
    clEnumVal(g , "No optimizations, enable debugging"),
    clEnumVal(O1, "Enable trivial optimizations"),
    clEnumVal(O2, "Enable default optimizations"),
    clEnumVal(O3, "Enable expensive optimizations"),
   clEnumValEnd),
   cl::Positional
   );

int
main (int argc, char ** argv)
{
  cl::ParseCommandLineOptions(argc, argv);

  // Easy access in gdb (getValue is inlined!)
  OptLevel* test = &(OptimizationLevel.getValue() );
}

It also doesn't make a huge amount of sense (based on the output of
-help) either because the OptimizationLevel options have the "-" prefix
which is almost always taken to mean that it is optional and NOT
positional. -help shows...

  Choose optimization level:
    -g - No optimizations, enable debugging
    -O1 - Enable trivial optimizations
    -O2 - Enable default optimizations
    -O3 - Enable expensive optimizations

Trying

$ ./program -O1
$ ./program O1
$ ./program -- -O1
$ ./program -- O1

does not result in OptimizationLevel being modified by calling
ParseCommandLineOptions (I tested this in gdb).

This behaviour is arguably a bug. You're welcome to try and fix it.

I would like to suggest an alternative though. If I understand you
correctly you're looking for your command line syntax to be something
like...

./prog <option1> | ( <option2> --arg1 --arg2) | ( <option3> --arg1 )

I don't see why you should really care about the order, i.e. this is
probably okay.

./prog --arg1 <option1>

So why not make every argument optional (i.e. no positional arguments)

then after calling ParseCommandLineOptions you can check the user has
used the right options by doing something like...

// Note cl::opt<T> is a type of Option
Option* NOTValidForOption1[] = { &arg1, &arg2};
Option* NOTValidForOption3[] = { &arg2 };

switch(YourOption)
{
   case Option1:
     for(int I=0; I < sizeof(NOTValidForOption1)/sizeof(Option*);++I)
     {
        if(NotValidForOption1[I]->getNumOccurrences() != 0)
        {
           //Fail
        }
     }
     break;

    case Option2:
      break;

    case Option3:
      // similar to Option1
}

^ Note the above certainly code be coded better, this is just to give
you an idea.

You could also make it more obvious in the output of -help that only
certain options should be used with each other by putting them into
categories (see cl::cat() in documentation). Note this will only work
for you if arguments are mutually exclusive as an option may only be in
one category.

Hope that helps.

Dan.

Hi,I've been trying to code through CommandLine the options I want my tool accepts, but I find quite impossible to achieve robustly what I need .Look, I want the tool accepts a list of arguments in a particular order. For this goal, I know the cl::Positional flag. But, the problem is that *the first argument must be one of a set of options *(like a kind of subcommand of the tool). In my case, only the three next commands are possible:

myTool option1myTool option2 arg1 arg2 myTool option3 arg1and I don't want a different order is possible, for instance, this is not permitted:myTool arg2 option2 arg1So, I thought about using an enum for this first argument:enum OptLevel{option1, option2, option3};cl::opt<OptLevel> OptionsLevel(cl::Positional, cl::desc("Choose one of these options:"),cl::values(clEnumVal(option1, "..."),clEnumVal(option2, "..."),clEnumVal(option3, "..."), clEnumValEnd),);After that, the rest of arguments are also particular of the option selected as the first argument, i.e, the rest of arguments are related with the first one. So I thought I could independently parse these arguments with:cl::list<std::string> Argv (cl::ConsumeAfter, cl::desc("<program arguments>..."));But, doing this when I run:myTool option1 file.cpp --I got the next error:"error - this positional option will never be matched, because it does not Require a value and a cl::ConsumeAfter option is active!"So, I modify "O!

ptionsLeve
lOptionsLevel" including the cl::Required flagThe error is now:"option: does not allow a value! option1 specified.option: must be specified at least once!option: must be specified at least once!option: must be specified at least once!"Then, I decided to use cl::PositionalEatsArgs instead of cl::ConsumeAfter. Then, this is the result:"option: does not allow a value! option1 specified."But, this time, the program continues. However, if I run "myTool option3 arg1 file.cpp --" it gives me a different problem:"warning: ../build/arg1: 'linker' input unusederror: unable to handle compilation, expected exactly one compiler job in ' '"But the program still goes on.Is there a way to accomplish what I have explained? I don't want those errors and warnings. Thanks,Pedro.