diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /llvm/lib/Support/CommandLine.cpp | |
parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) |
Notes
Diffstat (limited to 'llvm/lib/Support/CommandLine.cpp')
-rw-r--r-- | llvm/lib/Support/CommandLine.cpp | 209 |
1 files changed, 152 insertions, 57 deletions
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 620f7ffd4c9f..cb73380ba383 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -24,11 +24,13 @@ #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" #include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -37,9 +39,11 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/StringSaver.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> #include <map> +#include <string> using namespace llvm; using namespace cl; @@ -53,6 +57,8 @@ namespace cl { template class basic_parser<bool>; template class basic_parser<boolOrDefault>; template class basic_parser<int>; +template class basic_parser<long>; +template class basic_parser<long long>; template class basic_parser<unsigned>; template class basic_parser<unsigned long>; template class basic_parser<unsigned long long>; @@ -78,6 +84,8 @@ void basic_parser_impl::anchor() {} void parser<bool>::anchor() {} void parser<boolOrDefault>::anchor() {} void parser<int>::anchor() {} +void parser<long>::anchor() {} +void parser<long long>::anchor() {} void parser<unsigned>::anchor() {} void parser<unsigned long>::anchor() {} void parser<unsigned long long>::anchor() {} @@ -88,21 +96,26 @@ void parser<char>::anchor() {} //===----------------------------------------------------------------------===// -static StringRef ArgPrefix = " -"; -static StringRef ArgPrefixLong = " --"; +const static size_t DefaultPad = 2; + +static StringRef ArgPrefix = "-"; +static StringRef ArgPrefixLong = "--"; static StringRef ArgHelpPrefix = " - "; -static size_t argPlusPrefixesSize(StringRef ArgName) { +static size_t argPlusPrefixesSize(StringRef ArgName, size_t Pad = DefaultPad) { size_t Len = ArgName.size(); if (Len == 1) - return Len + ArgPrefix.size() + ArgHelpPrefix.size(); - return Len + ArgPrefixLong.size() + ArgHelpPrefix.size(); + return Len + Pad + ArgPrefix.size() + ArgHelpPrefix.size(); + return Len + Pad + ArgPrefixLong.size() + ArgHelpPrefix.size(); } -static StringRef argPrefix(StringRef ArgName) { - if (ArgName.size() == 1) - return ArgPrefix; - return ArgPrefixLong; +static SmallString<8> argPrefix(StringRef ArgName, size_t Pad = DefaultPad) { + SmallString<8> Prefix; + for (size_t I = 0; I < Pad; ++I) { + Prefix.push_back(' '); + } + Prefix.append(ArgName.size() > 1 ? ArgPrefixLong : ArgPrefix); + return Prefix; } // Option predicates... @@ -119,13 +132,14 @@ namespace { class PrintArg { StringRef ArgName; + size_t Pad; public: - PrintArg(StringRef ArgName) : ArgName(ArgName) {} - friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg&); + PrintArg(StringRef ArgName, size_t Pad = DefaultPad) : ArgName(ArgName), Pad(Pad) {} + friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg &); }; raw_ostream &operator<<(raw_ostream &OS, const PrintArg& Arg) { - OS << argPrefix(Arg.ArgName) << Arg.ArgName; + OS << argPrefix(Arg.ArgName, Arg.Pad) << Arg.ArgName; return OS; } @@ -173,7 +187,7 @@ public: // 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) { + for (auto *Sub : RegisteredSubCommands) { if (SC == Sub) continue; addLiteralOption(Opt, Sub, Name); @@ -229,7 +243,7 @@ public: // 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) { + for (auto *Sub : RegisteredSubCommands) { if (SC == Sub) continue; addOption(O, Sub); @@ -304,7 +318,7 @@ public: } bool hasOptions() const { - for (const auto &S : RegisteredSubCommands) { + for (const auto *S : RegisteredSubCommands) { if (hasOptions(*S)) return true; } @@ -1037,14 +1051,16 @@ static bool hasUTF8ByteOrderMark(ArrayRef<char> S) { return (S.size() >= 3 && S[0] == '\xef' && S[1] == '\xbb' && S[2] == '\xbf'); } -static bool ExpandResponseFile(StringRef FName, StringSaver &Saver, - TokenizerCallback Tokenizer, - SmallVectorImpl<const char *> &NewArgv, - bool MarkEOLs, bool RelativeNames) { - ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr = - MemoryBuffer::getFile(FName); +// FName must be an absolute path. +static llvm::Error ExpandResponseFile( + StringRef FName, StringSaver &Saver, TokenizerCallback Tokenizer, + SmallVectorImpl<const char *> &NewArgv, bool MarkEOLs, bool RelativeNames, + llvm::vfs::FileSystem &FS) { + assert(sys::path::is_absolute(FName)); + llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr = + FS.getBufferForFile(FName); if (!MemBufOrErr) - return false; + return llvm::errorCodeToError(MemBufOrErr.getError()); MemoryBuffer &MemBuf = *MemBufOrErr.get(); StringRef Str(MemBuf.getBufferStart(), MemBuf.getBufferSize()); @@ -1053,7 +1069,8 @@ static bool ExpandResponseFile(StringRef FName, StringSaver &Saver, std::string UTF8Buf; if (hasUTF16ByteOrderMark(BufRef)) { if (!convertUTF16ToUTF8String(BufRef, UTF8Buf)) - return false; + return llvm::createStringError(std::errc::illegal_byte_sequence, + "Could not convert UTF16 to UTF8"); Str = StringRef(UTF8Buf); } // If we see UTF-8 BOM sequence at the beginning of a file, we shall remove @@ -1065,41 +1082,40 @@ static bool ExpandResponseFile(StringRef FName, StringSaver &Saver, // Tokenize the contents into NewArgv. Tokenizer(Str, Saver, NewArgv, MarkEOLs); + if (!RelativeNames) + 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. - if (RelativeNames) - for (unsigned I = 0; I < NewArgv.size(); ++I) - if (NewArgv[I]) { - StringRef Arg = NewArgv[I]; - if (Arg.front() == '@') { - StringRef FileName = Arg.drop_front(); - if (llvm::sys::path::is_relative(FileName)) { - SmallString<128> ResponseFile; - ResponseFile.append(1, '@'); - if (llvm::sys::path::is_relative(FName)) { - SmallString<128> curr_dir; - llvm::sys::fs::current_path(curr_dir); - ResponseFile.append(curr_dir.str()); - } - llvm::sys::path::append( - ResponseFile, llvm::sys::path::parent_path(FName), FileName); - NewArgv[I] = Saver.save(ResponseFile.c_str()).data(); - } - } - } + for (auto &Arg : NewArgv) { + // Skip non-rsp file arguments. + if (!Arg || Arg[0] != '@') + continue; - return true; + StringRef FileName(Arg + 1); + // Skip if non-relative. + if (!llvm::sys::path::is_relative(FileName)) + continue; + + SmallString<128> ResponseFile; + ResponseFile.push_back('@'); + ResponseFile.append(BasePath); + llvm::sys::path::append(ResponseFile, FileName); + Arg = Saver.save(ResponseFile.c_str()).data(); + } + return Error::success(); } /// 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) { + SmallVectorImpl<const char *> &Argv, bool MarkEOLs, + bool RelativeNames, llvm::vfs::FileSystem &FS, + llvm::Optional<llvm::StringRef> CurrentDir) { bool AllExpanded = true; struct ResponseFileRecord { - const char *File; + std::string File; size_t End; }; @@ -1133,8 +1149,31 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, } const char *FName = Arg + 1; - auto IsEquivalent = [FName](const ResponseFileRecord &RFile) { - return sys::fs::equivalent(RFile.File, FName); + // Note that CurrentDir is only used for top-level rsp files, the rest will + // 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; + 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; + } + return LHS->equivalent(*RHS); }; // Check for recursive response files. @@ -1149,10 +1188,13 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, // 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 (!ExpandResponseFile(FName, Saver, Tokenizer, ExpandedArgv, MarkEOLs, - RelativeNames)) { + if (llvm::Error Err = + ExpandResponseFile(FName, Saver, Tokenizer, ExpandedArgv, MarkEOLs, + RelativeNames, 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; @@ -1180,9 +1222,20 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, bool cl::readConfigFile(StringRef CfgFile, StringSaver &Saver, SmallVectorImpl<const char *> &Argv) { - if (!ExpandResponseFile(CfgFile, Saver, cl::tokenizeConfigFile, Argv, - /*MarkEOLs*/ false, /*RelativeNames*/ true)) + SmallString<128> AbsPath; + if (sys::path::is_relative(CfgFile)) { + llvm::sys::fs::current_path(AbsPath); + llvm::sys::path::append(AbsPath, CfgFile); + CfgFile = AbsPath.str(); + } + if (llvm::Error Err = + ExpandResponseFile(CfgFile, Saver, cl::tokenizeConfigFile, Argv, + /*MarkEOLs*/ false, /*RelativeNames*/ 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); } @@ -1447,7 +1500,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, if (NearestHandler) { // If we know a near match, report it as well. *Errs << ProgramName << ": Did you mean '" - << PrintArg(NearestHandlerString) << "'?\n"; + << PrintArg(NearestHandlerString, 0) << "'?\n"; } ErrorParsing = true; @@ -1601,7 +1654,7 @@ bool Option::error(const Twine &Message, StringRef ArgName, raw_ostream &Errs) { if (ArgName.empty()) Errs << HelpStr; // Be nice for positional arguments else - Errs << GlobalParser->ProgramName << ": for the " << PrintArg(ArgName); + Errs << GlobalParser->ProgramName << ": for the " << PrintArg(ArgName, 0); Errs << " option: " << Message << "\n"; return true; @@ -1757,6 +1810,24 @@ bool parser<int>::parse(Option &O, StringRef ArgName, StringRef Arg, return false; } +// parser<long> implementation +// +bool parser<long>::parse(Option &O, StringRef ArgName, StringRef Arg, + long &Value) { + if (Arg.getAsInteger(0, Value)) + return O.error("'" + Arg + "' value invalid for long argument!"); + return false; +} + +// parser<long long> implementation +// +bool parser<long long>::parse(Option &O, StringRef ArgName, StringRef Arg, + long long &Value) { + if (Arg.getAsInteger(0, Value)) + return O.error("'" + Arg + "' value invalid for llong argument!"); + return false; +} + // parser<unsigned> implementation // bool parser<unsigned>::parse(Option &O, StringRef ArgName, StringRef Arg, @@ -1966,6 +2037,8 @@ void generic_parser_base::printGenericOptionDiff( PRINT_OPT_DIFF(bool) PRINT_OPT_DIFF(boolOrDefault) PRINT_OPT_DIFF(int) +PRINT_OPT_DIFF(long) +PRINT_OPT_DIFF(long long) PRINT_OPT_DIFF(unsigned) PRINT_OPT_DIFF(unsigned long) PRINT_OPT_DIFF(unsigned long long) @@ -2039,7 +2112,7 @@ static void sortOpts(StringMap<Option *> &OptMap, static void sortSubCommands(const SmallPtrSetImpl<SubCommand *> &SubMap, SmallVectorImpl<std::pair<const char *, SubCommand *>> &Subs) { - for (const auto &S : SubMap) { + for (auto *S : SubMap) { if (S->getName().empty()) continue; Subs.push_back(std::make_pair(S->getName().data(), S)); @@ -2363,6 +2436,28 @@ static VersionPrinterTy OverrideVersionPrinter = nullptr; static std::vector<VersionPrinterTy> *ExtraVersionPrinters = nullptr; +#if defined(__GNUC__) +// GCC and GCC-compatible compilers define __OPTIMIZE__ when optimizations are +// enabled. +# if defined(__OPTIMIZE__) +# define LLVM_IS_DEBUG_BUILD 0 +# else +# define LLVM_IS_DEBUG_BUILD 1 +# endif +#elif defined(_MSC_VER) +// MSVC doesn't have a predefined macro indicating if optimizations are enabled. +// Use _DEBUG instead. This macro actually corresponds to the choice between +// debug and release CRTs, but it is a reasonable proxy. +# if defined(_DEBUG) +# define LLVM_IS_DEBUG_BUILD 1 +# else +# define LLVM_IS_DEBUG_BUILD 0 +# endif +#else +// Otherwise, for an unknown compiler, assume this is an optimized build. +# define LLVM_IS_DEBUG_BUILD 0 +#endif + namespace { class VersionPrinter { public: @@ -2378,7 +2473,7 @@ public: OS << " " << LLVM_VERSION_INFO; #endif OS << "\n "; -#ifndef __OPTIMIZE__ +#if LLVM_IS_DEBUG_BUILD OS << "DEBUG build"; #else OS << "Optimized build"; |