diff options
Diffstat (limited to 'tools/driver/driver.cpp')
-rw-r--r-- | tools/driver/driver.cpp | 171 |
1 files changed, 78 insertions, 93 deletions
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 5925447..ea218d5 100644 --- a/tools/driver/driver.cpp +++ b/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,94 +201,33 @@ extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, extern int cc1as_main(ArrayRef<const char *> 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; -} - -static void ParseProgName(SmallVectorImpl<const char *> &ArgVector, - std::set<std::string> &SavedStrings) { - // 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. - - std::string ProgName =llvm::sys::path::stem(ArgVector[0]); -#ifdef LLVM_ON_WIN32 - // Transform to lowercase for case insensitive file systems. - ProgName = StringRef(ProgName).lower(); -#endif - - StringRef ProgNameRef = ProgName; - const DriverSuffix *DS = FindDriverSuffix(ProgNameRef); - - if (!DS) { - // Try again after stripping any trailing version number: - // clang++3.5 -> clang++ - ProgNameRef = ProgNameRef.rtrim("0123456789."); - DS = FindDriverSuffix(ProgNameRef); +static void insertTargetAndModeArgs(StringRef Target, StringRef Mode, + SmallVectorImpl<const char *> &ArgVector, + std::set<std::string> &SavedStrings) { + if (!Mode.empty()) { + // Add the mode flag to the arguments. + auto it = ArgVector.begin(); + if (it != ArgVector.end()) + ++it; + ArgVector.insert(it, GetStableCStr(SavedStrings, Mode)); } - if (!DS) { - // Try again after stripping trailing -component. - // clang++-tot -> clang++ - ProgNameRef = ProgNameRef.slice(0, ProgNameRef.rfind('-')); - DS = FindDriverSuffix(ProgNameRef); + if (!Target.empty()) { + auto it = ArgVector.begin(); + if (it != ArgVector.end()) + ++it; + const char *arr[] = {"-target", GetStableCStr(SavedStrings, Target)}; + ArgVector.insert(it, std::begin(arr), std::end(arr)); } +} - if (DS) { - if (const char *Flag = DS->ModeFlag) { - // Add Flag to the arguments. - auto it = ArgVector.begin(); - if (it != ArgVector.end()) - ++it; - ArgVector.insert(it, Flag); - } - - StringRef::size_type LastComponent = ProgNameRef.rfind( - '-', ProgNameRef.size() - strlen(DS->Suffix)); - if (LastComponent == StringRef::npos) - return; - - // Infer target from the prefix. - StringRef Prefix = ProgNameRef.slice(0, LastComponent); - std::string IgnoredError; - if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { - auto it = ArgVector.begin(); - if (it != ArgVector.end()) - ++it; - const char *arr[] = { "-target", GetStableCStr(SavedStrings, Prefix) }; - ArgVector.insert(it, std::begin(arr), std::end(arr)); - } - } +static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver, + SmallVectorImpl<const char *> &Opts) { + llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts); + // The first instance of '#' should be replaced with '=' in each option. + for (const char *Opt : Opts) + if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#'))) + *NumberSignPtr = '='; } static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) { @@ -335,7 +274,7 @@ CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) { } static void SetInstallDir(SmallVectorImpl<const char *> &argv, - Driver &TheDriver) { + Driver &TheDriver, bool CanonicalPrefixes) { // Attempt to find the original path used to invoke the driver, to determine // the installed path. We do this manually, because we want to support that // path being a symlink. @@ -346,7 +285,11 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv, if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName( llvm::sys::path::filename(InstalledPath.str()))) InstalledPath = *Tmp; - llvm::sys::fs::make_absolute(InstalledPath); + + // FIXME: We don't actually canonicalize this, we just make it absolute. + if (CanonicalPrefixes) + llvm::sys::fs::make_absolute(InstalledPath); + InstalledPath = llvm::sys::path::parent_path(InstalledPath); if (llvm::sys::fs::exists(InstalledPath.c_str())) TheDriver.setInstalledDir(InstalledPath); @@ -380,16 +323,35 @@ int main(int argc_, const char **argv_) { return 1; } + llvm::InitializeAllTargets(); + std::string ProgName = argv[0]; + std::pair<std::string, std::string> TargetAndMode = + ToolChain::getTargetAndModeFromProgramName(ProgName); + llvm::BumpPtrAllocator A; - llvm::BumpPtrStringSaver Saver(A); + llvm::StringSaver Saver(A); + + // Parse response files using the GNU syntax, unless we're in CL mode. There + // are two ways to put clang in CL compatibility mode: argv[0] is either + // clang-cl or cl, or --driver-mode=cl is on the command line. The normal + // command line parsing can't happen until after response file parsing, so we + // have to manually search for a --driver-mode=cl argument the hard way. + // 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 (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()) { + Tokenizer = &llvm::cl::TokenizeWindowsCommandLine; + } // Determines whether we want nullptr markers in argv to indicate response // files end-of-lines. We only use this for the /LINK driver argument. bool MarkEOLs = true; if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) MarkEOLs = false; - llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv, - MarkEOLs); + llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs); // Handle -cc1 integrated tools, even if -cc1 was expanded from a response // file. @@ -415,6 +377,29 @@ int main(int argc_, const char **argv_) { } } + // Handle CL and _CL_ which permits additional command line options to be + // prepended or appended. + if (Tokenizer == &llvm::cl::TokenizeWindowsCommandLine) { + // Arguments in "CL" are prepended. + llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL"); + if (OptCL.hasValue()) { + SmallVector<const char *, 8> PrependedOpts; + getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts); + + // Insert right after the program name to prepend to the argument list. + argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end()); + } + // Arguments in "_CL_" are appended. + llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_"); + if (Opt_CL_.hasValue()) { + SmallVector<const char *, 8> AppendedOpts; + getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts); + + // Insert at the end of the argument list to append. + argv.append(AppendedOpts.begin(), AppendedOpts.end()); + } + } + std::set<std::string> SavedStrings; // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the // scenes. @@ -447,10 +432,10 @@ int main(int argc_, const char **argv_) { ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); - SetInstallDir(argv, TheDriver); + SetInstallDir(argv, TheDriver, CanonicalPrefixes); - llvm::InitializeAllTargets(); - ParseProgName(argv, SavedStrings); + insertTargetAndModeArgs(TargetAndMode.first, TargetAndMode.second, argv, + SavedStrings); SetBackdoorDriverOutputsFromEnvVars(TheDriver); |