Shuzheng
Shuzheng

Reputation: 13830

How do I pass a variable number of arguments to a LLVM opt pass?

I want to pass a variable number of arguments to my LLVM opt pass.

To do this, I do something like:

static cl::list<std::string> Files(cl::Positional, cl::OneOrMore);
static cl::list<std::string> Libraries("l", cl::ZeroOrMore);

However, if I now invoke opt like:

foo@foo-Ubuntu:~/llvm-ir-obfuscation$ opt -load cmake-build-debug/water/libMapInstWMPass.so -mapiWM programs/ll/sum100.ll -S 2 3 4  -o foo.ll
opt: Too many positional arguments specified!
Can specify at most 2 positional arguments: See: opt -help

, then I get errors that opt will accept at most 2 positional arguments.

What am I doing wrong?

Upvotes: 3

Views: 2647

Answers (2)

compor
compor

Reputation: 2329

I think the problem is that opt is already parsing its own arguments, and has already the bitcode file to process as a positional argument, so having more than one positional arguments creates ambiguity.

The documentation explains the API as if it is used in a standalone application. So, for example, if you do something like this:

int main(int argc, char *argv[]) {
  cl::list<std::string> Files(cl::Positional, cl::OneOrMore);
  cl::list<std::string> Files2(cl::Positional, cl::OneOrMore);
  cl::list<std::string> Libraries("l", cl::ZeroOrMore);
  cl::ParseCommandLineOptions(argc, argv);

  for(auto &e : Libraries) outs() << e << "\n";
  outs() << "....\n";
  for(auto &e : Files) outs() << e << "\n";
  outs() << "....\n";
  for(auto &e : Files2) outs() << e << "\n";
  outs() << "....\n";
}

you get something like this:

$ foo -l one two three four five six

one
....
two
three
four
five
....
six
....

Now, if you swap around the two positional argument definitions, or even change the cl::OneOrMore of Files2 option to cl::ZeroOrMore, you will get an error

$ option: error - option can never match, because another positional argument will match an unbounded number of values, and this option does not require a value!

Personally, when I use opt I forego the positiontal argument option and do something like this:

cl::list<std::string> Lists("lists", cl::desc("Specify names"), cl::OneOrMore);

which allows me to do this:

opt -load ./fooPass.so -foo -o out.bc -lists one ./in.bc -lists two

and iterating over the std::string list the same way I get:

one
two

Upvotes: 3

Nicolas Lykke Iversen
Nicolas Lykke Iversen

Reputation: 4195

As @compor suggests, this probably has something to do with intertwining arguments for opt and your own pass. The CommandLine library is primarily written for standalone applications within the LLVM framework.

However, you can do something like:

static cl::list<std::string> Args1("args1", cl::Positional, cl::CommaSeparated);
static cl::list<std::string> Args2("args2", cl::ZeroOrMore);

This has the advantage that you can input multiple arguments on the command-line using either commas, e.g., arg1,arg2,... or by using the identifier -args1 arg1 arg2 ...; and these get inserted into the Args1 list. If you just supply a single positional argument arg on the command line, then Args1 will contain this argument only.

Also, you can specify -args2 arg on the command-line wherever you with (named non-positional option). These will go into the Args2 list.

Upvotes: 2

Related Questions