From: Andrew Trick Date: Mon, 6 May 2013 21:56:23 +0000 (+0000) Subject: Support command line option categories. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b7ad33b7195cb99b0cbb1c5308324d328650ca45;p=oota-llvm.git Support command line option categories. Patch by Dan Liew! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181253 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/CommandLine.rst b/docs/CommandLine.rst index ea0c369670a..8a266e23b26 100644 --- a/docs/CommandLine.rst +++ b/docs/CommandLine.rst @@ -618,6 +618,53 @@ would yield the help output: -help - display available options (-help-hidden for more) -o - Specify output filename +Grouping options into categories +-------------------------------- + +If our program has a large number of options it may become difficult for users +of our tool to navigate the output of ``-help``. To alleviate this problem we +can put our options into categories. This can be done by declaring option +categories (`cl::OptionCategory`_ objects) and then placing our options into +these categories using the `cl::cat`_ option attribute. For example: + +.. code-block:: c++ + + cl::OptionCategory StageSelectionCat("Stage Selection Options", + "These control which stages are run."); + + cl::opt Preprocessor("E",cl::desc("Run preprocessor stage."), + cl::cat(StageSelectionCat)); + + cl::opt NoLink("c",cl::desc("Run all stages except linking."), + cl::cat(StageSelectionCat)); + +The output of ``-help`` will become categorized if an option category is +declared. The output looks something like :: + + OVERVIEW: This is a small program to demo the LLVM CommandLine API + USAGE: Sample [options] + + OPTIONS: + + General options: + + -help - Display available options (-help-hidden for more) + -help-list - Display list of available options (-help-list-hidden for more) + + + Stage Selection Options: + These control which stages are run. + + -E - Run preprocessor stage. + -c - Run all stages except linking. + +In addition to the behaviour of ``-help`` changing when an option category is +declared, the command line option ``-help-list`` becomes visible which will +print the command line options as uncategorized list. + +Note that Options that are not explicitly categorized will be placed in the +``cl::GeneralCategory`` category. + .. _Reference Guide: Reference Guide @@ -946,6 +993,11 @@ This section describes the basic attributes that you can specify on options. of the usual modifiers on multi-valued options (besides ``cl::ValueDisallowed``, obviously). +.. _cl::cat: + +* The **cl::cat** attribute specifies the option category that the option + belongs to. The category should be a `cl::OptionCategory`_ object. + Option Modifiers ---------------- @@ -1385,6 +1437,29 @@ For example: cl::extrahelp("\nADDITIONAL HELP:\n\n This is the extra help\n"); +.. _cl::OptionCategory: + +The ``cl::OptionCategory`` class +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``cl::OptionCategory`` class is a simple class for declaring +option categories. + +.. code-block:: c++ + + namespace cl { + class OptionCategory; + } + +An option category must have a name and optionally a description which are +passed to the constructor as ``const char*``. + +Note that declaring an option category and associating it with an option before +parsing options (e.g. statically) will change the output of ``-help`` from +uncategorized to categorized. If an option category is declared but not +associated with an option then it will be hidden from the output of ``-help`` +but will be shown in the output of ``-help-hidden``. + .. _different parser: .. _discussed previously: diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 2e84d7b349d..19b716427ff 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -137,7 +137,23 @@ enum MiscFlags { // Miscellaneous flags to adjust argument Sink = 0x04 // Should this cl::list eat all unknown options? }; +//===----------------------------------------------------------------------===// +// Option Category class +// +class OptionCategory { +private: + const char *const Name; + const char *const Description; + void registerCategory(); +public: + OptionCategory(const char *const Name, const char *const Description = 0) + : Name(Name), Description(Description) { registerCategory(); } + const char *getName() { return Name; } + const char *getDescription() { return Description; } +}; +// The general Option Category (used as default category). +extern OptionCategory GeneralCategory; //===----------------------------------------------------------------------===// // Option Base class @@ -173,10 +189,12 @@ class Option { unsigned Position; // Position of last occurrence of the option unsigned AdditionalVals;// Greater than 0 for multi-valued option. Option *NextRegistered; // Singly linked list of registered options. + public: - const char *ArgStr; // The argument string itself (ex: "help", "o") - const char *HelpStr; // The descriptive text message for -help - const char *ValueStr; // String describing what the value of this option is + const char *ArgStr; // The argument string itself (ex: "help", "o") + const char *HelpStr; // The descriptive text message for -help + const char *ValueStr; // String describing what the value of this option is + OptionCategory *Category; // The Category this option belongs to inline enum NumOccurrencesFlag getNumOccurrencesFlag() const { return (enum NumOccurrencesFlag)Occurrences; @@ -214,13 +232,14 @@ public: void setFormattingFlag(enum FormattingFlags V) { Formatting = V; } void setMiscFlag(enum MiscFlags M) { Misc |= M; } void setPosition(unsigned pos) { Position = pos; } + void setCategory(OptionCategory &C) { Category = &C; } protected: explicit Option(enum NumOccurrencesFlag OccurrencesFlag, enum OptionHidden Hidden) : NumOccurrences(0), Occurrences(OccurrencesFlag), Value(0), HiddenFlag(Hidden), Formatting(NormalFormatting), Misc(0), Position(0), AdditionalVals(0), NextRegistered(0), - ArgStr(""), HelpStr(""), ValueStr("") { + ArgStr(""), HelpStr(""), ValueStr(""), Category(&GeneralCategory) { } inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; } @@ -312,6 +331,16 @@ struct LocationClass { template LocationClass location(Ty &L) { return LocationClass(L); } +// cat - Specifiy the Option category for the command line argument to belong +// to. +struct cat { + OptionCategory &Category; + cat(OptionCategory &c) : Category(c) {} + + template + void apply(Opt &O) const { O.setCategory(Category); } +}; + //===----------------------------------------------------------------------===// // OptionValue class @@ -1674,10 +1703,15 @@ struct extrahelp { }; void PrintVersionMessage(); -// This function just prints the help message, exactly the same way as if the -// -help option had been given on the command line. -// NOTE: THIS FUNCTION TERMINATES THE PROGRAM! -void PrintHelpMessage(); + +/// This function just prints the help message, exactly the same way as if the +/// -help or -help-hidden option had been given on the command line. +/// +/// NOTE: THIS FUNCTION TERMINATES THE PROGRAM! +/// +/// \param hidden if true will print hidden options +/// \param categorized if true print options in categories +void PrintHelpMessage(bool Hidden=false, bool Categorized=false); } // End namespace cl diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 560d7eb289c..8e937794be6 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/system_error.h" #include #include +#include using namespace llvm; using namespace cl; @@ -106,6 +107,17 @@ void Option::addArgument() { MarkOptionsChanged(); } +// This collects the different option categories that have been registered. +typedef SmallPtrSet OptionCatSet; +static ManagedStatic RegisteredOptionCategories; + +// Initialise the general option category. +OptionCategory llvm::cl::GeneralCategory("General options"); + +void OptionCategory::registerCategory() +{ + RegisteredOptionCategories->insert(this); +} //===----------------------------------------------------------------------===// // Basic, shared command line option processing machinery. @@ -1222,11 +1234,20 @@ sortOpts(StringMap &OptMap, namespace { class HelpPrinter { +protected: const bool ShowHidden; + typedef SmallVector,128> StrOptionPairVector; + // Print the options. Opts is assumed to be alphabetically sorted. + virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) { + for (size_t i = 0, e = Opts.size(); i != e; ++i) + Opts[i].second->printOptionInfo(MaxArgLen); + } public: explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) {} + virtual ~HelpPrinter() {} + // Invoke the printer. void operator=(bool Value) { if (Value == false) return; @@ -1236,7 +1257,7 @@ public: StringMap OptMap; GetOptionInfo(PositionalOpts, SinkOpts, OptMap); - SmallVector, 128> Opts; + StrOptionPairVector Opts; sortOpts(OptMap, Opts, ShowHidden); if (ProgramOverview) @@ -1267,12 +1288,12 @@ public: MaxArgLen = std::max(MaxArgLen, Opts[i].second->getOptionWidth()); outs() << "OPTIONS:\n"; - for (size_t i = 0, e = Opts.size(); i != e; ++i) - Opts[i].second->printOptionInfo(MaxArgLen); + printOptions(Opts, MaxArgLen); // Print any extra help the user has declared. for (std::vector::iterator I = MoreHelp->begin(), - E = MoreHelp->end(); I != E; ++I) + E = MoreHelp->end(); + I != E; ++I) outs() << *I; MoreHelp->clear(); @@ -1280,21 +1301,152 @@ public: exit(1); } }; + +class CategorizedHelpPrinter : public HelpPrinter { +public: + explicit CategorizedHelpPrinter(bool showHidden) : HelpPrinter(showHidden) {} + + // Helper function for printOptions(). + // It shall return true if A's name should be lexographically + // ordered before B's name. It returns false otherwise. + static bool OptionCategoryCompare(OptionCategory *A, OptionCategory *B) { + int Length = strcmp(A->getName(), B->getName()); + assert(Length != 0 && "Duplicate option categories"); + return Length < 0; + } + + // Make sure we inherit our base class's operator=() + using HelpPrinter::operator= ; + +protected: + virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen) { + std::vector SortedCategories; + std::map > CategorizedOptions; + + // Collect registered option categories into vector in preperation for + // sorting. + for (OptionCatSet::const_iterator I = RegisteredOptionCategories->begin(), + E = RegisteredOptionCategories->end(); + I != E; ++I) + SortedCategories.push_back(*I); + + // Sort the different option categories alphabetically. + assert(SortedCategories.size() > 0 && "No option categories registered!"); + std::sort(SortedCategories.begin(), SortedCategories.end(), + OptionCategoryCompare); + + // Create map to empty vectors. + for (std::vector::const_iterator + I = SortedCategories.begin(), + E = SortedCategories.end(); + I != E; ++I) + CategorizedOptions[*I] = std::vector