[LLVMdev] Adding sub-commands and option classes to the command line library.

Michael Spencer bigcheesegs at gmail.com
Sun Oct 23 00:27:19 PDT 2011


There was discussion on IRC about merging all of the compiler hacker
tools (llvm-as, bugpoint, llc, lli, etc...) into a single llvm
megatool. This tool would work similar to how most version control cli
programs work. One would call 'llvm as bitcode.ll' instead of 'llvm-as
bitcode.ll'. The main reason for this is to improve link time, but it
also reduces the total file size (especially in the case of static
linking), and makes it easier to discover the tools available.

I've begun work on this, but quickly ran into two problems. The first
is how to hook up each cl::opt to the command it belongs to, as when
all of the tools are in one executable, all options would be exposed
as it stands. The following is a sample of the API I propose to solve
this first problem. A new cl::subcommand class would be added. This
class contains the information for all sub-commands, including what
entry point to call when they are used. When the parser encounters
this option, It sets Command to the specified entry point and switches
to only recognizing options that have the cl::sub("<toolname>")
attribute.

Example usage (I've not written any code yet, so please forgive any
errors in the following):

======== driver.h ==================
typedef int (*MainFunctionT)(int, char**);

int main_eat(int, char**);
int main_order(int, char**);

======== driver.cpp ================
#include "driver.h"

static cl:subcommand<MainFunctionT> Command(
  "command"
  cl::desc("Driver commands"),
  cl::values(
    "eat", main_eat, "Eat all the food",
    "order", main_order, "Order the food",
    0));

static cl::opt<std::string> Restaurant("restaurant"
  cl::desc("The name of the restaurant to use"));

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, "Restaurant driver!\n");

  // Shared setup code...

  return Command(argc - 1, argv + 1);
}

======== eat.cpp ===================
#include "driver.h"

static cl::opt<std::string> Utensil("utensil",
  cl::desc("What to eat with"),
  cl::sub("eat"));

int main_eat(int argc, char **argc) {
  // Some code...
}

======== order.cpp =================
#include "driver.h"

static cl::opt<std::string> Size("size",
  cl::desc("Size of food to order"),
  cl::sub("order"));

int main_order(int argc, char **argc) {
  // Some code...
}

==== end ====

This will output the following.

$ driver
Restaurant driver!
USAGE: driver [-restaurant] <command> [<args>]

OPTIONS:
  -restaurant - The name of the restaurant to use

Driver commands:
    eat    - Eat all the food.
    order - Order the food.

See 'driver help <command>' for more information on a specific command.
$ driver help order
USAGE: driver order [-size] <food>...

OPTIONS:
  -size - Size of food to order

The second problem is handling library options. With the megatool, the
union of libraries needed for each command is linked in, and many of
these libraries include options. As it currently stands, the megatool
would have all of these options, which would be very confusing to the
user. I propose that we add the concept of an option class. All
library options would be given a class depending on what they actually
effect. For example, -x86-asm-syntax would have the class backend, or
target. The call to cl::parseCommandLineOptions would have a defaulted
classes argument. If an option has a class, and it isn't one of these,
it would be ignored.

- Michael Spencer



More information about the llvm-dev mailing list