// (Currently not perfect, but best-effort.)
void PrintOptionValues();
-// MarkOptionsChanged - Internal helper function.
-void MarkOptionsChanged();
-
//===----------------------------------------------------------------------===//
// Flags permitted to be passed to command line arguments
//
unsigned Misc : 3;
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
+ bool FullyInitialized; // Has addArguemnt been called?
inline enum NumOccurrencesFlag getNumOccurrencesFlag() const {
return (enum NumOccurrencesFlag)Occurrences;
//-------------------------------------------------------------------------===
// Accessor functions set by OptionModifiers
//
- void setArgStr(const char *S) { ArgStr = S; }
+ void setArgStr(const char *S);
void setDescription(const char *S) { HelpStr = S; }
void setValueStr(const char *S) { ValueStr = S; }
void setNumOccurrencesFlag(enum NumOccurrencesFlag Val) { Occurrences = Val; }
enum OptionHidden Hidden)
: NumOccurrences(0), Occurrences(OccurrencesFlag), Value(0),
HiddenFlag(Hidden), Formatting(NormalFormatting), Misc(0), Position(0),
- AdditionalVals(0), NextRegistered(nullptr), ArgStr(""), HelpStr(""),
- ValueStr(""), Category(&GeneralCategory) {}
+ AdditionalVals(0), ArgStr(""), HelpStr(""), ValueStr(""),
+ Category(&GeneralCategory), FullyInitialized(false) {}
inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; }
/// For testing purposes only.
void removeArgument();
- Option *getNextRegisteredOption() const { return NextRegistered; }
-
// Return the width of the option tag for printing...
virtual size_t getOptionWidth() const = 0;
assert(findOption(Name) == Values.size() && "Option already exists!");
OptionInfo X(Name, static_cast<DataType>(V), HelpStr);
Values.push_back(X);
- MarkOptionsChanged();
+ AddLiteralOption(Owner, Name);
}
/// removeLiteralOption - Remove the specified option.
/// \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*.
+/// \return A reference to the StringMap used by the cl APIs to parse options.
///
/// 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);
+/// StringMap<llvm::cl::Option*> &opts = llvm::cl::getRegisteredOptions();
/// assert(opts.count("help") == 1)
/// opts["help"]->setDescription("Show alphabetical help information")
/// // More code
/// 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);
+///
+/// Hopefully this API can be depricated soon. Any situation where options need
+/// to be modified by tools or libraries should be handled by sane APIs rather
+/// than just handing around a global list.
+StringMap<Option *> &getRegisteredOptions();
//===----------------------------------------------------------------------===//
// Standalone command line processing utilities.
/// option category to display in the -help output.
void HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories);
+/// \brief Adds a new option for parsing and provides the option it refers to.
+///
+/// \param O pointer to the option
+/// \param Name the string name for the option to handle during parsing
+///
+/// Literal options are used by some parsers to register special option values.
+/// This is how the PassNameParser registers pass names for opt.
+void AddLiteralOption(Option &O, const char *Name);
+
} // End namespace cl
} // End namespace llvm
//===----------------------------------------------------------------------===//
-// Globals for name and overview of program. Program name is not a string to
-// avoid static ctor/dtor issues.
-static char ProgramName[80] = "<premain>";
-static const char *ProgramOverview = nullptr;
+class CommandLineParser {
+public:
+ // Globals for name and overview of program. Program name is not a string to
+ // avoid static ctor/dtor issues.
+ char ProgramName[80] = "<premain>";
+ const char *ProgramOverview = nullptr;
-// This collects additional help to be printed.
-static ManagedStatic<std::vector<const char *>> MoreHelp;
+ // This collects additional help to be printed.
+ std::vector<const char *> MoreHelp;
-extrahelp::extrahelp(const char *Help) : morehelp(Help) {
- MoreHelp->push_back(Help);
-}
+ SmallVector<Option *, 4> PositionalOpts;
+ SmallVector<Option *, 4> SinkOpts;
+ StringMap<Option *> OptionsMap;
-static bool OptionListChanged = false;
+ Option *ConsumeAfterOpt = nullptr; // The ConsumeAfter option if it exists.
-// MarkOptionsChanged - Internal helper function.
-void cl::MarkOptionsChanged() { OptionListChanged = true; }
+ void ParseCommandLineOptions(int argc, const char *const *argv,
+ const char *Overview);
-/// RegisteredOptionList - This is the list of the command line options that
-/// have statically constructed themselves.
-static Option *RegisteredOptionList = nullptr;
+ void addLiteralOption(Option &Opt, const char *Name) {
+ if (!Opt.hasArgStr()) {
+ if (!OptionsMap.insert(std::make_pair(Name, &Opt)).second) {
+ errs() << ProgramName << ": CommandLine Error: Option '" << Name
+ << "' registered more than once!\n";
+ report_fatal_error("inconsistency in registered CommandLine options");
+ }
+ }
+ }
-void Option::addArgument() {
- assert(!NextRegistered && "argument multiply registered!");
+ void addOption(Option *O) {
+ bool HadErrors = false;
+ if (O->ArgStr[0]) {
+ // Add argument to the argument map!
+ if (!OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) {
+ errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr
+ << "' registered more than once!\n";
+ HadErrors = true;
+ }
+ }
- NextRegistered = RegisteredOptionList;
- RegisteredOptionList = this;
- MarkOptionsChanged();
-}
+ // Remember information about positional options.
+ if (O->getFormattingFlag() == cl::Positional)
+ PositionalOpts.push_back(O);
+ else if (O->getMiscFlags() & cl::Sink) // Remember sink options
+ SinkOpts.push_back(O);
+ else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) {
+ if (ConsumeAfterOpt) {
+ O->error("Cannot specify more than one option with cl::ConsumeAfter!");
+ HadErrors = true;
+ }
+ ConsumeAfterOpt = O;
+ }
-void Option::removeArgument() {
- if (RegisteredOptionList == this) {
- RegisteredOptionList = NextRegistered;
- MarkOptionsChanged();
- return;
+ // Fail hard if there were errors. These are strictly unrecoverable and
+ // indicate serious issues such as conflicting option names or an
+ // incorrectly
+ // linked LLVM distribution.
+ if (HadErrors)
+ report_fatal_error("inconsistency in registered CommandLine options");
}
- Option *O = RegisteredOptionList;
- for (; O->NextRegistered != this; O = O->NextRegistered)
- ;
- O->NextRegistered = NextRegistered;
- MarkOptionsChanged();
+
+ void removeOption(Option *O) {
+ SmallVector<const char *, 16> OptionNames;
+ O->getExtraOptionNames(OptionNames);
+ if (O->ArgStr[0])
+ OptionNames.push_back(O->ArgStr);
+ for (auto Name : OptionNames)
+ OptionsMap.erase(StringRef(Name));
+
+ if (O->getFormattingFlag() == cl::Positional)
+ for (auto Opt = PositionalOpts.begin(); Opt != PositionalOpts.end();
+ ++Opt) {
+ if (*Opt == O) {
+ PositionalOpts.erase(Opt);
+ break;
+ }
+ }
+ else if (O->getMiscFlags() & cl::Sink)
+ for (auto Opt = SinkOpts.begin(); Opt != SinkOpts.end(); ++Opt) {
+ if (*Opt == O) {
+ SinkOpts.erase(Opt);
+ break;
+ }
+ }
+ else if (O == ConsumeAfterOpt)
+ ConsumeAfterOpt = nullptr;
+ }
+
+ bool hasOptions() {
+ return (!OptionsMap.empty() || !PositionalOpts.empty() ||
+ nullptr != ConsumeAfterOpt);
+ }
+
+ void updateArgStr(Option *O, const char* NewName) {
+ if (!OptionsMap.insert(std::make_pair(NewName, O)).second) {
+ errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr
+ << "' registered more than once!\n";
+ report_fatal_error("inconsistency in registered CommandLine options");
+ }
+ OptionsMap.erase(StringRef(O->ArgStr));
+ }
+};
+
+static ManagedStatic<CommandLineParser> GlobalParser;
+
+void cl::AddLiteralOption(Option &O, const char *Name) {
+ GlobalParser->addLiteralOption(O, Name);
+}
+
+extrahelp::extrahelp(const char *Help) : morehelp(Help) {
+ GlobalParser->MoreHelp.push_back(Help);
+}
+
+void Option::addArgument() {
+ GlobalParser->addOption(this);
+ FullyInitialized = true;
+}
+
+void Option::removeArgument() { GlobalParser->removeOption(this); }
+
+void Option::setArgStr(const char *S) {
+ if (FullyInitialized)
+ GlobalParser->updateArgStr(this, S);
+ ArgStr = S;
}
// This collects the different option categories that have been registered.
// Basic, shared command line option processing machinery.
//
-/// GetOptionInfo - Scan the list of registered options, turning them into data
-/// structures that are easier to handle.
-static void GetOptionInfo(SmallVectorImpl<Option *> &PositionalOpts,
- SmallVectorImpl<Option *> &SinkOpts,
- StringMap<Option *> &OptionsMap) {
- bool HadErrors = false;
- SmallVector<const char *, 16> OptionNames;
- Option *CAOpt = nullptr; // The ConsumeAfter option if it exists.
- for (Option *O = RegisteredOptionList; O; O = O->getNextRegisteredOption()) {
- // If this option wants to handle multiple option names, get the full set.
- // This handles enum options like "-O1 -O2" etc.
- O->getExtraOptionNames(OptionNames);
- if (O->ArgStr[0])
- OptionNames.push_back(O->ArgStr);
-
- // Handle named options.
- for (size_t i = 0, e = OptionNames.size(); i != e; ++i) {
- // Add argument to the argument map!
- if (!OptionsMap.insert(std::make_pair(OptionNames[i], O)).second) {
- errs() << ProgramName << ": CommandLine Error: Option '"
- << OptionNames[i] << "' registered more than once!\n";
- HadErrors = true;
- }
- }
-
- OptionNames.clear();
-
- // Remember information about positional options.
- if (O->getFormattingFlag() == cl::Positional)
- PositionalOpts.push_back(O);
- else if (O->getMiscFlags() & cl::Sink) // Remember sink options
- SinkOpts.push_back(O);
- else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) {
- if (CAOpt) {
- O->error("Cannot specify more than one option with cl::ConsumeAfter!");
- HadErrors = true;
- }
- CAOpt = O;
- }
- }
-
- if (CAOpt)
- PositionalOpts.push_back(CAOpt);
-
- // Make sure that they are in order of registration not backwards.
- std::reverse(PositionalOpts.begin(), PositionalOpts.end());
-
- // Fail hard if there were errors. These are strictly unrecoverable and
- // indicate serious issues such as conflicting option names or an incorrectly
- // linked LLVM distribution.
- if (HadErrors)
- report_fatal_error("inconsistency in registered CommandLine options");
-}
-
/// LookupOption - Lookup the option specified by the specified option on the
/// command line. If there is a value specified (after an equal sign) return
/// that as well. This assumes that leading dashes have already been stripped.
void cl::ParseCommandLineOptions(int argc, const char *const *argv,
const char *Overview) {
- // Process all registered options.
- SmallVector<Option *, 4> PositionalOpts;
- SmallVector<Option *, 4> SinkOpts;
- StringMap<Option *> Opts;
- GetOptionInfo(PositionalOpts, SinkOpts, Opts);
+ GlobalParser->ParseCommandLineOptions(argc, argv, Overview);
+}
- assert((!Opts.empty() || !PositionalOpts.empty()) && "No options specified!");
+void CommandLineParser::ParseCommandLineOptions(int argc,
+ const char *const *argv,
+ const char *Overview) {
+ assert(hasOptions() && "No options specified!");
// Expand response files.
SmallVector<const char *, 20> newArgv;
// Determine whether or not there are an unlimited number of positionals
bool HasUnlimitedPositionals = false;
- Option *ConsumeAfterOpt = nullptr;
+ if (ConsumeAfterOpt) {
+ assert(PositionalOpts.size() > 0 &&
+ "Cannot specify cl::ConsumeAfter without a positional argument!");
+ }
if (!PositionalOpts.empty()) {
- if (PositionalOpts[0]->getNumOccurrencesFlag() == cl::ConsumeAfter) {
- assert(PositionalOpts.size() > 1 &&
- "Cannot specify cl::ConsumeAfter without a positional argument!");
- ConsumeAfterOpt = PositionalOpts[0];
- }
// Calculate how many positional values are _required_.
bool UnboundedFound = false;
- for (size_t i = ConsumeAfterOpt ? 1 : 0, e = PositionalOpts.size(); i != e;
- ++i) {
+ for (size_t i = 0, e = PositionalOpts.size(); i != e; ++i) {
Option *Opt = PositionalOpts[i];
if (RequiresValue(Opt))
++NumPositionalRequired;
else if (ConsumeAfterOpt) {
// ConsumeAfter cannot be combined with "optional" positional options
// unless there is only one positional argument...
- if (PositionalOpts.size() > 2)
+ if (PositionalOpts.size() > 1)
ErrorParsing |= Opt->error(
"error - this positional option will never be matched, "
"because it does not Require a value, and a "
"another positional argument will match an "
"unbounded number of values, and this option"
" does not require a value!");
+ errs() << ProgramName << ": CommandLine Error: Option '" << Opt->ArgStr
+ << "' is all messed up!\n";
+ errs() << PositionalOpts.size();
}
UnboundedFound |= EatsUnboundedNumberOfValues(Opt);
}
StringRef Value;
StringRef ArgName = "";
- // If the option list changed, this means that some command line
- // option has just been registered or deregistered. This can occur in
- // response to things like -load, etc. If this happens, rescan the options.
- if (OptionListChanged) {
- PositionalOpts.clear();
- SinkOpts.clear();
- Opts.clear();
- GetOptionInfo(PositionalOpts, SinkOpts, Opts);
- OptionListChanged = false;
- }
-
// Check to see if this is a positional argument. This argument is
// considered to be positional if it doesn't start with '-', if it is "-"
// itself, or if we have seen "--" already.
while (!ArgName.empty() && ArgName[0] == '-')
ArgName = ArgName.substr(1);
- Handler = LookupOption(ArgName, Value, Opts);
+ Handler = LookupOption(ArgName, Value, OptionsMap);
if (!Handler || Handler->getFormattingFlag() != cl::Positional) {
ProvidePositionalOption(ActivePositionalArg, argv[i], i);
continue; // We are done!
while (!ArgName.empty() && ArgName[0] == '-')
ArgName = ArgName.substr(1);
- Handler = LookupOption(ArgName, Value, Opts);
+ Handler = LookupOption(ArgName, Value, OptionsMap);
// Check to see if this "option" is really a prefixed or grouped argument.
if (!Handler)
- Handler =
- HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, Opts);
+ Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing,
+ OptionsMap);
// Otherwise, look for the closest available option to report to the user
// in the upcoming error.
if (!Handler && SinkOpts.empty())
NearestHandler =
- LookupNearestOption(ArgName, Opts, NearestHandlerString);
+ LookupNearestOption(ArgName, OptionsMap, NearestHandlerString);
}
if (!Handler) {
// positional option and keep the rest for the consume after. The above
// loop would have assigned no values to positional options in this case.
//
- if (PositionalOpts.size() == 2 && ValNo == 0 && !PositionalVals.empty()) {
- ErrorParsing |= ProvidePositionalOption(PositionalOpts[1],
+ if (PositionalOpts.size() == 1 && ValNo == 0 && !PositionalVals.empty()) {
+ ErrorParsing |= ProvidePositionalOption(PositionalOpts[0],
PositionalVals[ValNo].first,
PositionalVals[ValNo].second);
ValNo++;
}
// Loop over args and make sure all required args are specified!
- for (const auto &Opt : Opts) {
+ for (const auto &Opt : OptionsMap) {
switch (Opt.second->getNumOccurrencesFlag()) {
case Required:
case OneOrMore:
// Free all of the memory allocated to the map. Command line options may only
// be processed once!
- Opts.clear();
- PositionalOpts.clear();
- MoreHelp->clear();
+ MoreHelp.clear();
// If we had an error processing our arguments, don't let the program execute
if (ErrorParsing)
if (ArgName.empty())
errs() << HelpStr; // Be nice for positional arguments
else
- errs() << ProgramName << ": for the -" << ArgName;
+ errs() << GlobalParser->ProgramName << ": for the -" << ArgName;
errs() << " option: " << Message << "\n";
return true;
if (Value == false)
return;
- // Get all the options.
- SmallVector<Option *, 4> PositionalOpts;
- SmallVector<Option *, 4> SinkOpts;
- StringMap<Option *> OptMap;
- GetOptionInfo(PositionalOpts, SinkOpts, OptMap);
-
StrOptionPairVector Opts;
- sortOpts(OptMap, Opts, ShowHidden);
-
- if (ProgramOverview)
- outs() << "OVERVIEW: " << ProgramOverview << "\n";
+ sortOpts(GlobalParser->OptionsMap, Opts, ShowHidden);
- outs() << "USAGE: " << ProgramName << " [options]";
+ if (GlobalParser->ProgramOverview)
+ outs() << "OVERVIEW: " << GlobalParser->ProgramOverview << "\n";
- // Print out the positional options.
- Option *CAOpt = nullptr; // The cl::ConsumeAfter option, if it exists...
- if (!PositionalOpts.empty() &&
- PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter)
- CAOpt = PositionalOpts[0];
+ outs() << "USAGE: " << GlobalParser->ProgramName << " [options]";
- for (size_t i = CAOpt != nullptr, e = PositionalOpts.size(); i != e; ++i) {
- if (PositionalOpts[i]->ArgStr[0])
- outs() << " --" << PositionalOpts[i]->ArgStr;
- outs() << " " << PositionalOpts[i]->HelpStr;
+ for (auto Opt : GlobalParser->PositionalOpts) {
+ if (Opt->ArgStr[0])
+ outs() << " --" << Opt->ArgStr;
+ outs() << " " << Opt->HelpStr;
}
// Print the consume after option info if it exists...
- if (CAOpt)
- outs() << " " << CAOpt->HelpStr;
+ if (GlobalParser->ConsumeAfterOpt)
+ outs() << " " << GlobalParser->ConsumeAfterOpt->HelpStr;
outs() << "\n\n";
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)
- outs() << *I;
- MoreHelp->clear();
+ for (auto I : GlobalParser->MoreHelp)
+ outs() << I;
+ GlobalParser->MoreHelp.clear();
// Halt the program since help information was printed
exit(0);
if (!PrintOptions && !PrintAllOptions)
return;
- // Get all the options.
- SmallVector<Option *, 4> PositionalOpts;
- SmallVector<Option *, 4> SinkOpts;
- StringMap<Option *> OptMap;
- GetOptionInfo(PositionalOpts, SinkOpts, OptMap);
-
SmallVector<std::pair<const char *, Option *>, 128> Opts;
- sortOpts(OptMap, Opts, /*ShowHidden*/ true);
+ sortOpts(GlobalParser->OptionsMap, Opts, /*ShowHidden*/ true);
// Compute the maximum argument length...
size_t MaxArgLen = 0;
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;
+StringMap<Option *> &cl::getRegisteredOptions() {
+ return GlobalParser->OptionsMap;
}
void cl::HideUnrelatedOptions(cl::OptionCategory &Category) {
- StringMap<cl::Option *> Options;
- cl::getRegisteredOptions(Options);
- for (auto &I : Options) {
+ for (auto &I : GlobalParser->OptionsMap) {
if (I.second->Category != &Category &&
I.second->Category != &GenericCategory)
I.second->setHiddenFlag(cl::ReallyHidden);
void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories) {
auto CategoriesBegin = Categories.begin();
auto CategoriesEnd = Categories.end();
- StringMap<cl::Option *> Options;
- cl::getRegisteredOptions(Options);
- for (auto &I : Options) {
+ for (auto &I : GlobalParser->OptionsMap) {
if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) ==
CategoriesEnd &&
I.second->Category != &GenericCategory)