Index: clang/include/clang/Driver/Driver.h =================================================================== --- clang/include/clang/Driver/Driver.h +++ clang/include/clang/Driver/Driver.h @@ -278,6 +278,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; @@ -375,6 +381,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 = 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 @@ -199,8 +199,8 @@ DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(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 @@ -5020,7 +5020,7 @@ C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(), - CmdArgs, Inputs, Output)); + CmdArgs, Inputs, Output, D.getLLVMDriverPrependArg())); return; } @@ -7382,13 +7382,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. @@ -8153,13 +8153,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.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 @@ -38,6 +38,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,8 @@ ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); Driver TheDriver(Argv[0], llvm::sys::getDefaultTargetTriple(), Diags); TheDriver.setTargetAndMode(TargetAndMode); + if (llvm::IsLLVMDriver) + TheDriver.setLLVMDriverPrependArg("clang"); 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); + if (llvm::IsLLVMDriver && CanonicalPrefixes) + TheDriver.setLLVMDriverPrependArg("clang"); 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); }