//===-- CommandLine.cpp - Command line parser implementation --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This class implements a command line argument processor that is useful when // creating a tool. It provides a simple, minimalistic interface that is easily // extensible and supports nonlocal (library) command line options. // // Note that rather than trying to figure out what this code does, you could try // reading the library documentation located in docs/CommandLine.html // //===----------------------------------------------------------------------===// #include "llvm/Support/CommandLine.h" #include "llvm-c/Support.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace llvm; using namespace cl; #define DEBUG_TYPE "commandline" //===----------------------------------------------------------------------===// // Template instantiations and anchors. // namespace llvm { namespace cl { template class basic_parser; template class basic_parser; template class basic_parser; template class basic_parser; template class basic_parser; template class basic_parser; template class basic_parser; template class basic_parser; template class basic_parser; template class basic_parser; template class opt; template class opt; template class opt; template class opt; template class opt; } } // end namespace llvm::cl // Pin the vtables to this file. void GenericOptionValue::anchor() {} void OptionValue::anchor() {} void OptionValue::anchor() {} void Option::anchor() {} void basic_parser_impl::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} //===----------------------------------------------------------------------===// static StringRef ArgPrefix = " -"; static StringRef ArgPrefixLong = " --"; static StringRef ArgHelpPrefix = " - "; static size_t argPlusPrefixesSize(StringRef ArgName) { size_t Len = ArgName.size(); if (Len == 1) return Len + ArgPrefix.size() + ArgHelpPrefix.size(); return Len + ArgPrefixLong.size() + ArgHelpPrefix.size(); } static StringRef argPrefix(StringRef ArgName) { if (ArgName.size() == 1) return ArgPrefix; return ArgPrefixLong; } // Option predicates... static inline bool isGrouping(const Option *O) { return O->getMiscFlags() & cl::Grouping; } static inline bool isPrefixedOrGrouping(const Option *O) { return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || O->getFormattingFlag() == cl::AlwaysPrefix; } namespace { class PrintArg { StringRef ArgName; public: PrintArg(StringRef ArgName) : ArgName(ArgName) {} friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg&); }; raw_ostream &operator<<(raw_ostream &OS, const PrintArg& Arg) { OS << argPrefix(Arg.ArgName) << Arg.ArgName; return OS; } class CommandLineParser { public: // Globals for name and overview of program. Program name is not a string to // avoid static ctor/dtor issues. std::string ProgramName; StringRef ProgramOverview; // This collects additional help to be printed. std::vector MoreHelp; // This collects Options added with the cl::DefaultOption flag. Since they can // be overridden, they are not added to the appropriate SubCommands until // ParseCommandLineOptions actually runs. SmallVector, 4> DefaultOptions; // This collects the different option categories that have been registered. SmallPtrSet RegisteredOptionCategories; // This collects the different subcommands that have been registered. SmallPtrSet RegisteredSubCommands; CommandLineParser() : ActiveSubCommand(nullptr) { RegisteredOptionCategories.insert(&*GeneralCategory); registerSubCommand(&*TopLevelSubCommand); registerSubCommand(&*AllSubCommands); } void ResetAllOptionOccurrences(); bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs = nullptr, bool LongOptionsUseDoubleDash = false); void addLiteralOption(Option &Opt, SubCommand *SC, StringRef Name) { if (Opt.hasArgStr()) return; if (!SC->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"); } // If we're adding this to all sub-commands, add it to the ones that have // already been registered. if (SC == &*AllSubCommands) { for (const auto &Sub : RegisteredSubCommands) { if (SC == Sub) continue; addLiteralOption(Opt, Sub, Name); } } } void addLiteralOption(Option &Opt, StringRef Name) { for(SubCommand *SC: Opt.getSubCommands()) addLiteralOption(Opt, SC, Name); } void addOption(Option *O, SubCommand *SC, bool ProcessDefaultOptions = false) { if (!ProcessDefaultOptions && O->isDefaultOption()) { DefaultOptions.push_back(std::make_pair(O, SC)); return; } bool HadErrors = false; if (O->hasArgStr()) { // If it's a DefaultOption, check to make sure it isn't already there. if (O->isDefaultOption() && SC->OptionsMap.find(O->ArgStr) != SC->OptionsMap.end()) return; // Add argument to the argument map! if (!SC->OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) { errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr << "' registered more than once!\n"; HadErrors = true; } } // Remember information about positional options. if (O->getFormattingFlag() == cl::Positional) SC->PositionalOpts.push_back(O); else if (O->getMiscFlags() & cl::Sink) // Remember sink options SC->SinkOpts.push_back(O); else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { if (SC->ConsumeAfterOpt) { O->error("Cannot specify more than one option with cl::ConsumeAfter!"); HadErrors = true; } SC->ConsumeAfterOpt = O; } // 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"); // If we're adding this to all sub-commands, add it to the ones that have // already been registered. if (SC == &*AllSubCommands) { for (const auto &Sub : RegisteredSubCommands) { if (SC == Sub) continue; addOption(O, Sub, ProcessDefaultOptions); } } } void addDefaultOptions() { for (std::pair