forked from OSchip/llvm-project
Implemented public interface for modifying registered (not positional or sink options) command line options at runtime.
Patch by Dan Liew! llvm-svn: 181254
This commit is contained in:
parent
0537a98878
commit
7cb710d58c
|
@ -1267,6 +1267,57 @@ only consists of one function `cl::ParseCommandLineOptions`_) and three main
|
||||||
classes: `cl::opt`_, `cl::list`_, and `cl::alias`_. This section describes
|
classes: `cl::opt`_, `cl::list`_, and `cl::alias`_. This section describes
|
||||||
these three classes in detail.
|
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:
|
.. _cl::ParseCommandLineOptions:
|
||||||
|
|
||||||
The ``cl::ParseCommandLineOptions`` function
|
The ``cl::ParseCommandLineOptions`` function
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/Twine.h"
|
#include "llvm/ADT/Twine.h"
|
||||||
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Support/type_traits.h"
|
#include "llvm/Support/type_traits.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -1713,6 +1714,39 @@ void PrintVersionMessage();
|
||||||
/// \param categorized if true print options in categories
|
/// \param categorized if true print options in categories
|
||||||
void PrintHelpMessage(bool Hidden=false, bool Categorized=false);
|
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 cl
|
||||||
|
|
||||||
} // End namespace llvm
|
} // End namespace llvm
|
||||||
|
|
|
@ -1596,3 +1596,13 @@ void cl::AddExtraVersionPrinter(void (*func)()) {
|
||||||
|
|
||||||
ExtraVersionPrinters->push_back(func);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,45 @@ class TempEnvVar {
|
||||||
const char *const name;
|
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
|
#ifndef SKIP_ENVIRONMENT_TESTS
|
||||||
|
|
||||||
const char test_env_var[] = "LLVM_TEST_COMMAND_LINE_FLAGS";
|
const char test_env_var[] = "LLVM_TEST_COMMAND_LINE_FLAGS";
|
||||||
|
@ -55,6 +94,12 @@ TEST(CommandLineTest, ParseEnvironment) {
|
||||||
|
|
||||||
// This test used to make valgrind complain
|
// This test used to make valgrind complain
|
||||||
// ("Conditional jump or move depends on uninitialised value(s)")
|
// ("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) {
|
TEST(CommandLineTest, ParseEnvironmentToLocalVar) {
|
||||||
// Put cl::opt on stack to check for proper initialization of fields.
|
// Put cl::opt on stack to check for proper initialization of fields.
|
||||||
cl::opt<std::string> EnvironmentTestOptionLocal("env-test-opt-local");
|
cl::opt<std::string> EnvironmentTestOptionLocal("env-test-opt-local");
|
||||||
|
@ -67,10 +112,9 @@ TEST(CommandLineTest, ParseEnvironmentToLocalVar) {
|
||||||
#endif // SKIP_ENVIRONMENT_TESTS
|
#endif // SKIP_ENVIRONMENT_TESTS
|
||||||
|
|
||||||
TEST(CommandLineTest, UseOptionCategory) {
|
TEST(CommandLineTest, UseOptionCategory) {
|
||||||
cl::OptionCategory TestCategory("Test Options", "Description");
|
cl::opt<int> TestOption2("test-option", cl::cat(TestCategory));
|
||||||
cl::opt<int> TestOption("test-option", cl::cat(TestCategory));
|
|
||||||
|
|
||||||
ASSERT_EQ(&TestCategory,TestOption.Category) << "Failed to assign Option "
|
ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option "
|
||||||
"Category.";
|
"Category.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue