[llvm] r181254 - Implemented public interface for modifying registered (not positional or sink options) command line options at runtime.

Andrew Trick atrick at apple.com
Mon May 6 14:56:35 PDT 2013


Author: atrick
Date: Mon May  6 16:56:35 2013
New Revision: 181254

URL: http://llvm.org/viewvc/llvm-project?rev=181254&view=rev
Log:
Implemented public interface for modifying registered (not positional or sink options) command line options at runtime.

Patch by Dan Liew!

Modified:
    llvm/trunk/docs/CommandLine.rst
    llvm/trunk/include/llvm/Support/CommandLine.h
    llvm/trunk/lib/Support/CommandLine.cpp
    llvm/trunk/unittests/Support/CommandLineTest.cpp

Modified: llvm/trunk/docs/CommandLine.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandLine.rst?rev=181254&r1=181253&r2=181254&view=diff
==============================================================================
--- llvm/trunk/docs/CommandLine.rst (original)
+++ llvm/trunk/docs/CommandLine.rst Mon May  6 16:56:35 2013
@@ -1267,6 +1267,57 @@ only consists of one function `cl::Parse
 classes: `cl::opt`_, `cl::list`_, and `cl::alias`_.  This section describes
 these three classes in detail.
 
+.. _cl::getRegisteredOptions:
+
+The ``cl::getRegisteredOptions`` function
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``cl::getRegisteredOptions`` function is designed to give a programmer
+access to declared non positional command line options so that how they appear
+in ``-help`` can be modified prior to calling `cl::ParseCommandLineOptions`_.
+Note this method should not be called during any static initialisation because
+it cannot be guaranteed that all options will have been initialised. Hence it
+should be called from ``main``.
+
+This function can be used to gain access to options declared in libraries that
+the tool writter may not have direct access to.
+
+The function retrieves a :ref:`StringMap <dss_stringmap>` that maps the option
+string (e.g. ``-help``) to an ``Option*``.
+
+Here is an example of how the function could be used:
+
+.. code-block:: c++
+
+  using namespace llvm;
+  int main(int argc, char **argv) {
+    cl::OptionCategory AnotherCategory("Some options");
+
+    StringMap<cl::Option*> Map;
+    cl::getRegisteredOptions(Map);
+
+    //Unhide useful option and put it in a different category
+    assert(Map.count("print-all-options") > 0);
+    Map["print-all-options"]->setHiddenFlag(cl::NotHidden);
+    Map["print-all-options"]->setCategory(AnotherCategory);
+
+    //Hide an option we don't want to see
+    assert(Map.count("enable-no-infs-fp-math") > 0);
+    Map["enable-no-infs-fp-math"]->setHiddenFlag(cl::Hidden);
+
+    //Change --version to --show-version
+    assert(Map.count("version") > 0);
+    Map["version"]->setArgStr("show-version");
+
+    //Change --help description
+    assert(Map.count("help") > 0);
+    Map["help"]->setDescription("Shows help");
+
+    cl::ParseCommandLineOptions(argc, argv, "This is a small program to demo the LLVM CommandLine API");
+    ...
+  }
+
+
 .. _cl::ParseCommandLineOptions:
 
 The ``cl::ParseCommandLineOptions`` function

Modified: llvm/trunk/include/llvm/Support/CommandLine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/CommandLine.h?rev=181254&r1=181253&r2=181254&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/CommandLine.h (original)
+++ llvm/trunk/include/llvm/Support/CommandLine.h Mon May  6 16:56:35 2013
@@ -22,6 +22,7 @@
 
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/type_traits.h"
 #include <cassert>
@@ -1713,6 +1714,39 @@ void PrintVersionMessage();
 /// \param categorized if true print options in categories
 void PrintHelpMessage(bool Hidden=false, bool Categorized=false);
 
+
+//===----------------------------------------------------------------------===//
+// Public interface for accessing registered options.
+//
+
+/// \brief Use this to get a StringMap to all registered named options
+/// (e.g. -help). Note \p Map Should be an empty StringMap.
+///
+/// \param [out] map will be filled with mappings where the key is the
+/// Option argument string (e.g. "help") and value is the corresponding
+/// Option*.
+///
+/// Access to unnamed arguments (i.e. positional) are not provided because
+/// it is expected that the client already has access to these.
+///
+/// Typical usage:
+/// \code
+/// main(int argc,char* argv[]) {
+/// StringMap<llvm::cl::Option*> opts;
+/// llvm::cl::getRegisteredOptions(opts);
+/// assert(opts.count("help") == 1)
+/// opts["help"]->setDescription("Show alphabetical help information")
+/// // More code
+/// llvm::cl::ParseCommandLineOptions(argc,argv);
+/// //More code
+/// }
+/// \endcode
+///
+/// This interface is useful for modifying options in libraries that are out of
+/// the control of the client. The options should be modified before calling
+/// llvm::cl::ParseCommandLineOptions().
+void getRegisteredOptions(StringMap<Option*> &Map);
+
 } // End namespace cl
 
 } // End namespace llvm

Modified: llvm/trunk/lib/Support/CommandLine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CommandLine.cpp?rev=181254&r1=181253&r2=181254&view=diff
==============================================================================
--- llvm/trunk/lib/Support/CommandLine.cpp (original)
+++ llvm/trunk/lib/Support/CommandLine.cpp Mon May  6 16:56:35 2013
@@ -1596,3 +1596,13 @@ void cl::AddExtraVersionPrinter(void (*f
 
   ExtraVersionPrinters->push_back(func);
 }
+
+void cl::getRegisteredOptions(StringMap<Option*> &Map)
+{
+  // Get all the options.
+  SmallVector<Option*, 4> PositionalOpts; //NOT USED
+  SmallVector<Option*, 4> SinkOpts;  //NOT USED
+  assert(Map.size() == 0 && "StringMap must be empty");
+  GetOptionInfo(PositionalOpts, SinkOpts, Map);
+  return;
+}

Modified: llvm/trunk/unittests/Support/CommandLineTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/CommandLineTest.cpp?rev=181254&r1=181253&r2=181254&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/CommandLineTest.cpp (original)
+++ llvm/trunk/unittests/Support/CommandLineTest.cpp Mon May  6 16:56:35 2013
@@ -41,6 +41,45 @@ class TempEnvVar {
   const char *const name;
 };
 
+cl::OptionCategory TestCategory("Test Options", "Description");
+cl::opt<int> TestOption("test-option", cl::desc("old description"));
+TEST(CommandLineTest, ModifyExisitingOption) {
+  const char Description[] = "New description";
+  const char ArgString[] = "new-test-option";
+  const char ValueString[] = "Integer";
+
+  StringMap<cl::Option*> Map;
+  cl::getRegisteredOptions(Map);
+
+  ASSERT_TRUE(Map.count("test-option") == 1) <<
+    "Could not find option in map.";
+
+  cl::Option *Retrieved = Map["test-option"];
+  ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
+
+  ASSERT_EQ(&cl::GeneralCategory,Retrieved->Category) <<
+    "Incorrect default option category.";
+
+  Retrieved->setCategory(TestCategory);
+  ASSERT_EQ(&TestCategory,Retrieved->Category) <<
+    "Failed to modify option's option category.";
+
+  Retrieved->setDescription(Description);
+  ASSERT_STREQ(Retrieved->HelpStr, Description) <<
+    "Changing option description failed.";
+
+  Retrieved->setArgStr(ArgString);
+  ASSERT_STREQ(ArgString, Retrieved->ArgStr) <<
+    "Failed to modify option's Argument string.";
+
+  Retrieved->setValueStr(ValueString);
+  ASSERT_STREQ(Retrieved->ValueStr, ValueString) <<
+    "Failed to modify option's Value string.";
+
+  Retrieved->setHiddenFlag(cl::Hidden);
+  ASSERT_EQ(cl::Hidden, TestOption.getOptionHiddenFlag()) <<
+    "Failed to modify option's hidden flag.";
+}
 #ifndef SKIP_ENVIRONMENT_TESTS
 
 const char test_env_var[] = "LLVM_TEST_COMMAND_LINE_FLAGS";
@@ -55,6 +94,12 @@ TEST(CommandLineTest, ParseEnvironment)
 
 // This test used to make valgrind complain
 // ("Conditional jump or move depends on uninitialised value(s)")
+//
+// Warning: Do not run any tests after this one that try to gain access to
+// registered command line options because this will likely result in a
+// SEGFAULT. This can occur because the cl::opt in the test below is declared
+// on the stack which will be destroyed after the test completes but the
+// command line system will still hold a pointer to a deallocated cl::Option.
 TEST(CommandLineTest, ParseEnvironmentToLocalVar) {
   // Put cl::opt on stack to check for proper initialization of fields.
   cl::opt<std::string> EnvironmentTestOptionLocal("env-test-opt-local");
@@ -67,10 +112,9 @@ TEST(CommandLineTest, ParseEnvironmentTo
 #endif  // SKIP_ENVIRONMENT_TESTS
 
 TEST(CommandLineTest, UseOptionCategory) {
-  cl::OptionCategory TestCategory("Test Options", "Description");
-  cl::opt<int> TestOption("test-option", cl::cat(TestCategory));
+  cl::opt<int> TestOption2("test-option", cl::cat(TestCategory));
 
-  ASSERT_EQ(&TestCategory,TestOption.Category) << "Failed to assign Option "
+  ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option "
                                                   "Category.";
 }
 





More information about the llvm-commits mailing list