Index: clang/include/clang/Driver/Driver.h =================================================================== --- clang/include/clang/Driver/Driver.h +++ clang/include/clang/Driver/Driver.h @@ -282,6 +282,10 @@ /// -include foo.h to -include-pch foo.h.pch. unsigned ProbePrecompiled : 1; + /// Whether `ClangExecutable` is a path to the llvm-driver and should then + /// be invoked by prepending "clang" to it's arguments. + unsigned OutOfProcessIsLLVMDriver : 1; + public: // getFinalPhase - Determine which compilation mode we are in and record // which option we used to determine the final phase. @@ -372,6 +376,11 @@ bool getProbePrecompiled() const { return ProbePrecompiled; } void setProbePrecompiled(bool Value) { ProbePrecompiled = Value; } + bool getOutOfProcessIsLLVMDriver() const { return OutOfProcessIsLLVMDriver; } + void setOutOfProcessIsLLVMDriver(bool Value) { + OutOfProcessIsLLVMDriver = 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 = None); + ArrayRef Outputs = None, 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; @@ -240,7 +243,8 @@ CC1Command(const Action &Source, const Tool &Creator, ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, - ArrayRef Inputs, ArrayRef Outputs = None); + ArrayRef Inputs, ArrayRef Outputs = None, + 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,7 +200,7 @@ CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc), CheckInputsExist(true), ProbePrecompiled(true), - SuppressMissingInputWarning(false) { + OutOfProcessIsLLVMDriver(false), 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 @@ -5001,9 +5001,11 @@ II.getInputArg().renderAsInput(Args, CmdArgs); } + const char *PrependArg = + D.getOutOfProcessIsLLVMDriver() ? "clang" : nullptr; C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(), - CmdArgs, Inputs, Output)); + CmdArgs, Inputs, Output, PrependArg)); return; } @@ -7367,15 +7369,16 @@ Input.getInputArg().renderAsInput(Args, CmdArgs); } + const char *PrependArg = D.getOutOfProcessIsLLVMDriver() ? "clang" : nullptr; 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, PrependArg)); } 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, PrependArg)); } // Make the compile command echo its inputs for /showFilenames. @@ -8142,15 +8145,16 @@ CmdArgs.push_back(Input.getFilename()); const char *Exec = getToolChain().getDriver().getClangProgramPath(); + const char *PrependArg = D.getOutOfProcessIsLLVMDriver() ? "clang" : nullptr; 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, PrependArg)); } 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, PrependArg)); } } 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.is_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/test/CMakeLists.txt =================================================================== --- clang/test/CMakeLists.txt +++ clang/test/CMakeLists.txt @@ -15,6 +15,7 @@ LLVM_ENABLE_PER_TARGET_RUNTIME_DIR LLVM_ENABLE_THREADS LLVM_WITH_Z3 + LLVM_TOOL_LLVM_DRIVER_BUILD ) configure_lit_site_cfg( @@ -72,7 +73,7 @@ diagtool hmaptool ) - + if(CLANG_ENABLE_STATIC_ANALYZER) list(APPEND CLANG_TEST_DEPS clang-check Index: clang/test/CodeGen/debug-info-codeview-buildinfo.c =================================================================== --- clang/test/CodeGen/debug-info-codeview-buildinfo.c +++ clang/test/CodeGen/debug-info-codeview-buildinfo.c @@ -11,7 +11,7 @@ // CHECK: 0x[[PWD:.+]] | LF_STRING_ID [size = {{.+}}] ID: , String: [[PWDVAL:.+]] // CHECK: 0x[[FILEPATH:.+]] | LF_STRING_ID [size = {{.+}}] ID: , String: [[FILEPATHVAL:.+[\\/]debug-info-codeview-buildinfo.c]] // CHECK: 0x[[ZIPDB:.+]] | LF_STRING_ID [size = {{.+}}] ID: , String: -// CHECK: 0x[[TOOL:.+]] | LF_STRING_ID [size = {{.+}}] ID: , String: [[TOOLVAL:.+[\\/]clang.*]] +// CHECK: 0x[[TOOL:.+]] | LF_STRING_ID [size = {{.+}}] ID: , String: [[TOOLVAL:.+[\\/][clang|llvm].*]] // CHECK: 0x[[CMDLINE:.+]] | LF_STRING_ID [size = {{.+}}] ID: , String: "-cc1 // CHECK: 0x{{.+}} | LF_BUILDINFO [size = {{.+}}] // CHECK: 0x[[PWD]]: `[[PWDVAL]]` Index: clang/test/Driver/check-time-trace.cpp =================================================================== --- clang/test/Driver/check-time-trace.cpp +++ clang/test/Driver/check-time-trace.cpp @@ -27,7 +27,7 @@ // CHECK-NEXT: "pid": // CHECK-NEXT: "tid": // CHECK-NEXT: "ts": -// CHECK: "name": "clang{{.*}}" +// CHECK: "name": "{{[llvm|clang]}}{{.*}}" // CHECK: "name": "process_name" // CHECK: "name": "thread_name" Index: clang/test/lit.site.cfg.py.in =================================================================== --- clang/test/lit.site.cfg.py.in +++ clang/test/lit.site.cfg.py.in @@ -39,6 +39,7 @@ config.clang_vendor_uti = "@CLANG_VENDOR_UTI@" config.llvm_external_lit = path(r"@LLVM_EXTERNAL_LIT@") config.standalone_build = @CLANG_BUILT_STANDALONE@ +config.is_llvm_driver = @LLVM_TOOL_LLVM_DRIVER_BUILD@ import lit.llvm lit.llvm.initialize(lit_config, config) 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" @@ -121,6 +122,7 @@ ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); Driver TheDriver(Argv[0], llvm::sys::getDefaultTargetTriple(), Diags); TheDriver.setTargetAndMode(TargetAndMode); + TheDriver.setOutOfProcessIsLLVMDriver(llvm::IsLLVMDriver); std::unique_ptr C(TheDriver.BuildCompilation(Argv)); if (C && !C->containsError()) { Index: clang/tools/driver/driver.cpp =================================================================== --- clang/tools/driver/driver.cpp +++ clang/tools/driver/driver.cpp @@ -37,6 +37,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" @@ -269,12 +270,15 @@ } static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient, - const std::string &Path) { + const std::string &Path, + llvm::StringRef Argv0) { // If the clang binary happens to be named cl.exe for compatibility reasons, // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC. StringRef ExeBasename(llvm::sys::path::stem(Path)); if (ExeBasename.equals_insensitive("cl")) ExeBasename = "clang-cl"; + if (llvm::IsLLVMDriver) + ExeBasename = llvm::sys::path::stem(Argv0); DiagClient->setPrefix(std::string(ExeBasename)); } @@ -450,7 +454,7 @@ TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); - FixupDiagPrefixExeName(DiagClient, Path); + FixupDiagPrefixExeName(DiagClient, Path, Args[0]); IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); @@ -470,6 +474,8 @@ SetInstallDir(Args, TheDriver, CanonicalPrefixes); auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Args[0]); TheDriver.setTargetAndMode(TargetAndMode); + TheDriver.setOutOfProcessIsLLVMDriver(llvm::IsLLVMDriver && + CanonicalPrefixes); insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings); Index: clang/tools/scan-build/libexec/ccc-analyzer =================================================================== --- clang/tools/scan-build/libexec/ccc-analyzer +++ clang/tools/scan-build/libexec/ccc-analyzer @@ -201,7 +201,13 @@ $line =~ s/^\s+|\s+$//g; my @items = quotewords('\s+', 0, $line); my $cmd = shift @items; - die "cannot find 'clang' in 'clang' command\n" if (!($cmd =~ /clang/)); + die "cannot find 'clang' in 'clang' command\n" if (!($cmd =~ /clang/ || basename($cmd) =~ /llvm/)); + # If this is the llvm-driver the internal command will look like "llvm clang ...". + # Later this will be invoked like "clang clang ...", so skip over it. + if (basename($cmd) =~ /llvm/) { + die "Expected first arg to llvm driver to be 'clang'" if $items[0] ne "clang"; + shift @items; + } return \@items; } 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 @@ -6,6 +6,12 @@ // //===----------------------------------------------------------------------===// +namespace llvm { + +extern const bool IsLLVMDriver = false; + +} // namespace llvm + int @TOOL_NAME@_main(int argc, char **argv); int main(int argc, char **argv) { return @TOOL_NAME@_main(argc, argv); } Index: llvm/include/llvm/Support/LLVMDriver.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/LLVMDriver.h @@ -0,0 +1,17 @@ +//===- LLVMDriver.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// The llvm-driver is an executable which statically links in many llvm tools +// into one. This can be useful for tools which need to behave slightly +// differently under that environment. +// +//===----------------------------------------------------------------------===// + +namespace llvm { +extern const bool IsLLVMDriver; +} // 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 @@ -194,7 +194,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 @@ -11,9 +11,16 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LLVMDriver.h" #include "llvm/Support/Path.h" #include "llvm/Support/WithColor.h" +namespace llvm { + +const bool IsLLVMDriver = true; + +} + using namespace llvm; #define LLVM_DRIVER_TOOL(tool, entry) int entry##_main(int argc, char **argv); @@ -72,9 +79,4 @@ 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); }