diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /llvm/lib/Support/CommandLine.cpp | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) |
Diffstat (limited to 'llvm/lib/Support/CommandLine.cpp')
-rw-r--r-- | llvm/lib/Support/CommandLine.cpp | 386 |
1 files changed, 226 insertions, 160 deletions
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 5e7d63165130..66632504d6fb 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -21,14 +21,12 @@ #include "llvm-c/Support.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" #include "llvm/Support/ConvertUTF.h" @@ -36,7 +34,6 @@ #include "llvm/Support/Error.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" @@ -45,6 +42,7 @@ #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> +#include <optional> #include <string> using namespace llvm; using namespace cl; @@ -167,8 +165,8 @@ public: SmallPtrSet<SubCommand *, 4> RegisteredSubCommands; CommandLineParser() { - registerSubCommand(&*TopLevelSubCommand); - registerSubCommand(&*AllSubCommands); + registerSubCommand(&SubCommand::getTopLevel()); + registerSubCommand(&SubCommand::getAll()); } void ResetAllOptionOccurrences(); @@ -188,7 +186,7 @@ public: // If we're adding this to all sub-commands, add it to the ones that have // already been registered. - if (SC == &*AllSubCommands) { + if (SC == &SubCommand::getAll()) { for (auto *Sub : RegisteredSubCommands) { if (SC == Sub) continue; @@ -199,7 +197,7 @@ public: void addLiteralOption(Option &Opt, StringRef Name) { if (Opt.Subs.empty()) - addLiteralOption(Opt, &*TopLevelSubCommand, Name); + addLiteralOption(Opt, &SubCommand::getTopLevel(), Name); else { for (auto *SC : Opt.Subs) addLiteralOption(Opt, SC, Name); @@ -244,7 +242,7 @@ public: // If we're adding this to all sub-commands, add it to the ones that have // already been registered. - if (SC == &*AllSubCommands) { + if (SC == &SubCommand::getAll()) { for (auto *Sub : RegisteredSubCommands) { if (SC == Sub) continue; @@ -260,7 +258,7 @@ public: } if (O->Subs.empty()) { - addOption(O, &*TopLevelSubCommand); + addOption(O, &SubCommand::getTopLevel()); } else { for (auto *SC : O->Subs) addOption(O, SC); @@ -302,7 +300,7 @@ public: void removeOption(Option *O) { if (O->Subs.empty()) - removeOption(O, &*TopLevelSubCommand); + removeOption(O, &SubCommand::getTopLevel()); else { if (O->isInAllSubCommands()) { for (auto *SC : RegisteredSubCommands) @@ -341,7 +339,7 @@ public: void updateArgStr(Option *O, StringRef NewName) { if (O->Subs.empty()) - updateArgStr(O, NewName, &*TopLevelSubCommand); + updateArgStr(O, NewName, &SubCommand::getTopLevel()); else { if (O->isInAllSubCommands()) { for (auto *SC : RegisteredSubCommands) @@ -376,8 +374,8 @@ public: // For all options that have been registered for all subcommands, add the // option to this subcommand now. - if (sub != &*AllSubCommands) { - for (auto &E : AllSubCommands->OptionsMap) { + if (sub != &SubCommand::getAll()) { + for (auto &E : SubCommand::getAll().OptionsMap) { Option *O = E.second; if ((O->isPositional() || O->isSink() || O->isConsumeAfter()) || O->hasArgStr()) @@ -409,10 +407,10 @@ public: ResetAllOptionOccurrences(); RegisteredSubCommands.clear(); - TopLevelSubCommand->reset(); - AllSubCommands->reset(); - registerSubCommand(&*TopLevelSubCommand); - registerSubCommand(&*AllSubCommands); + SubCommand::getTopLevel().reset(); + SubCommand::getAll().reset(); + registerSubCommand(&SubCommand::getTopLevel()); + registerSubCommand(&SubCommand::getAll()); DefaultOptions.clear(); } @@ -491,6 +489,10 @@ ManagedStatic<SubCommand> llvm::cl::TopLevelSubCommand; // A special subcommand that can be used to put an option into all subcommands. ManagedStatic<SubCommand> llvm::cl::AllSubCommands; +SubCommand &SubCommand::getTopLevel() { return *TopLevelSubCommand; } + +SubCommand &SubCommand::getAll() { return *AllSubCommands; } + void SubCommand::registerSubCommand() { GlobalParser->registerSubCommand(this); } @@ -523,7 +525,7 @@ Option *CommandLineParser::LookupOption(SubCommand &Sub, StringRef &Arg, // Reject all dashes. if (Arg.empty()) return nullptr; - assert(&Sub != &*AllSubCommands); + assert(&Sub != &SubCommand::getAll()); size_t EqualPos = Arg.find('='); @@ -551,9 +553,9 @@ Option *CommandLineParser::LookupOption(SubCommand &Sub, StringRef &Arg, SubCommand *CommandLineParser::LookupSubCommand(StringRef Name) { if (Name.empty()) - return &*TopLevelSubCommand; + return &SubCommand::getTopLevel(); for (auto *S : RegisteredSubCommands) { - if (S == &*AllSubCommands) + if (S == &SubCommand::getAll()) continue; if (S->getName().empty()) continue; @@ -561,7 +563,7 @@ SubCommand *CommandLineParser::LookupSubCommand(StringRef Name) { if (StringRef(S->getName()) == StringRef(Name)) return S; } - return &*TopLevelSubCommand; + return &SubCommand::getTopLevel(); } /// LookupNearestOption - Lookup the closest match to the option specified by @@ -1149,17 +1151,16 @@ static void ExpandBasePaths(StringRef BasePath, StringSaver &Saver, } // FName must be an absolute path. -static llvm::Error ExpandResponseFile(StringRef FName, StringSaver &Saver, - TokenizerCallback Tokenizer, - SmallVectorImpl<const char *> &NewArgv, - bool MarkEOLs, bool RelativeNames, - bool ExpandBasePath, - llvm::vfs::FileSystem &FS) { +Error ExpansionContext::expandResponseFile( + StringRef FName, SmallVectorImpl<const char *> &NewArgv) { assert(sys::path::is_absolute(FName)); llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr = - FS.getBufferForFile(FName); - if (!MemBufOrErr) - return llvm::errorCodeToError(MemBufOrErr.getError()); + FS->getBufferForFile(FName); + if (!MemBufOrErr) { + std::error_code EC = MemBufOrErr.getError(); + return llvm::createStringError(EC, Twine("cannot not open file '") + FName + + "': " + EC.message()); + } MemoryBuffer &MemBuf = *MemBufOrErr.get(); StringRef Str(MemBuf.getBufferStart(), MemBuf.getBufferSize()); @@ -1181,33 +1182,51 @@ static llvm::Error ExpandResponseFile(StringRef FName, StringSaver &Saver, // Tokenize the contents into NewArgv. Tokenizer(Str, Saver, NewArgv, MarkEOLs); - if (!RelativeNames) + // Expanded file content may require additional transformations, like using + // absolute paths instead of relative in '@file' constructs or expanding + // macros. + if (!RelativeNames && !InConfigFile) return Error::success(); - llvm::StringRef BasePath = llvm::sys::path::parent_path(FName); - // If names of nested response files should be resolved relative to including - // file, replace the included response file names with their full paths - // obtained by required resolution. - for (auto &Arg : NewArgv) { + + StringRef BasePath = llvm::sys::path::parent_path(FName); + for (const char *&Arg : NewArgv) { if (!Arg) continue; // Substitute <CFGDIR> with the file's base path. - if (ExpandBasePath) + if (InConfigFile) ExpandBasePaths(BasePath, Saver, Arg); - // Skip non-rsp file arguments. - if (Arg[0] != '@') - continue; - - StringRef FileName(Arg + 1); - // Skip if non-relative. - if (!llvm::sys::path::is_relative(FileName)) + // Discover the case, when argument should be transformed into '@file' and + // evaluate 'file' for it. + StringRef ArgStr(Arg); + StringRef FileName; + bool ConfigInclusion = false; + if (ArgStr.consume_front("@")) { + FileName = ArgStr; + if (!llvm::sys::path::is_relative(FileName)) + continue; + } else if (ArgStr.consume_front("--config=")) { + FileName = ArgStr; + ConfigInclusion = true; + } else { continue; + } + // Update expansion construct. SmallString<128> ResponseFile; ResponseFile.push_back('@'); - ResponseFile.append(BasePath); - llvm::sys::path::append(ResponseFile, FileName); + if (ConfigInclusion && !llvm::sys::path::has_parent_path(FileName)) { + SmallString<128> FilePath; + if (!findConfigFile(FileName, FilePath)) + return createStringError( + std::make_error_code(std::errc::no_such_file_or_directory), + "cannot not find configuration file: " + FileName); + ResponseFile.append(FilePath); + } else { + ResponseFile.append(BasePath); + llvm::sys::path::append(ResponseFile, FileName); + } Arg = Saver.save(ResponseFile.str()).data(); } return Error::success(); @@ -1215,12 +1234,8 @@ static llvm::Error ExpandResponseFile(StringRef FName, StringSaver &Saver, /// Expand response files on a command line recursively using the given /// StringSaver and tokenization strategy. -bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, - SmallVectorImpl<const char *> &Argv, bool MarkEOLs, - bool RelativeNames, bool ExpandBasePath, - llvm::Optional<llvm::StringRef> CurrentDir, - llvm::vfs::FileSystem &FS) { - bool AllExpanded = true; +Error ExpansionContext::expandResponseFiles( + SmallVectorImpl<const char *> &Argv) { struct ResponseFileRecord { std::string File; size_t End; @@ -1260,52 +1275,63 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, // always have an absolute path deduced from the containing file. SmallString<128> CurrDir; if (llvm::sys::path::is_relative(FName)) { - if (!CurrentDir) - llvm::sys::fs::current_path(CurrDir); - else - CurrDir = *CurrentDir; + if (CurrentDir.empty()) { + if (auto CWD = FS->getCurrentWorkingDirectory()) { + CurrDir = *CWD; + } else { + return createStringError( + CWD.getError(), Twine("cannot get absolute path for: ") + FName); + } + } else { + CurrDir = CurrentDir; + } llvm::sys::path::append(CurrDir, FName); FName = CurrDir.c_str(); } - auto IsEquivalent = [FName, &FS](const ResponseFileRecord &RFile) { - llvm::ErrorOr<llvm::vfs::Status> LHS = FS.status(FName); - if (!LHS) { - // TODO: The error should be propagated up the stack. - llvm::consumeError(llvm::errorCodeToError(LHS.getError())); - return false; - } - llvm::ErrorOr<llvm::vfs::Status> RHS = FS.status(RFile.File); - if (!RHS) { - // TODO: The error should be propagated up the stack. - llvm::consumeError(llvm::errorCodeToError(RHS.getError())); - return false; + + ErrorOr<llvm::vfs::Status> Res = FS->status(FName); + if (!Res || !Res->exists()) { + std::error_code EC = Res.getError(); + if (!InConfigFile) { + // If the specified file does not exist, leave '@file' unexpanded, as + // libiberty does. + if (!EC || EC == llvm::errc::no_such_file_or_directory) { + ++I; + continue; + } } - return LHS->equivalent(*RHS); + if (!EC) + EC = llvm::errc::no_such_file_or_directory; + return createStringError(EC, Twine("cannot not open file '") + FName + + "': " + EC.message()); + } + const llvm::vfs::Status &FileStatus = Res.get(); + + auto IsEquivalent = + [FileStatus, this](const ResponseFileRecord &RFile) -> ErrorOr<bool> { + ErrorOr<llvm::vfs::Status> RHS = FS->status(RFile.File); + if (!RHS) + return RHS.getError(); + return FileStatus.equivalent(*RHS); }; // Check for recursive response files. - if (any_of(drop_begin(FileStack), IsEquivalent)) { - // This file is recursive, so we leave it in the argument stream and - // move on. - AllExpanded = false; - ++I; - continue; + for (const auto &F : drop_begin(FileStack)) { + if (ErrorOr<bool> R = IsEquivalent(F)) { + if (R.get()) + return createStringError( + R.getError(), Twine("recursive expansion of: '") + F.File + "'"); + } else { + return createStringError(R.getError(), + Twine("cannot open file: ") + F.File); + } } // Replace this response file argument with the tokenization of its // contents. Nested response files are expanded in subsequent iterations. SmallVector<const char *, 0> ExpandedArgv; - if (llvm::Error Err = - ExpandResponseFile(FName, Saver, Tokenizer, ExpandedArgv, MarkEOLs, - RelativeNames, ExpandBasePath, FS)) { - // We couldn't read this file, so we leave it in the argument stream and - // move on. - // TODO: The error should be propagated up the stack. - llvm::consumeError(std::move(Err)); - AllExpanded = false; - ++I; - continue; - } + if (Error Err = expandResponseFile(FName, ExpandedArgv)) + return Err; for (ResponseFileRecord &Record : FileStack) { // Increase the end of all active records by the number of newly expanded @@ -1324,53 +1350,97 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, // don't have a chance to pop the stack when encountering recursive files at // the end of the stream, so seeing that doesn't indicate a bug. assert(FileStack.size() > 0 && Argv.size() == FileStack.back().End); - return AllExpanded; -} - -bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, - SmallVectorImpl<const char *> &Argv, bool MarkEOLs, - bool RelativeNames, bool ExpandBasePath, - llvm::Optional<StringRef> CurrentDir) { - return ExpandResponseFiles(Saver, std::move(Tokenizer), Argv, MarkEOLs, - RelativeNames, ExpandBasePath, - std::move(CurrentDir), *vfs::getRealFileSystem()); + return Error::success(); } bool cl::expandResponseFiles(int Argc, const char *const *Argv, const char *EnvVar, StringSaver &Saver, SmallVectorImpl<const char *> &NewArgv) { - auto Tokenize = Triple(sys::getProcessTriple()).isOSWindows() - ? cl::TokenizeWindowsCommandLine - : cl::TokenizeGNUCommandLine; +#ifdef _WIN32 + auto Tokenize = cl::TokenizeWindowsCommandLine; +#else + auto Tokenize = cl::TokenizeGNUCommandLine; +#endif // The environment variable specifies initial options. if (EnvVar) - if (llvm::Optional<std::string> EnvValue = sys::Process::GetEnv(EnvVar)) + if (std::optional<std::string> EnvValue = sys::Process::GetEnv(EnvVar)) Tokenize(*EnvValue, Saver, NewArgv, /*MarkEOLs=*/false); // Command line options can override the environment variable. NewArgv.append(Argv + 1, Argv + Argc); - return ExpandResponseFiles(Saver, Tokenize, NewArgv); + ExpansionContext ECtx(Saver.getAllocator(), Tokenize); + if (Error Err = ECtx.expandResponseFiles(NewArgv)) { + errs() << toString(std::move(Err)) << '\n'; + return false; + } + return true; +} + +bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, + SmallVectorImpl<const char *> &Argv) { + ExpansionContext ECtx(Saver.getAllocator(), Tokenizer); + if (Error Err = ECtx.expandResponseFiles(Argv)) { + errs() << toString(std::move(Err)) << '\n'; + return false; + } + return true; } -bool cl::readConfigFile(StringRef CfgFile, StringSaver &Saver, - SmallVectorImpl<const char *> &Argv) { +ExpansionContext::ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T) + : Saver(A), Tokenizer(T), FS(vfs::getRealFileSystem().get()) {} + +bool ExpansionContext::findConfigFile(StringRef FileName, + SmallVectorImpl<char> &FilePath) { + SmallString<128> CfgFilePath; + const auto FileExists = [this](SmallString<128> Path) -> bool { + auto Status = FS->status(Path); + return Status && + Status->getType() == llvm::sys::fs::file_type::regular_file; + }; + + // If file name contains directory separator, treat it as a path to + // configuration file. + if (llvm::sys::path::has_parent_path(FileName)) { + CfgFilePath = FileName; + if (llvm::sys::path::is_relative(FileName) && FS->makeAbsolute(CfgFilePath)) + return false; + if (!FileExists(CfgFilePath)) + return false; + FilePath.assign(CfgFilePath.begin(), CfgFilePath.end()); + return true; + } + + // Look for the file in search directories. + for (const StringRef &Dir : SearchDirs) { + if (Dir.empty()) + continue; + CfgFilePath.assign(Dir); + llvm::sys::path::append(CfgFilePath, FileName); + llvm::sys::path::native(CfgFilePath); + if (FileExists(CfgFilePath)) { + FilePath.assign(CfgFilePath.begin(), CfgFilePath.end()); + return true; + } + } + + return false; +} + +Error ExpansionContext::readConfigFile(StringRef CfgFile, + SmallVectorImpl<const char *> &Argv) { SmallString<128> AbsPath; if (sys::path::is_relative(CfgFile)) { - llvm::sys::fs::current_path(AbsPath); - llvm::sys::path::append(AbsPath, CfgFile); + AbsPath.assign(CfgFile); + if (std::error_code EC = FS->makeAbsolute(AbsPath)) + return make_error<StringError>( + EC, Twine("cannot get absolute path for " + CfgFile)); CfgFile = AbsPath.str(); } - if (llvm::Error Err = ExpandResponseFile( - CfgFile, Saver, cl::tokenizeConfigFile, Argv, - /*MarkEOLs=*/false, /*RelativeNames=*/true, /*ExpandBasePath=*/true, - *llvm::vfs::getRealFileSystem())) { - // TODO: The error should be propagated up the stack. - llvm::consumeError(std::move(Err)); - return false; - } - return ExpandResponseFiles(Saver, cl::tokenizeConfigFile, Argv, - /*MarkEOLs=*/false, /*RelativeNames=*/true, - /*ExpandBasePath=*/true, llvm::None); + InConfigFile = true; + RelativeNames = true; + if (Error Err = expandResponseFile(CfgFile, Argv)) + return Err; + return expandResponseFiles(Argv); } static void initCommonOptions(); @@ -1386,7 +1456,7 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv, // Parse options from environment variable. if (EnvVar) { - if (llvm::Optional<std::string> EnvValue = + if (std::optional<std::string> EnvValue = sys::Process::GetEnv(StringRef(EnvVar))) TokenizeGNUCommandLine(*EnvValue, Saver, NewArgv); } @@ -1425,26 +1495,31 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, bool LongOptionsUseDoubleDash) { assert(hasOptions() && "No options specified!"); + ProgramOverview = Overview; + bool IgnoreErrors = Errs; + if (!Errs) + Errs = &errs(); + bool ErrorParsing = false; + // Expand response files. SmallVector<const char *, 20> newArgv(argv, argv + argc); BumpPtrAllocator A; - StringSaver Saver(A); - ExpandResponseFiles(Saver, - Triple(sys::getProcessTriple()).isOSWindows() ? - cl::TokenizeWindowsCommandLine : cl::TokenizeGNUCommandLine, - newArgv); +#ifdef _WIN32 + auto Tokenize = cl::TokenizeWindowsCommandLine; +#else + auto Tokenize = cl::TokenizeGNUCommandLine; +#endif + ExpansionContext ECtx(A, Tokenize); + if (Error Err = ECtx.expandResponseFiles(newArgv)) { + *Errs << toString(std::move(Err)) << '\n'; + return false; + } argv = &newArgv[0]; argc = static_cast<int>(newArgv.size()); // Copy the program name into ProgName, making sure not to overflow it. ProgramName = std::string(sys::path::filename(StringRef(argv[0]))); - ProgramOverview = Overview; - bool IgnoreErrors = Errs; - if (!Errs) - Errs = &errs(); - bool ErrorParsing = false; - // Check out the positional arguments to collect information about them. unsigned NumPositionalRequired = 0; @@ -1452,12 +1527,12 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, bool HasUnlimitedPositionals = false; int FirstArg = 1; - SubCommand *ChosenSubCommand = &*TopLevelSubCommand; + SubCommand *ChosenSubCommand = &SubCommand::getTopLevel(); if (argc >= 2 && argv[FirstArg][0] != '-') { // If the first argument specifies a valid subcommand, start processing // options from the second argument. ChosenSubCommand = LookupSubCommand(StringRef(argv[FirstArg])); - if (ChosenSubCommand != &*TopLevelSubCommand) + if (ChosenSubCommand != &SubCommand::getTopLevel()) FirstArg = 2; } GlobalParser->ActiveSubCommand = ChosenSubCommand; @@ -1675,7 +1750,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, switch (PositionalOpts[i]->getNumOccurrencesFlag()) { case cl::Optional: Done = true; // Optional arguments want _at most_ one value - LLVM_FALLTHROUGH; + [[fallthrough]]; case cl::ZeroOrMore: // Zero or more will take all they can get... case cl::OneOrMore: // One or more will take all they can get... ProvidePositionalOption(PositionalOpts[i], @@ -1729,7 +1804,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, Opt.second->error("must be specified at least once!"); ErrorParsing = true; } - LLVM_FALLTHROUGH; + [[fallthrough]]; default: break; } @@ -2289,7 +2364,7 @@ public: if (!GlobalParser->ProgramOverview.empty()) outs() << "OVERVIEW: " << GlobalParser->ProgramOverview << "\n"; - if (Sub == &*TopLevelSubCommand) { + if (Sub == &SubCommand::getTopLevel()) { outs() << "USAGE: " << GlobalParser->ProgramName; if (Subs.size() > 2) outs() << " [subcommand]"; @@ -2313,7 +2388,7 @@ public: if (ConsumeAfterOpt) outs() << " " << ConsumeAfterOpt->HelpStr; - if (Sub == &*TopLevelSubCommand && !Subs.empty()) { + if (Sub == &SubCommand::getTopLevel() && !Subs.empty()) { // Compute the maximum subcommand length... size_t MaxSubLen = 0; for (size_t i = 0, e = Subs.size(); i != e; ++i) @@ -2463,7 +2538,7 @@ public: namespace { class VersionPrinter { public: - void print() { + void print(std::vector<VersionPrinterTy> ExtraPrinters = {}) { raw_ostream &OS = outs(); #ifdef PACKAGE_VENDOR OS << PACKAGE_VENDOR << " "; @@ -2479,15 +2554,14 @@ public: #ifndef NDEBUG OS << " with assertions"; #endif -#if LLVM_VERSION_PRINTER_SHOW_HOST_TARGET_INFO - std::string CPU = std::string(sys::getHostCPUName()); - if (CPU == "generic") - CPU = "(unknown)"; - OS << ".\n" - << " Default target: " << sys::getDefaultTargetTriple() << '\n' - << " Host CPU: " << CPU; -#endif - OS << '\n'; + OS << ".\n"; + + // Iterate over any registered extra printers and call them to add further + // information. + if (!ExtraPrinters.empty()) { + for (const auto &I : ExtraPrinters) + I(outs()); + } } void operator=(bool OptionWasSpecified); }; @@ -2519,7 +2593,7 @@ struct CommandLineCommonOptions { cl::Hidden, cl::ValueDisallowed, cl::cat(GenericCategory), - cl::sub(*AllSubCommands)}; + cl::sub(SubCommand::getAll())}; cl::opt<HelpPrinter, true, parser<bool>> HLHOp{ "help-list-hidden", @@ -2528,7 +2602,7 @@ struct CommandLineCommonOptions { cl::Hidden, cl::ValueDisallowed, cl::cat(GenericCategory), - cl::sub(*AllSubCommands)}; + cl::sub(SubCommand::getAll())}; // Define uncategorized/categorized help printers. These printers change their // behaviour at runtime depending on whether one or more Option categories @@ -2539,7 +2613,7 @@ struct CommandLineCommonOptions { cl::location(WrappedNormalPrinter), cl::ValueDisallowed, cl::cat(GenericCategory), - cl::sub(*AllSubCommands)}; + cl::sub(SubCommand::getAll())}; cl::alias HOpA{"h", cl::desc("Alias for --help"), cl::aliasopt(HOp), cl::DefaultOption}; @@ -2551,7 +2625,7 @@ struct CommandLineCommonOptions { cl::Hidden, cl::ValueDisallowed, cl::cat(GenericCategory), - cl::sub(*AllSubCommands)}; + cl::sub(SubCommand::getAll())}; cl::opt<bool> PrintOptions{ "print-options", @@ -2559,7 +2633,7 @@ struct CommandLineCommonOptions { cl::Hidden, cl::init(false), cl::cat(GenericCategory), - cl::sub(*AllSubCommands)}; + cl::sub(SubCommand::getAll())}; cl::opt<bool> PrintAllOptions{ "print-all-options", @@ -2567,7 +2641,7 @@ struct CommandLineCommonOptions { cl::Hidden, cl::init(false), cl::cat(GenericCategory), - cl::sub(*AllSubCommands)}; + cl::sub(SubCommand::getAll())}; VersionPrinterTy OverrideVersionPrinter = nullptr; @@ -2614,15 +2688,7 @@ void VersionPrinter::operator=(bool OptionWasSpecified) { CommonOptions->OverrideVersionPrinter(outs()); exit(0); } - print(); - - // Iterate over any registered extra printers and call them to add further - // information. - if (!CommonOptions->ExtraVersionPrinters.empty()) { - outs() << '\n'; - for (const auto &I : CommonOptions->ExtraVersionPrinters) - I(outs()); - } + print(CommonOptions->ExtraVersionPrinters); exit(0); } @@ -2677,7 +2743,7 @@ void cl::PrintHelpMessage(bool Hidden, bool Categorized) { /// Utility function for printing version number. void cl::PrintVersionMessage() { - CommonOptions->VersionPrinterInstance.print(); + CommonOptions->VersionPrinterInstance.print(CommonOptions->ExtraVersionPrinters); } void cl::SetVersionPrinter(VersionPrinterTy func) { |