diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 85810f0b568b6..da7e8386a151c 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -380,12 +380,6 @@ class Driver { /// to determine if an error occurred. Compilation *BuildCompilation(ArrayRef Args); - /// @name Driver Steps - /// @{ - - /// ParseDriverMode - Look for and handle the driver mode option in Args. - void ParseDriverMode(StringRef ProgramName, ArrayRef Args); - /// ParseArgStrings - Parse the given list of strings into an /// ArgList. llvm::opt::InputArgList ParseArgStrings(ArrayRef Args, @@ -584,9 +578,9 @@ class Driver { /// \returns true, if error occurred while reading. bool readConfigFile(StringRef FileName); - /// Set the driver mode (cl, gcc, etc) from an option string of the form - /// --driver-mode=. - void setDriverModeFromOption(StringRef Opt); + /// Set the driver mode (cl, gcc, etc) from the value of the `--driver-mode` + /// option. + void setDriverMode(StringRef DriverModeValue); /// Parse the \p Args list for LTO options and record the type of LTO /// compilation based on which -f(no-)?lto(=.*)? option occurs last. @@ -646,6 +640,16 @@ bool isOptimizationLevelFast(const llvm::opt::ArgList &Args); /// \return True if the argument combination will end up generating remarks. bool willEmitRemarks(const llvm::opt::ArgList &Args); +/// Returns the driver mode option's value, i.e. `X` in `--driver-mode=X`. If \p +/// Args doesn't mention one explicitly, tries to deduce from `ProgName`. +/// Returns empty on failure. +/// Common values are "gcc", "g++", "cpp", "cl" and "flang". Returned value need +/// not be one of these. +llvm::StringRef getDriverMode(StringRef ProgName, ArrayRef Args); + +/// Checks whether the value produced by getDriverMode is for CL mode. +bool IsClangCL(StringRef DriverMode); + } // end namespace driver } // end namespace clang diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index a06eb6ccc1b3c..5c323cb6ea23e 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -63,6 +63,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" @@ -168,28 +169,9 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR); } -void Driver::ParseDriverMode(StringRef ProgramName, - ArrayRef Args) { - if (ClangNameParts.isEmpty()) - ClangNameParts = ToolChain::getTargetAndModeFromProgramName(ProgramName); - setDriverModeFromOption(ClangNameParts.DriverMode); - - for (const char *ArgPtr : Args) { - // Ignore nullptrs, they are the response file's EOL markers. - if (ArgPtr == nullptr) - continue; - const StringRef Arg = ArgPtr; - setDriverModeFromOption(Arg); - } -} - -void Driver::setDriverModeFromOption(StringRef Opt) { - const std::string OptName = +void Driver::setDriverMode(StringRef Value) { + static const std::string OptName = getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); - if (!Opt.startswith(OptName)) - return; - StringRef Value = Opt.drop_front(OptName.size()); - if (auto M = llvm::StringSwitch>(Value) .Case("gcc", GCCMode) .Case("g++", GXXMode) @@ -1031,7 +1013,10 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { // We look for the driver mode option early, because the mode can affect // how other options are parsed. - ParseDriverMode(ClangExecutable, ArgList.slice(1)); + + auto DriverMode = getDriverMode(ClangExecutable, ArgList.slice(1)); + if (!DriverMode.empty()) + setDriverMode(DriverMode); // FIXME: What are we going to do with -V and -b? @@ -5573,3 +5558,21 @@ bool clang::driver::willEmitRemarks(const ArgList &Args) { return true; return false; } + +llvm::StringRef clang::driver::getDriverMode(StringRef ProgName, + ArrayRef Args) { + static const std::string OptName = + getDriverOptTable().getOption(options::OPT_driver_mode).getPrefixedName(); + llvm::StringRef Opt; + for (StringRef Arg : Args) { + if (!Arg.startswith(OptName)) + continue; + Opt = Arg; + break; + } + if (Opt.empty()) + Opt = ToolChain::getTargetAndModeFromProgramName(ProgName).DriverMode; + return Opt.consume_front(OptName) ? Opt : ""; +} + +bool driver::IsClangCL(StringRef DriverMode) { return DriverMode.equals("cl"); } diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp index 650e510fb68ff..c1e25c41f7198 100644 --- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp +++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp @@ -43,9 +43,11 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/LangStandard.h" +#include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" #include "clang/Driver/Types.h" #include "clang/Tooling/CompilationDatabase.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringExtras.h" @@ -134,8 +136,7 @@ struct TransferableCommand { bool ClangCLMode; TransferableCommand(CompileCommand C) - : Cmd(std::move(C)), Type(guessType(Cmd.Filename)), - ClangCLMode(checkIsCLMode(Cmd.CommandLine)) { + : Cmd(std::move(C)), Type(guessType(Cmd.Filename)) { std::vector OldArgs = std::move(Cmd.CommandLine); Cmd.CommandLine.clear(); @@ -145,6 +146,9 @@ struct TransferableCommand { SmallVector TmpArgv; for (const std::string &S : OldArgs) TmpArgv.push_back(S.c_str()); + ClangCLMode = !TmpArgv.empty() && + driver::IsClangCL(driver::getDriverMode( + TmpArgv.front(), llvm::makeArrayRef(TmpArgv).slice(1))); ArgList = {TmpArgv.begin(), TmpArgv.end()}; } @@ -246,19 +250,6 @@ struct TransferableCommand { } private: - // Determine whether the given command line is intended for the CL driver. - static bool checkIsCLMode(ArrayRef CmdLine) { - // First look for --driver-mode. - for (StringRef S : llvm::reverse(CmdLine)) { - if (S.consume_front("--driver-mode=")) - return S == "cl"; - } - - // Otherwise just check the clang executable file name. - return !CmdLine.empty() && - llvm::sys::path::stem(CmdLine.front()).endswith_insensitive("cl"); - } - // Map the language from the --std flag to that of the -x flag. static types::ID toType(Language Lang) { switch (Lang) { diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp index 9e3f51db21a9d..5a453429e79bf 100644 --- a/clang/tools/driver/driver.cpp +++ b/clang/tools/driver/driver.cpp @@ -360,7 +360,6 @@ int main(int Argc, const char **Argv) { return 1; llvm::InitializeAllTargets(); - auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Args[0]); llvm::BumpPtrAllocator A; llvm::StringSaver Saver(A); @@ -372,13 +371,8 @@ int main(int Argc, const char **Argv) { // 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. - bool ClangCLMode = false; - if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") || - llvm::find_if(Args, [](const char *F) { - return F && strcmp(F, "--driver-mode=cl") == 0; - }) != Args.end()) { - ClangCLMode = true; - } + bool ClangCLMode = + IsClangCL(getDriverMode(Args[0], llvm::makeArrayRef(Args).slice(1))); enum { Default, POSIX, Windows } RSPQuoting = Default; for (const char *F : Args) { if (strcmp(F, "--rsp-quoting=posix") == 0) @@ -490,6 +484,7 @@ int main(int Argc, const char **Argv) { Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); SetInstallDir(Args, TheDriver, CanonicalPrefixes); + auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Args[0]); TheDriver.setTargetAndMode(TargetAndMode); insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings);