Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -151,6 +151,20 @@ // Returns the RTTIMode for the toolchain with the current arguments. RTTIMode getRTTIMode() const { return CachedRTTIMode; } + /// \brief Return any implicit target and/or mode flag for an invocation of + /// the compiler driver as `ProgName`. + /// + /// For example, when called with i686-linux-android-g++, the first element + /// of the return value will be set to `"i686-linux-android"` and the second + /// will be set to "--driver-mode=g++"`. + /// + /// \pre `llvm::InitializeAllTargets()` has been called. + /// \param ProgName The name the Clang driver was invoked with (from, + /// e.g., argv[0]) + /// \return A pair of (`target`, `mode-flag`), where one or both may be empty. + static std::pair + getTargetAndModeFromProgramName(StringRef ProgName); + // Tool access. /// TranslateArgs - Create a new derived argument list for any argument Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -22,6 +22,7 @@ #include "llvm/Option/Option.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/TargetRegistry.h" using namespace clang::driver; using namespace clang; using namespace llvm::opt; @@ -88,6 +89,99 @@ return *SanitizerArguments.get(); } +namespace { +struct DriverSuffix { + const char *Suffix; + const char *ModeFlag; +}; + +const DriverSuffix *FindDriverSuffix(StringRef ProgName) { + // A list of known driver suffixes. Suffixes are compared against the + // program name in order. If there is a match, the frontend type is updated as + // necessary by applying the ModeFlag. + static const DriverSuffix DriverSuffixes[] = { + {"clang", nullptr}, + {"clang++", "--driver-mode=g++"}, + {"clang-c++", "--driver-mode=g++"}, + {"clang-cc", nullptr}, + {"clang-cpp", "--driver-mode=cpp"}, + {"clang-g++", "--driver-mode=g++"}, + {"clang-gcc", nullptr}, + {"clang-cl", "--driver-mode=cl"}, + {"cc", nullptr}, + {"cpp", "--driver-mode=cpp"}, + {"cl", "--driver-mode=cl"}, + {"++", "--driver-mode=g++"}, + }; + + for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) + if (ProgName.endswith(DriverSuffixes[i].Suffix)) + return &DriverSuffixes[i]; + return nullptr; +} + +/// Normalize the program name from argv[0] by stripping the file extension if +/// present and lower-casing the string on Windows. +std::string normalizeProgramName(llvm::StringRef Argv0) { + std::string ProgName = llvm::sys::path::stem(Argv0); +#ifdef LLVM_ON_WIN32 + // Transform to lowercase for case insensitive file systems. + std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), ::tolower); +#endif + return ProgName; +} + +const DriverSuffix *parseDriverSuffix(StringRef ProgName) { + // Try to infer frontend type and default target from the program name by + // comparing it against DriverSuffixes in order. + + // If there is a match, the function tries to identify a target as prefix. + // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target + // prefix "x86_64-linux". If such a target prefix is found, it may be + // added via -target as implicit first argument. + const DriverSuffix *DS = FindDriverSuffix(ProgName); + + if (!DS) { + // Try again after stripping any trailing version number: + // clang++3.5 -> clang++ + ProgName = ProgName.rtrim("0123456789."); + DS = FindDriverSuffix(ProgName); + } + + if (!DS) { + // Try again after stripping trailing -component. + // clang++-tot -> clang++ + ProgName = ProgName.slice(0, ProgName.rfind('-')); + DS = FindDriverSuffix(ProgName); + } + return DS; +} +} // anonymous namespace + +std::pair +ToolChain::getTargetAndModeFromProgramName(StringRef PN) { + std::string ProgName = normalizeProgramName(PN); + const DriverSuffix *DS = parseDriverSuffix(ProgName); + if (!DS) + return std::make_pair("", ""); + std::string ModeFlag = DS->ModeFlag == nullptr ? "" : DS->ModeFlag; + + std::string::size_type LastComponent = + ProgName.rfind('-', ProgName.size() - strlen(DS->Suffix)); + if (LastComponent == std::string::npos) + return std::make_pair("", ModeFlag); + + // Infer target from the prefix. + StringRef Prefix(ProgName); + Prefix = Prefix.slice(0, LastComponent); + std::string IgnoredError; + std::string Target; + if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { + Target = Prefix; + } + return std::make_pair(Target, ModeFlag); +} + StringRef ToolChain::getDefaultUniversalArchName() const { // In universal driver terms, the arch name accepted by -arch isn't exactly // the same as the ones that appear in the triple. Roughly speaking, this is Index: tools/driver/driver.cpp =================================================================== --- tools/driver/driver.cpp +++ tools/driver/driver.cpp @@ -18,6 +18,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/ToolChain.h" #include "clang/Frontend/ChainedDiagnosticConsumer.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/SerializedDiagnosticPrinter.h" @@ -44,7 +45,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/Signals.h" #include "llvm/Support/StringSaver.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" @@ -201,101 +201,22 @@ extern int cc1as_main(ArrayRef Argv, const char *Argv0, void *MainAddr); -struct DriverSuffix { - const char *Suffix; - const char *ModeFlag; -}; - -static const DriverSuffix *FindDriverSuffix(StringRef ProgName) { - // A list of known driver suffixes. Suffixes are compared against the - // program name in order. If there is a match, the frontend type if updated as - // necessary by applying the ModeFlag. - static const DriverSuffix DriverSuffixes[] = { - {"clang", nullptr}, - {"clang++", "--driver-mode=g++"}, - {"clang-c++", "--driver-mode=g++"}, - {"clang-cc", nullptr}, - {"clang-cpp", "--driver-mode=cpp"}, - {"clang-g++", "--driver-mode=g++"}, - {"clang-gcc", nullptr}, - {"clang-cl", "--driver-mode=cl"}, - {"cc", nullptr}, - {"cpp", "--driver-mode=cpp"}, - {"cl", "--driver-mode=cl"}, - {"++", "--driver-mode=g++"}, - }; - - for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) - if (ProgName.endswith(DriverSuffixes[i].Suffix)) - return &DriverSuffixes[i]; - return nullptr; -} - -/// Normalize the program name from argv[0] by stripping the file extension if -/// present and lower-casing the string on Windows. -static std::string normalizeProgramName(const char *Argv0) { - std::string ProgName = llvm::sys::path::stem(Argv0); -#ifdef LLVM_ON_WIN32 - // Transform to lowercase for case insensitive file systems. - std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), ::tolower); -#endif - return ProgName; -} - -static const DriverSuffix *parseDriverSuffix(StringRef ProgName) { - // Try to infer frontend type and default target from the program name by - // comparing it against DriverSuffixes in order. - - // If there is a match, the function tries to identify a target as prefix. - // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target - // prefix "x86_64-linux". If such a target prefix is found, is gets added via - // -target as implicit first argument. - const DriverSuffix *DS = FindDriverSuffix(ProgName); - - if (!DS) { - // Try again after stripping any trailing version number: - // clang++3.5 -> clang++ - ProgName = ProgName.rtrim("0123456789."); - DS = FindDriverSuffix(ProgName); - } - - if (!DS) { - // Try again after stripping trailing -component. - // clang++-tot -> clang++ - ProgName = ProgName.slice(0, ProgName.rfind('-')); - DS = FindDriverSuffix(ProgName); - } - return DS; -} - -static void insertArgsFromProgramName(StringRef ProgName, - const DriverSuffix *DS, - SmallVectorImpl &ArgVector, - std::set &SavedStrings) { - if (!DS) - return; - - if (const char *Flag = DS->ModeFlag) { - // Add Flag to the arguments. +static void insertTargetAndModeArgs(StringRef Target, StringRef Mode, + SmallVectorImpl &ArgVector, + std::set &SavedStrings) { + if (!Mode.empty()) { + // Add the mode flag to the arguments. auto it = ArgVector.begin(); if (it != ArgVector.end()) ++it; - ArgVector.insert(it, Flag); + ArgVector.insert(it, GetStableCStr(SavedStrings, Mode)); } - StringRef::size_type LastComponent = ProgName.rfind( - '-', ProgName.size() - strlen(DS->Suffix)); - if (LastComponent == StringRef::npos) - return; - - // Infer target from the prefix. - StringRef Prefix = ProgName.slice(0, LastComponent); - std::string IgnoredError; - if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { + if (!Target.empty()) { auto it = ArgVector.begin(); if (it != ArgVector.end()) ++it; - const char *arr[] = { "-target", GetStableCStr(SavedStrings, Prefix) }; + const char *arr[] = {"-target", GetStableCStr(SavedStrings, Target)}; ArgVector.insert(it, std::begin(arr), std::end(arr)); } } @@ -402,8 +323,10 @@ return 1; } - std::string ProgName = normalizeProgramName(argv[0]); - const DriverSuffix *DS = parseDriverSuffix(ProgName); + llvm::InitializeAllTargets(); + std::string ProgName = argv[0]; + std::pair TargetAndMode = + ToolChain::getTargetAndModeFromProgramName(ProgName); llvm::BumpPtrAllocator A; llvm::StringSaver Saver(A); @@ -416,7 +339,7 @@ // Finally, our -cc1 tools don't care which tokenization mode we use because // response files written by clang will tokenize the same way in either mode. llvm::cl::TokenizerCallback Tokenizer = &llvm::cl::TokenizeGNUCommandLine; - if ((DS && DS->ModeFlag && strcmp(DS->ModeFlag, "--driver-mode=cl") == 0) || + if (TargetAndMode.second == "--driver-mode=cl" || std::find_if(argv.begin(), argv.end(), [](const char *F) { return F && strcmp(F, "--driver-mode=cl") == 0; }) != argv.end()) { @@ -511,8 +434,8 @@ Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); SetInstallDir(argv, TheDriver, CanonicalPrefixes); - llvm::InitializeAllTargets(); - insertArgsFromProgramName(ProgName, DS, argv, SavedStrings); + insertTargetAndModeArgs(TargetAndMode.first, TargetAndMode.second, argv, + SavedStrings); SetBackdoorDriverOutputsFromEnvVars(TheDriver);