[PATCH] D24489: [Support][CommandLine] Add cl::getRegisteredSubcommands()

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 13 10:13:03 PDT 2016


On Mon, Sep 12, 2016 at 6:57 PM Dean Michael Berris <dberris at google.com>
wrote:

> dberris created this revision.
> dberris added reviewers: zturner, dblaikie, echristo.
> dberris added a subscriber: llvm-commits.
> Herald added a subscriber: mehdi_amini.
>
> This should allow users of the library to get a range to iterate through
> all the subcommands that are registered to the global parser. This
> allows users to define subcommands in libraries that self-register to
> have dispatch done at a different stage (like main). It allows for
> writing code like the following:
>
>     for (auto *S : cl::getRegisteredSubcommands()) {
>       if (*S) {
>         // Dispatch on S->getName().
>       }
>     }
>

FWIW: I wasn't expecting/suggesting we should have to compare by strings
(stringly typed isn't ideal, of course) - I was hoping/figuring we could
declaer the subcommand in the header (along with the single entry point
function) and then define it over in the file that defines the single entry
point along with the subcommand's flags.

Did this not work for some reason?


>
> This change also contains tests that show this usage pattern.
>
> https://reviews.llvm.org/D24489
>
> Files:
>   include/llvm/Support/CommandLine.h
>   lib/Support/CommandLine.cpp
>   unittests/Support/CommandLineTest.cpp
>
> Index: unittests/Support/CommandLineTest.cpp
> ===================================================================
> --- unittests/Support/CommandLineTest.cpp
> +++ unittests/Support/CommandLineTest.cpp
> @@ -476,4 +476,26 @@
>    EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
>  }
>
> +TEST(CommandLineTest, GetRegisteredSubcommands) {
> +  cl::ResetCommandLineParser();
> +
> +  StackSubCommand SC1("sc1", "First Subcommand");
> +  StackSubCommand SC2("sc2", "Second subcommand");
> +
> +  const char *args0[] = {"prog", "sc1"};
> +  const char *args1[] = {"prog", "sc2"};
> +
> +  EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, nullptr, true));
> +  for (auto* S : cl::getRegisteredSubcommands()) {
> +    if (*S) EXPECT_STREQ("sc1", S->getName());
> +  }
> +
> +  cl::ResetAllOptionOccurrences();
> +  EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1, nullptr, true));
> +  for (auto* S : cl::getRegisteredSubcommands()) {
> +    if (*S) EXPECT_STREQ("sc2", S->getName());
> +  }
> +
> +}
> +
>  }  // anonymous namespace
> Index: lib/Support/CommandLine.cpp
> ===================================================================
> --- lib/Support/CommandLine.cpp
> +++ lib/Support/CommandLine.cpp
> @@ -309,6 +309,12 @@
>      RegisteredSubCommands.erase(sub);
>    }
>
> +  iterator_range<typename SmallPtrSet<SubCommand *, 4>::iterator>
> +  getRegisteredSubcommands() {
> +    return make_range(RegisteredSubCommands.begin(),
> +                      RegisteredSubCommands.end());
> +  }
> +
>    void reset() {
>      ActiveSubCommand = nullptr;
>      ProgramName.clear();
> @@ -2105,6 +2111,11 @@
>    return Sub.OptionsMap;
>  }
>
> +iterator_range<typename SmallPtrSet<SubCommand *, 4>::iterator>
> +cl::getRegisteredSubcommands() {
> +  return GlobalParser->getRegisteredSubcommands();
> +}
> +
>  void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand
> &Sub) {
>    for (auto &I : Sub.OptionsMap) {
>      if (I.second->Category != &Category &&
> Index: include/llvm/Support/CommandLine.h
> ===================================================================
> --- include/llvm/Support/CommandLine.h
> +++ include/llvm/Support/CommandLine.h
> @@ -1736,6 +1736,28 @@
>  /// than just handing around a global list.
>  StringMap<Option *> &getRegisteredOptions(SubCommand &Sub =
> *TopLevelSubCommand);
>
> +/// \brief Use this to get all registered SubCommands from the provided
> parser.
> +///
> +/// \return A range of all SubCommand pointers registered with the parser.
> +///
> +/// Typical usage:
> +/// \code
> +/// main(int argc, char* argv[]) {
> +///   llvm::cl::ParseCommandLineOptions(argc, argv);
> +///   for (auto* S : llvm::cl::getRegisteredSubcommands()) {
> +///     if (*S) {
> +///       std::cout << "Executing subcommand: " << S->getName() <<
> std::endl;
> +///       // Execute some function based on the name...
> +///     }
> +///   }
> +/// }
> +/// \endcode
> +///
> +/// This interface is useful for defining subcommands in libraries and
> +/// the dispatch from a single point (like in the main function).
> +iterator_range<typename SmallPtrSet<SubCommand *, 4>::iterator>
> +getRegisteredSubcommands();
> +
>
>  //===----------------------------------------------------------------------===//
>  // Standalone command line processing utilities.
>  //
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160913/db7c5f4d/attachment.html>


More information about the llvm-commits mailing list