Loading llvm/docs/CommandLine.rst +75 −0 Original line number Diff line number Diff line Loading @@ -618,6 +618,53 @@ would yield the help output: -help - display available options (-help-hidden for more) -o <filename> - 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<bool> Preprocessor("E",cl::desc("Run preprocessor stage."), cl::cat(StageSelectionCat)); cl::opt<bool> 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 Loading Loading @@ -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 ---------------- Loading Loading @@ -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: Loading llvm/include/llvm/Support/CommandLine.h +42 −8 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 OptionCategory *Category; // The Category this option belongs to inline enum NumOccurrencesFlag getNumOccurrencesFlag() const { return (enum NumOccurrencesFlag)Occurrences; Loading Loading @@ -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; } Loading Loading @@ -312,6 +331,16 @@ struct LocationClass { template<class Ty> LocationClass<Ty> location(Ty &L) { return LocationClass<Ty>(L); } // cat - Specifiy the Option category for the command line argument to belong // to. struct cat { OptionCategory &Category; cat(OptionCategory &c) : Category(c) {} template<class Opt> void apply(Opt &O) const { O.setCategory(Category); } }; //===----------------------------------------------------------------------===// // OptionValue class Loading Loading @@ -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 Loading llvm/lib/Support/CommandLine.cpp +198 −20 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ #include "llvm/Support/system_error.h" #include <cerrno> #include <cstdlib> #include <map> using namespace llvm; using namespace cl; Loading Loading @@ -106,6 +107,17 @@ void Option::addArgument() { MarkOptionsChanged(); } // This collects the different option categories that have been registered. typedef SmallPtrSet<OptionCategory*,16> OptionCatSet; static ManagedStatic<OptionCatSet> 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. Loading Loading @@ -1222,11 +1234,20 @@ sortOpts(StringMap<Option*> &OptMap, namespace { class HelpPrinter { protected: const bool ShowHidden; typedef SmallVector<std::pair<const char *, Option*>,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; Loading @@ -1236,7 +1257,7 @@ public: StringMap<Option*> OptMap; GetOptionInfo(PositionalOpts, SinkOpts, OptMap); SmallVector<std::pair<const char *, Option*>, 128> Opts; StrOptionPairVector Opts; sortOpts(OptMap, Opts, ShowHidden); if (ProgramOverview) Loading Loading @@ -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<const char *>::iterator I = MoreHelp->begin(), E = MoreHelp->end(); I != E; ++I) E = MoreHelp->end(); I != E; ++I) outs() << *I; MoreHelp->clear(); Loading @@ -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<OptionCategory *> SortedCategories; std::map<OptionCategory *, std::vector<Option *> > 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<OptionCategory *>::const_iterator I = SortedCategories.begin(), E = SortedCategories.end(); I != E; ++I) CategorizedOptions[*I] = std::vector<Option *>(); // Walk through pre-sorted options and assign into categories. // Because the options are already alphabetically sorted the // options within categories will also be alphabetically sorted. for (size_t I = 0, E = Opts.size(); I != E; ++I) { Option *Opt = Opts[I].second; assert(CategorizedOptions.count(Opt->Category) > 0 && "Option has an unregistered category"); CategorizedOptions[Opt->Category].push_back(Opt); } // Now do printing. for (std::vector<OptionCategory *>::const_iterator Category = SortedCategories.begin(), E = SortedCategories.end(); Category != E; ++Category) { // Hide empty categories for -help, but show for -help-hidden. bool IsEmptyCategory = CategorizedOptions[*Category].size() == 0; if (!ShowHidden && IsEmptyCategory) continue; // Print category information. outs() << "\n"; outs() << (*Category)->getName() << ":\n"; // Check if description is set. if ((*Category)->getDescription() != 0) outs() << (*Category)->getDescription() << "\n\n"; else outs() << "\n"; // When using -help-hidden explicitly state if the category has no // options associated with it. if (IsEmptyCategory) { outs() << " This option category has no options.\n"; continue; } // Loop over the options in the category and print. for (std::vector<Option *>::const_iterator Opt = CategorizedOptions[*Category].begin(), E = CategorizedOptions[*Category].end(); Opt != E; ++Opt) (*Opt)->printOptionInfo(MaxArgLen); } } }; // This wraps the Uncategorizing and Categorizing printers and decides // at run time which should be invoked. class HelpPrinterWrapper { private: HelpPrinter &UncategorizedPrinter; CategorizedHelpPrinter &CategorizedPrinter; public: explicit HelpPrinterWrapper(HelpPrinter &UncategorizedPrinter, CategorizedHelpPrinter &CategorizedPrinter) : UncategorizedPrinter(UncategorizedPrinter), CategorizedPrinter(CategorizedPrinter) { } // Invoke the printer. void operator=(bool Value); }; } // End anonymous namespace // Define the two HelpPrinter instances that are used to print out help, or // help-hidden... // static HelpPrinter NormalPrinter(false); static HelpPrinter HiddenPrinter(true); // Declare the four HelpPrinter instances that are used to print out help, or // help-hidden as an uncategorized list or in categories. static HelpPrinter UncategorizedNormalPrinter(false); static HelpPrinter UncategorizedHiddenPrinter(true); static CategorizedHelpPrinter CategorizedNormalPrinter(false); static CategorizedHelpPrinter CategorizedHiddenPrinter(true); // Declare HelpPrinter wrappers that will decide whether or not to invoke // a categorizing help printer static HelpPrinterWrapper WrappedNormalPrinter(UncategorizedNormalPrinter, CategorizedNormalPrinter); static HelpPrinterWrapper WrappedHiddenPrinter(UncategorizedHiddenPrinter, CategorizedHiddenPrinter); // Define uncategorized help printers. // -help-list is hidden by default because if Option categories are being used // then -help behaves the same as -help-list. static cl::opt<HelpPrinter, true, parser<bool> > HOp("help", cl::desc("Display available options (-help-hidden for more)"), cl::location(NormalPrinter), cl::ValueDisallowed); HLOp("help-list", cl::desc("Display list of available options (-help-list-hidden for more)"), cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed); static cl::opt<HelpPrinter, true, parser<bool> > HLHOp("help-list-hidden", cl::desc("Display list of all available options"), cl::location(UncategorizedHiddenPrinter), cl::Hidden, cl::ValueDisallowed); // Define uncategorized/categorized help printers. These printers change their // behaviour at runtime depending on whether one or more Option categories have // been declared. static cl::opt<HelpPrinterWrapper, true, parser<bool> > HOp("help", cl::desc("Display available options (-help-hidden for more)"), cl::location(WrappedNormalPrinter), cl::ValueDisallowed); static cl::opt<HelpPrinterWrapper, true, parser<bool> > HHOp("help-hidden", cl::desc("Display all available options"), cl::location(HiddenPrinter), cl::Hidden, cl::ValueDisallowed); cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed); static cl::opt<bool> PrintOptions("print-options", Loading @@ -1306,6 +1458,24 @@ PrintAllOptions("print-all-options", cl::desc("Print all option values after command line parsing"), cl::Hidden, cl::init(false)); void HelpPrinterWrapper::operator=(bool Value) { if (Value == false) return; // Decide which printer to invoke. If more than one option category is // registered then it is useful to show the categorized help instead of // uncategorized help. if (RegisteredOptionCategories->size() > 1) { // unhide -help-list option so user can have uncategorized output if they // want it. HLOp.setHiddenFlag(NotHidden); CategorizedPrinter = true; // Invoke categorized printer } else UncategorizedPrinter = true; // Invoke uncategorized printer } // Print the value of each option. void cl::PrintOptionValues() { if (!PrintOptions && !PrintAllOptions) return; Loading Loading @@ -1393,14 +1563,22 @@ VersOp("version", cl::desc("Display the version of this program"), cl::location(VersionPrinterInstance), cl::ValueDisallowed); // Utility function for printing the help message. void cl::PrintHelpMessage() { // This looks weird, but it actually prints the help message. The // NormalPrinter variable is a HelpPrinter and the help gets printed when // its operator= is invoked. That's because the "normal" usages of the // help printer is to be assigned true/false depending on whether the // -help option was given or not. Since we're circumventing that we have // to make it look like -help was given, so we assign true. NormalPrinter = true; void cl::PrintHelpMessage(bool Hidden, bool Categorized) { // This looks weird, but it actually prints the help message. The Printers are // types of HelpPrinter and the help gets printed when its operator= is // invoked. That's because the "normal" usages of the help printer is to be // assigned true/false depending on whether -help or -help-hidden was given or // not. Since we're circumventing that we have to make it look like -help or // -help-hidden were given, so we assign true. if (!Hidden && !Categorized) UncategorizedNormalPrinter = true; else if (!Hidden && Categorized) CategorizedNormalPrinter = true; else if (Hidden && !Categorized) UncategorizedHiddenPrinter = true; else CategorizedHiddenPrinter = true; } /// Utility function for printing version number. Loading llvm/unittests/Support/CommandLineTest.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -66,4 +66,12 @@ TEST(CommandLineTest, ParseEnvironmentToLocalVar) { #endif // SKIP_ENVIRONMENT_TESTS TEST(CommandLineTest, UseOptionCategory) { cl::OptionCategory TestCategory("Test Options", "Description"); cl::opt<int> TestOption("test-option", cl::cat(TestCategory)); ASSERT_EQ(&TestCategory,TestOption.Category) << "Failed to assign Option " "Category."; } } // anonymous namespace Loading
llvm/docs/CommandLine.rst +75 −0 Original line number Diff line number Diff line Loading @@ -618,6 +618,53 @@ would yield the help output: -help - display available options (-help-hidden for more) -o <filename> - 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<bool> Preprocessor("E",cl::desc("Run preprocessor stage."), cl::cat(StageSelectionCat)); cl::opt<bool> 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 Loading Loading @@ -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 ---------------- Loading Loading @@ -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: Loading
llvm/include/llvm/Support/CommandLine.h +42 −8 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 OptionCategory *Category; // The Category this option belongs to inline enum NumOccurrencesFlag getNumOccurrencesFlag() const { return (enum NumOccurrencesFlag)Occurrences; Loading Loading @@ -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; } Loading Loading @@ -312,6 +331,16 @@ struct LocationClass { template<class Ty> LocationClass<Ty> location(Ty &L) { return LocationClass<Ty>(L); } // cat - Specifiy the Option category for the command line argument to belong // to. struct cat { OptionCategory &Category; cat(OptionCategory &c) : Category(c) {} template<class Opt> void apply(Opt &O) const { O.setCategory(Category); } }; //===----------------------------------------------------------------------===// // OptionValue class Loading Loading @@ -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 Loading
llvm/lib/Support/CommandLine.cpp +198 −20 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ #include "llvm/Support/system_error.h" #include <cerrno> #include <cstdlib> #include <map> using namespace llvm; using namespace cl; Loading Loading @@ -106,6 +107,17 @@ void Option::addArgument() { MarkOptionsChanged(); } // This collects the different option categories that have been registered. typedef SmallPtrSet<OptionCategory*,16> OptionCatSet; static ManagedStatic<OptionCatSet> 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. Loading Loading @@ -1222,11 +1234,20 @@ sortOpts(StringMap<Option*> &OptMap, namespace { class HelpPrinter { protected: const bool ShowHidden; typedef SmallVector<std::pair<const char *, Option*>,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; Loading @@ -1236,7 +1257,7 @@ public: StringMap<Option*> OptMap; GetOptionInfo(PositionalOpts, SinkOpts, OptMap); SmallVector<std::pair<const char *, Option*>, 128> Opts; StrOptionPairVector Opts; sortOpts(OptMap, Opts, ShowHidden); if (ProgramOverview) Loading Loading @@ -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<const char *>::iterator I = MoreHelp->begin(), E = MoreHelp->end(); I != E; ++I) E = MoreHelp->end(); I != E; ++I) outs() << *I; MoreHelp->clear(); Loading @@ -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<OptionCategory *> SortedCategories; std::map<OptionCategory *, std::vector<Option *> > 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<OptionCategory *>::const_iterator I = SortedCategories.begin(), E = SortedCategories.end(); I != E; ++I) CategorizedOptions[*I] = std::vector<Option *>(); // Walk through pre-sorted options and assign into categories. // Because the options are already alphabetically sorted the // options within categories will also be alphabetically sorted. for (size_t I = 0, E = Opts.size(); I != E; ++I) { Option *Opt = Opts[I].second; assert(CategorizedOptions.count(Opt->Category) > 0 && "Option has an unregistered category"); CategorizedOptions[Opt->Category].push_back(Opt); } // Now do printing. for (std::vector<OptionCategory *>::const_iterator Category = SortedCategories.begin(), E = SortedCategories.end(); Category != E; ++Category) { // Hide empty categories for -help, but show for -help-hidden. bool IsEmptyCategory = CategorizedOptions[*Category].size() == 0; if (!ShowHidden && IsEmptyCategory) continue; // Print category information. outs() << "\n"; outs() << (*Category)->getName() << ":\n"; // Check if description is set. if ((*Category)->getDescription() != 0) outs() << (*Category)->getDescription() << "\n\n"; else outs() << "\n"; // When using -help-hidden explicitly state if the category has no // options associated with it. if (IsEmptyCategory) { outs() << " This option category has no options.\n"; continue; } // Loop over the options in the category and print. for (std::vector<Option *>::const_iterator Opt = CategorizedOptions[*Category].begin(), E = CategorizedOptions[*Category].end(); Opt != E; ++Opt) (*Opt)->printOptionInfo(MaxArgLen); } } }; // This wraps the Uncategorizing and Categorizing printers and decides // at run time which should be invoked. class HelpPrinterWrapper { private: HelpPrinter &UncategorizedPrinter; CategorizedHelpPrinter &CategorizedPrinter; public: explicit HelpPrinterWrapper(HelpPrinter &UncategorizedPrinter, CategorizedHelpPrinter &CategorizedPrinter) : UncategorizedPrinter(UncategorizedPrinter), CategorizedPrinter(CategorizedPrinter) { } // Invoke the printer. void operator=(bool Value); }; } // End anonymous namespace // Define the two HelpPrinter instances that are used to print out help, or // help-hidden... // static HelpPrinter NormalPrinter(false); static HelpPrinter HiddenPrinter(true); // Declare the four HelpPrinter instances that are used to print out help, or // help-hidden as an uncategorized list or in categories. static HelpPrinter UncategorizedNormalPrinter(false); static HelpPrinter UncategorizedHiddenPrinter(true); static CategorizedHelpPrinter CategorizedNormalPrinter(false); static CategorizedHelpPrinter CategorizedHiddenPrinter(true); // Declare HelpPrinter wrappers that will decide whether or not to invoke // a categorizing help printer static HelpPrinterWrapper WrappedNormalPrinter(UncategorizedNormalPrinter, CategorizedNormalPrinter); static HelpPrinterWrapper WrappedHiddenPrinter(UncategorizedHiddenPrinter, CategorizedHiddenPrinter); // Define uncategorized help printers. // -help-list is hidden by default because if Option categories are being used // then -help behaves the same as -help-list. static cl::opt<HelpPrinter, true, parser<bool> > HOp("help", cl::desc("Display available options (-help-hidden for more)"), cl::location(NormalPrinter), cl::ValueDisallowed); HLOp("help-list", cl::desc("Display list of available options (-help-list-hidden for more)"), cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed); static cl::opt<HelpPrinter, true, parser<bool> > HLHOp("help-list-hidden", cl::desc("Display list of all available options"), cl::location(UncategorizedHiddenPrinter), cl::Hidden, cl::ValueDisallowed); // Define uncategorized/categorized help printers. These printers change their // behaviour at runtime depending on whether one or more Option categories have // been declared. static cl::opt<HelpPrinterWrapper, true, parser<bool> > HOp("help", cl::desc("Display available options (-help-hidden for more)"), cl::location(WrappedNormalPrinter), cl::ValueDisallowed); static cl::opt<HelpPrinterWrapper, true, parser<bool> > HHOp("help-hidden", cl::desc("Display all available options"), cl::location(HiddenPrinter), cl::Hidden, cl::ValueDisallowed); cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed); static cl::opt<bool> PrintOptions("print-options", Loading @@ -1306,6 +1458,24 @@ PrintAllOptions("print-all-options", cl::desc("Print all option values after command line parsing"), cl::Hidden, cl::init(false)); void HelpPrinterWrapper::operator=(bool Value) { if (Value == false) return; // Decide which printer to invoke. If more than one option category is // registered then it is useful to show the categorized help instead of // uncategorized help. if (RegisteredOptionCategories->size() > 1) { // unhide -help-list option so user can have uncategorized output if they // want it. HLOp.setHiddenFlag(NotHidden); CategorizedPrinter = true; // Invoke categorized printer } else UncategorizedPrinter = true; // Invoke uncategorized printer } // Print the value of each option. void cl::PrintOptionValues() { if (!PrintOptions && !PrintAllOptions) return; Loading Loading @@ -1393,14 +1563,22 @@ VersOp("version", cl::desc("Display the version of this program"), cl::location(VersionPrinterInstance), cl::ValueDisallowed); // Utility function for printing the help message. void cl::PrintHelpMessage() { // This looks weird, but it actually prints the help message. The // NormalPrinter variable is a HelpPrinter and the help gets printed when // its operator= is invoked. That's because the "normal" usages of the // help printer is to be assigned true/false depending on whether the // -help option was given or not. Since we're circumventing that we have // to make it look like -help was given, so we assign true. NormalPrinter = true; void cl::PrintHelpMessage(bool Hidden, bool Categorized) { // This looks weird, but it actually prints the help message. The Printers are // types of HelpPrinter and the help gets printed when its operator= is // invoked. That's because the "normal" usages of the help printer is to be // assigned true/false depending on whether -help or -help-hidden was given or // not. Since we're circumventing that we have to make it look like -help or // -help-hidden were given, so we assign true. if (!Hidden && !Categorized) UncategorizedNormalPrinter = true; else if (!Hidden && Categorized) CategorizedNormalPrinter = true; else if (Hidden && !Categorized) UncategorizedHiddenPrinter = true; else CategorizedHiddenPrinter = true; } /// Utility function for printing version number. Loading
llvm/unittests/Support/CommandLineTest.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -66,4 +66,12 @@ TEST(CommandLineTest, ParseEnvironmentToLocalVar) { #endif // SKIP_ENVIRONMENT_TESTS TEST(CommandLineTest, UseOptionCategory) { cl::OptionCategory TestCategory("Test Options", "Description"); cl::opt<int> TestOption("test-option", cl::cat(TestCategory)); ASSERT_EQ(&TestCategory,TestOption.Category) << "Failed to assign Option " "Category."; } } // anonymous namespace