Index: clang/include/clang/Driver/Driver.h =================================================================== --- clang/include/clang/Driver/Driver.h +++ clang/include/clang/Driver/Driver.h @@ -21,6 +21,7 @@ #include "clang/Driver/Types.h" #include "clang/Driver/Util.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Option/Arg.h" @@ -261,7 +262,8 @@ /// When the clangDriver lib is used through clang.exe, this provides a /// shortcut for executing the -cc1 command-line directly, in the same /// process. - typedef int (*CC1ToolFunc)(SmallVectorImpl &ArgV); + using CC1ToolFunc = + llvm::function_ref &ArgV)>; CC1ToolFunc CC1Main = nullptr; private: @@ -286,6 +288,12 @@ /// Arguments originated from command line. std::unique_ptr CLOptions; + /// If this is non-null, the driver will prepend this argument before + /// reinvoking clang. This is useful for the llvm-driver where clang's + /// realpath will be to the llvm binary and not clang, so it must pass + /// "clang" as it's first argument. + const char *LLVMDriverPrependArg; + /// Whether to check that input files exist when constructing compilation /// jobs. unsigned CheckInputsExist : 1; @@ -383,6 +391,11 @@ bool getProbePrecompiled() const { return ProbePrecompiled; } void setProbePrecompiled(bool Value) { ProbePrecompiled = Value; } + const char *getLLVMDriverPrependArg() const { return LLVMDriverPrependArg; } + void setLLVMDriverPrependArg(const char *Value) { + LLVMDriverPrependArg = Value; + } + void setTargetAndMode(const ParsedClangName &TM) { ClangNameParts = TM; } const std::string &getTitle() { return DriverTitle; } Index: clang/include/clang/Driver/Job.h =================================================================== --- clang/include/clang/Driver/Job.h +++ clang/include/clang/Driver/Job.h @@ -116,6 +116,9 @@ /// The executable to run. const char *Executable; + /// Optional argument to prepend. + const char *PrependArg; + /// The list of program arguments (not including the implicit first /// argument, which will be the executable). llvm::opt::ArgStringList Arguments; @@ -169,7 +172,7 @@ Command(const Action &Source, const Tool &Creator, ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, ArrayRef Inputs, - ArrayRef Outputs = std::nullopt); + ArrayRef Outputs = std::nullopt, const char *PrependArg = nullptr); // FIXME: This really shouldn't be copyable, but is currently copied in some // error handling in Driver::generateCompilationDiagnostics. Command(const Command &) = default; @@ -242,7 +245,8 @@ ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, ArrayRef Inputs, - ArrayRef Outputs = std::nullopt); + ArrayRef Outputs = std::nullopt, + const char *PrependArg = nullptr); void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo = nullptr) const override; Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -200,8 +200,8 @@ DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false), CCLogDiagnostics(false), CCGenDiagnostics(false), CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc), - CheckInputsExist(true), ProbePrecompiled(true), - SuppressMissingInputWarning(false) { + LLVMDriverPrependArg(nullptr), CheckInputsExist(true), + ProbePrecompiled(true), SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) this->VFS = llvm::vfs::getRealFileSystem(); Index: clang/lib/Driver/Job.cpp =================================================================== --- clang/lib/Driver/Job.cpp +++ clang/lib/Driver/Job.cpp @@ -38,9 +38,10 @@ Command::Command(const Action &Source, const Tool &Creator, ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, - ArrayRef Inputs, ArrayRef Outputs) + ArrayRef Inputs, ArrayRef Outputs, + const char *PrependArg) : Source(Source), Creator(Creator), ResponseSupport(ResponseSupport), - Executable(Executable), Arguments(Arguments) { + Executable(Executable), PrependArg(PrependArg), Arguments(Arguments) { for (const auto &II : Inputs) if (II.isFilename()) InputInfoList.push_back(II); @@ -144,6 +145,10 @@ for (const auto *InputName : InputFileList) Inputs.insert(InputName); Out.push_back(Executable); + + if (PrependArg) + Out.push_back(PrependArg); + // In a file list, build args vector ignoring parameters that will go in the // response file (elements of the InputFileList vector) bool FirstInput = true; @@ -209,6 +214,9 @@ if (ResponseFile != nullptr) { buildArgvForResponseFile(ArgsRespFile); Args = ArrayRef(ArgsRespFile).slice(1); // no executable name + } else if (PrependArg) { + OS << ' '; + llvm::sys::printArg(OS, PrependArg, /*Quote=*/true); } bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty(); @@ -321,6 +329,8 @@ SmallVector Argv; if (ResponseFile == nullptr) { Argv.push_back(Executable); + if (PrependArg) + Argv.push_back(PrependArg); Argv.append(Arguments.begin(), Arguments.end()); Argv.push_back(nullptr); } else { @@ -382,9 +392,10 @@ ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, - ArrayRef Inputs, ArrayRef Outputs) + ArrayRef Inputs, ArrayRef Outputs, + const char *PrependArg) : Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs, - Outputs) { + Outputs, PrependArg) { InProcess = true; } Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -4918,7 +4918,7 @@ C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(), - CmdArgs, Inputs, Output)); + CmdArgs, Inputs, Output, D.getLLVMDriverPrependArg())); return; } @@ -7322,13 +7322,13 @@ if (D.CC1Main && !D.CCGenDiagnostics) { // Invoke the CC1 directly in this process - C.addCommand(std::make_unique(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getLLVMDriverPrependArg())); } else { - C.addCommand(std::make_unique(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getLLVMDriverPrependArg())); } // Make the compile command echo its inputs for /showFilenames. @@ -8087,13 +8087,13 @@ const char *Exec = getToolChain().getDriver().getClangProgramPath(); if (D.CC1Main && !D.CCGenDiagnostics) { // Invoke cc1as directly in this process. - C.addCommand(std::make_unique(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getLLVMDriverPrependArg())); } else { - C.addCommand(std::make_unique(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getLLVMDriverPrependArg())); } } Index: clang/test/Analysis/scan-build/lit.local.cfg =================================================================== --- clang/test/Analysis/scan-build/lit.local.cfg +++ clang/test/Analysis/scan-build/lit.local.cfg @@ -7,6 +7,8 @@ use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") config.test_format = lit.formats.ShTest(use_lit_shell == "0") +clang_path = config.clang if config.have_llvm_driver else os.path.realpath(config.clang) + config.substitutions.append(('%scan-build', '\'%s\' --use-analyzer=%s ' % ( lit.util.which('scan-build', @@ -15,4 +17,4 @@ 'tools', 'scan-build', 'bin')), - os.path.realpath(config.clang)))) + clang_path))) Index: clang/tools/driver/cc1gen_reproducer_main.cpp =================================================================== --- clang/tools/driver/cc1gen_reproducer_main.cpp +++ clang/tools/driver/cc1gen_reproducer_main.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLTraits.h" @@ -110,7 +111,8 @@ /// Generates a reproducer for a set of arguments from a specific invocation. static llvm::Optional generateReproducerForInvocationArguments(ArrayRef Argv, - const ClangInvocationInfo &Info) { + const ClangInvocationInfo &Info, + const llvm::ToolContext &ToolContext) { using namespace driver; auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Argv[0]); @@ -119,8 +121,10 @@ IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, &*DiagOpts, new IgnoringDiagConsumer()); ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); - Driver TheDriver(Argv[0], llvm::sys::getDefaultTargetTriple(), Diags); + Driver TheDriver(ToolContext.Path, llvm::sys::getDefaultTargetTriple(), + Diags); TheDriver.setTargetAndMode(TargetAndMode); + TheDriver.setLLVMDriverPrependArg(ToolContext.PrependArg); std::unique_ptr C(TheDriver.BuildCompilation(Argv)); if (C && !C->containsError()) { @@ -154,7 +158,8 @@ } int cc1gen_reproducer_main(ArrayRef Argv, const char *Argv0, - void *MainAddr) { + void *MainAddr, + const llvm::ToolContext &ToolContext) { if (Argv.size() < 1) { llvm::errs() << "error: missing invocation file\n"; return 1; @@ -181,7 +186,8 @@ std::string Path = GetExecutablePath(Argv0, /*CanonicalPrefixes=*/true); DriverArgs[0] = Path.c_str(); llvm::Optional Report = - generateReproducerForInvocationArguments(DriverArgs, InvocationInfo); + generateReproducerForInvocationArguments(DriverArgs, InvocationInfo, + ToolContext); // Emit the information about the reproduce files to stdout. int Result = 1; Index: clang/tools/driver/driver.cpp =================================================================== --- clang/tools/driver/driver.cpp +++ clang/tools/driver/driver.cpp @@ -211,7 +211,8 @@ extern int cc1as_main(ArrayRef Argv, const char *Argv0, void *MainAddr); extern int cc1gen_reproducer_main(ArrayRef Argv, - const char *Argv0, void *MainAddr); + const char *Argv0, void *MainAddr, + const llvm::ToolContext &); static void insertTargetAndModeArgs(const ParsedClangName &NameParts, SmallVectorImpl &ArgVector, @@ -342,7 +343,8 @@ TheDriver.setInstalledDir(InstalledPathParent); } -static int ExecuteCC1Tool(SmallVectorImpl &ArgV) { +static int ExecuteCC1Tool(SmallVectorImpl &ArgV, + const llvm::ToolContext &ToolContext) { // If we call the cc1 tool from the clangDriver library (through // Driver::CC1Main), we need to clean up the options usage count. The options // are currently global, and they might have been used previously by the @@ -363,14 +365,14 @@ return cc1as_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP); if (Tool == "-cc1gen-reproducer") return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0], - GetExecutablePathVP); + GetExecutablePathVP, ToolContext); // Reject unknown tools. llvm::errs() << "error: unknown integrated tool '" << Tool << "'. " << "Valid tools include '-cc1' and '-cc1as'.\n"; return 1; } -int clang_main(int Argc, char **Argv, const llvm::ToolContext &) { +int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) { noteBottomOfStack(); llvm::InitLLVM X(Argc, Argv); llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL @@ -386,15 +388,17 @@ llvm::BumpPtrAllocator A; llvm::StringSaver Saver(A); + const char *ProgName = ToolContext.GetProgName(); + // Parse response files using the GNU syntax, unless we're in CL mode. There - // are two ways to put clang in CL compatibility mode: Args[0] is either + // are two ways to put clang in CL compatibility mode: ProgName 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. bool ClangCLMode = - IsClangCL(getDriverMode(Args[0], llvm::ArrayRef(Args).slice(1))); + IsClangCL(getDriverMode(ProgName, llvm::ArrayRef(Args).slice(1))); enum { Default, POSIX, Windows } RSPQuoting = Default; for (const char *F : Args) { if (strcmp(F, "--rsp-quoting=posix") == 0) @@ -433,7 +437,7 @@ auto newEnd = std::remove(Args.begin(), Args.end(), nullptr); Args.resize(newEnd - Args.begin()); } - return ExecuteCC1Tool(Args); + return ExecuteCC1Tool(Args, ToolContext); } // Handle options that need handling before the real command line parsing in @@ -480,7 +484,8 @@ ApplyQAOverride(Args, OverrideStr, SavedStrings); } - std::string Path = GetExecutablePath(Args[0], CanonicalPrefixes); + std::string Path = GetExecutablePath( + ToolContext.Path, CanonicalPrefixes && !ToolContext.IsDriver); // Whether the cc1 tool should be called inside the current process, or if we // should spawn a new clang subprocess (old behavior). @@ -498,7 +503,7 @@ TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); - FixupDiagPrefixExeName(DiagClient, Path); + FixupDiagPrefixExeName(DiagClient, ProgName); IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); @@ -516,8 +521,9 @@ Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); SetInstallDir(Args, TheDriver, CanonicalPrefixes); - auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Args[0]); + auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(ProgName); TheDriver.setTargetAndMode(TargetAndMode); + TheDriver.setLLVMDriverPrependArg(ToolContext.PrependArg); insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings); @@ -525,7 +531,9 @@ return 1; if (!UseNewCC1Process) { - TheDriver.CC1Main = &ExecuteCC1Tool; + TheDriver.CC1Main = [&ToolContext](SmallVectorImpl &ArgV) { + return ExecuteCC1Tool(ArgV, ToolContext); + }; // Ensure the CC1Command actually catches cc1 crashes llvm::CrashRecoveryContext::Enable(); } Index: llvm/cmake/modules/llvm-driver-template.cpp.in =================================================================== --- llvm/cmake/modules/llvm-driver-template.cpp.in +++ llvm/cmake/modules/llvm-driver-template.cpp.in @@ -11,4 +11,6 @@ int @TOOL_NAME@_main(int argc, char **, const llvm::ToolContext &); -int main(int argc, char **argv) { return @TOOL_NAME@_main(argc, argv, {}); } +int main(int argc, char **argv) { + return @TOOL_NAME@_main(argc, argv, {argv[0], nullptr, false}); +} Index: llvm/include/llvm/Support/LLVMDriver.h =================================================================== --- llvm/include/llvm/Support/LLVMDriver.h +++ llvm/include/llvm/Support/LLVMDriver.h @@ -9,9 +9,17 @@ #ifndef LLVM_SUPPORT_LLVMDRIVER_H #define LLVM_SUPPORT_LLVMDRIVER_H +#include "llvm/ADT/SmallVector.h" + namespace llvm { -struct ToolContext {}; +struct ToolContext { + const char *Path; + const char *PrependArg; + bool IsDriver; + + const char *GetProgName() const { return PrependArg ? PrependArg : Path; } +}; } // namespace llvm Index: llvm/lib/Support/Path.cpp =================================================================== --- llvm/lib/Support/Path.cpp +++ llvm/lib/Support/Path.cpp @@ -1202,18 +1202,10 @@ #include "Windows/Path.inc" #endif -bool IsLLVMDriver = false; - namespace llvm { namespace sys { namespace fs { -std::string getMainExecutable(const char *Argv0, void *MainAddr) { - if (IsLLVMDriver) - return sys::path::stem(Argv0).str(); - return getMainExecutableImpl(Argv0, MainAddr); -} - TempFile::TempFile(StringRef Name, int FD) : TmpName(std::string(Name)), FD(FD) {} TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); } Index: llvm/lib/Support/Unix/Path.inc =================================================================== --- llvm/lib/Support/Unix/Path.inc +++ llvm/lib/Support/Unix/Path.inc @@ -190,7 +190,7 @@ /// GetMainExecutable - Return the path to the main executable, given the /// value of argv[0] from program startup. -std::string getMainExecutableImpl(const char *argv0, void *MainAddr) { +std::string getMainExecutable(const char *argv0, void *MainAddr) { #if defined(__APPLE__) // On OS X the executable path is saved to the stack by dyld. Reading it // from there is much faster than calling dladdr, especially for large Index: llvm/lib/Support/Windows/Path.inc =================================================================== --- llvm/lib/Support/Windows/Path.inc +++ llvm/lib/Support/Windows/Path.inc @@ -130,7 +130,7 @@ const file_t kInvalidFile = INVALID_HANDLE_VALUE; -std::string getMainExecutableImpl(const char *argv0, void *MainExecAddr) { +std::string getMainExecutable(const char *argv0, void *MainExecAddr) { SmallVector PathName; PathName.resize_for_overwrite(PathName.capacity()); DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.size()); Index: llvm/tools/llvm-driver/llvm-driver.cpp =================================================================== --- llvm/tools/llvm-driver/llvm-driver.cpp +++ llvm/tools/llvm-driver/llvm-driver.cpp @@ -36,7 +36,7 @@ << "OPTIONS:\n\n --help - Display this message"; } -static int findTool(int Argc, char **Argv) { +static int findTool(int Argc, char **Argv, const char *Argv0) { if (!Argc) { printHelpMessage(); return 1; @@ -62,21 +62,22 @@ return false; }; + auto MakeDriverArgs = [=]() -> llvm::ToolContext { + if (ToolName != Argv0) + return {Argv0, ToolName.data(), true}; + return {Argv0, nullptr, true}; + }; + #define LLVM_DRIVER_TOOL(tool, entry) \ if (Is(tool)) \ - return entry##_main(Argc, Argv, {}); + return entry##_main(Argc, Argv, MakeDriverArgs()); #include "LLVMDriverTools.def" if (Is("llvm")) - return findTool(Argc - 1, Argv + 1); + return findTool(Argc - 1, Argv + 1, Argv0); printHelpMessage(); return 1; } -extern bool IsLLVMDriver; - -int main(int Argc, char **Argv) { - IsLLVMDriver = true; - return findTool(Argc, Argv); -} +int main(int Argc, char **Argv) { return findTool(Argc, Argv, Argv[0]); }