10b57cec5SDimitry Andric //===- Job.cpp - Command to Execute ---------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "clang/Driver/Job.h" 100b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 110b57cec5SDimitry Andric #include "clang/Driver/Driver.h" 120b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 13fe6060f1SDimitry Andric #include "clang/Driver/InputInfo.h" 140b57cec5SDimitry Andric #include "clang/Driver/Tool.h" 150b57cec5SDimitry Andric #include "clang/Driver/ToolChain.h" 160b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 170b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 180b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 1906c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 200b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 210b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h" 220b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 23480093f4SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h" 240b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 250b57cec5SDimitry Andric #include "llvm/Support/Path.h" 26480093f4SDimitry Andric #include "llvm/Support/PrettyStackTrace.h" 270b57cec5SDimitry Andric #include "llvm/Support/Program.h" 280b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 290b57cec5SDimitry Andric #include <algorithm> 300b57cec5SDimitry Andric #include <cassert> 310b57cec5SDimitry Andric #include <cstddef> 320b57cec5SDimitry Andric #include <string> 330b57cec5SDimitry Andric #include <system_error> 340b57cec5SDimitry Andric #include <utility> 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric using namespace clang; 370b57cec5SDimitry Andric using namespace driver; 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric Command::Command(const Action &Source, const Tool &Creator, 405ffd83dbSDimitry Andric ResponseFileSupport ResponseSupport, const char *Executable, 410b57cec5SDimitry Andric const llvm::opt::ArgStringList &Arguments, 4206c3fb27SDimitry Andric ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs, 4306c3fb27SDimitry Andric const char *PrependArg) 445ffd83dbSDimitry Andric : Source(Source), Creator(Creator), ResponseSupport(ResponseSupport), 4506c3fb27SDimitry Andric Executable(Executable), PrependArg(PrependArg), Arguments(Arguments) { 460b57cec5SDimitry Andric for (const auto &II : Inputs) 470b57cec5SDimitry Andric if (II.isFilename()) 48fe6060f1SDimitry Andric InputInfoList.push_back(II); 49e8d8bef9SDimitry Andric for (const auto &II : Outputs) 50e8d8bef9SDimitry Andric if (II.isFilename()) 51e8d8bef9SDimitry Andric OutputFilenames.push_back(II.getFilename()); 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric /// Check if the compiler flag in question should be skipped when 550b57cec5SDimitry Andric /// emitting a reproducer. Also track how many arguments it has and if the 560b57cec5SDimitry Andric /// option is some kind of include path. 570b57cec5SDimitry Andric static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum, 580b57cec5SDimitry Andric bool &IsInclude) { 590b57cec5SDimitry Andric SkipNum = 2; 600b57cec5SDimitry Andric // These flags are all of the form -Flag <Arg> and are treated as two 610b57cec5SDimitry Andric // arguments. Therefore, we need to skip the flag and the next argument. 620b57cec5SDimitry Andric bool ShouldSkip = llvm::StringSwitch<bool>(Flag) 630b57cec5SDimitry Andric .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true) 640b57cec5SDimitry Andric .Cases("-o", "-dependency-file", true) 650b57cec5SDimitry Andric .Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true) 660b57cec5SDimitry Andric .Cases("-dwarf-debug-flags", "-ivfsoverlay", true) 670b57cec5SDimitry Andric .Default(false); 680b57cec5SDimitry Andric if (ShouldSkip) 690b57cec5SDimitry Andric return true; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // Some include flags shouldn't be skipped if we have a crash VFS 720b57cec5SDimitry Andric IsInclude = llvm::StringSwitch<bool>(Flag) 730b57cec5SDimitry Andric .Cases("-include", "-header-include-file", true) 740b57cec5SDimitry Andric .Cases("-idirafter", "-internal-isystem", "-iwithprefix", true) 750b57cec5SDimitry Andric .Cases("-internal-externc-isystem", "-iprefix", true) 760b57cec5SDimitry Andric .Cases("-iwithprefixbefore", "-isystem", "-iquote", true) 770b57cec5SDimitry Andric .Cases("-isysroot", "-I", "-F", "-resource-dir", true) 780b57cec5SDimitry Andric .Cases("-iframework", "-include-pch", true) 790b57cec5SDimitry Andric .Default(false); 800b57cec5SDimitry Andric if (IsInclude) 810b57cec5SDimitry Andric return !HaveCrashVFS; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // The remaining flags are treated as a single argument. 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // These flags are all of the form -Flag and have no second argument. 860b57cec5SDimitry Andric ShouldSkip = llvm::StringSwitch<bool>(Flag) 870b57cec5SDimitry Andric .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) 880b57cec5SDimitry Andric .Case("-MMD", true) 890b57cec5SDimitry Andric .Default(false); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric // Match found. 920b57cec5SDimitry Andric SkipNum = 1; 930b57cec5SDimitry Andric if (ShouldSkip) 940b57cec5SDimitry Andric return true; 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric // These flags are treated as a single argument (e.g., -F<Dir>). 970b57cec5SDimitry Andric StringRef FlagRef(Flag); 98*5f757f3fSDimitry Andric IsInclude = FlagRef.starts_with("-F") || FlagRef.starts_with("-I"); 990b57cec5SDimitry Andric if (IsInclude) 1000b57cec5SDimitry Andric return !HaveCrashVFS; 101*5f757f3fSDimitry Andric if (FlagRef.starts_with("-fmodules-cache-path=")) 1020b57cec5SDimitry Andric return true; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric SkipNum = 0; 1050b57cec5SDimitry Andric return false; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric void Command::writeResponseFile(raw_ostream &OS) const { 1090b57cec5SDimitry Andric // In a file list, we only write the set of inputs to the response file 1105ffd83dbSDimitry Andric if (ResponseSupport.ResponseKind == ResponseFileSupport::RF_FileList) { 1110b57cec5SDimitry Andric for (const auto *Arg : InputFileList) { 1120b57cec5SDimitry Andric OS << Arg << '\n'; 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric return; 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // In regular response files, we send all arguments to the response file. 1180b57cec5SDimitry Andric // Wrapping all arguments in double quotes ensures that both Unix tools and 1190b57cec5SDimitry Andric // Windows tools understand the response file. 1200b57cec5SDimitry Andric for (const auto *Arg : Arguments) { 1210b57cec5SDimitry Andric OS << '"'; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric for (; *Arg != '\0'; Arg++) { 1240b57cec5SDimitry Andric if (*Arg == '\"' || *Arg == '\\') { 1250b57cec5SDimitry Andric OS << '\\'; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric OS << *Arg; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric OS << "\" "; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric void Command::buildArgvForResponseFile( 1350b57cec5SDimitry Andric llvm::SmallVectorImpl<const char *> &Out) const { 1360b57cec5SDimitry Andric // When not a file list, all arguments are sent to the response file. 1370b57cec5SDimitry Andric // This leaves us to set the argv to a single parameter, requesting the tool 1380b57cec5SDimitry Andric // to read the response file. 1395ffd83dbSDimitry Andric if (ResponseSupport.ResponseKind != ResponseFileSupport::RF_FileList) { 1400b57cec5SDimitry Andric Out.push_back(Executable); 1410b57cec5SDimitry Andric Out.push_back(ResponseFileFlag.c_str()); 1420b57cec5SDimitry Andric return; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric llvm::StringSet<> Inputs; 1460b57cec5SDimitry Andric for (const auto *InputName : InputFileList) 1470b57cec5SDimitry Andric Inputs.insert(InputName); 1480b57cec5SDimitry Andric Out.push_back(Executable); 14906c3fb27SDimitry Andric 15006c3fb27SDimitry Andric if (PrependArg) 15106c3fb27SDimitry Andric Out.push_back(PrependArg); 15206c3fb27SDimitry Andric 1530b57cec5SDimitry Andric // In a file list, build args vector ignoring parameters that will go in the 1540b57cec5SDimitry Andric // response file (elements of the InputFileList vector) 1550b57cec5SDimitry Andric bool FirstInput = true; 1560b57cec5SDimitry Andric for (const auto *Arg : Arguments) { 1570b57cec5SDimitry Andric if (Inputs.count(Arg) == 0) { 1580b57cec5SDimitry Andric Out.push_back(Arg); 1590b57cec5SDimitry Andric } else if (FirstInput) { 1600b57cec5SDimitry Andric FirstInput = false; 1615ffd83dbSDimitry Andric Out.push_back(ResponseSupport.ResponseFlag); 1620b57cec5SDimitry Andric Out.push_back(ResponseFile); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric /// Rewrite relative include-like flag paths to absolute ones. 1680b57cec5SDimitry Andric static void 1690b57cec5SDimitry Andric rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx, 1700b57cec5SDimitry Andric size_t NumArgs, 1710b57cec5SDimitry Andric llvm::SmallVectorImpl<llvm::SmallString<128>> &IncFlags) { 1720b57cec5SDimitry Andric using namespace llvm; 1730b57cec5SDimitry Andric using namespace sys; 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric auto getAbsPath = [](StringRef InInc, SmallVectorImpl<char> &OutInc) -> bool { 1760b57cec5SDimitry Andric if (path::is_absolute(InInc)) // Nothing to do here... 1770b57cec5SDimitry Andric return false; 1780b57cec5SDimitry Andric std::error_code EC = fs::current_path(OutInc); 1790b57cec5SDimitry Andric if (EC) 1800b57cec5SDimitry Andric return false; 1810b57cec5SDimitry Andric path::append(OutInc, InInc); 1820b57cec5SDimitry Andric return true; 1830b57cec5SDimitry Andric }; 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric SmallString<128> NewInc; 1860b57cec5SDimitry Andric if (NumArgs == 1) { 1870b57cec5SDimitry Andric StringRef FlagRef(Args[Idx + NumArgs - 1]); 188*5f757f3fSDimitry Andric assert((FlagRef.starts_with("-F") || FlagRef.starts_with("-I")) && 1890b57cec5SDimitry Andric "Expecting -I or -F"); 1900b57cec5SDimitry Andric StringRef Inc = FlagRef.slice(2, StringRef::npos); 1910b57cec5SDimitry Andric if (getAbsPath(Inc, NewInc)) { 1920b57cec5SDimitry Andric SmallString<128> NewArg(FlagRef.slice(0, 2)); 1930b57cec5SDimitry Andric NewArg += NewInc; 1940b57cec5SDimitry Andric IncFlags.push_back(std::move(NewArg)); 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric return; 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric assert(NumArgs == 2 && "Not expecting more than two arguments"); 2000b57cec5SDimitry Andric StringRef Inc(Args[Idx + NumArgs - 1]); 2010b57cec5SDimitry Andric if (!getAbsPath(Inc, NewInc)) 2020b57cec5SDimitry Andric return; 2030b57cec5SDimitry Andric IncFlags.push_back(SmallString<128>(Args[Idx])); 2040b57cec5SDimitry Andric IncFlags.push_back(std::move(NewInc)); 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, 2080b57cec5SDimitry Andric CrashReportInfo *CrashInfo) const { 2090b57cec5SDimitry Andric // Always quote the exe. 2100b57cec5SDimitry Andric OS << ' '; 2115ffd83dbSDimitry Andric llvm::sys::printArg(OS, Executable, /*Quote=*/true); 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric ArrayRef<const char *> Args = Arguments; 2140b57cec5SDimitry Andric SmallVector<const char *, 128> ArgsRespFile; 2150b57cec5SDimitry Andric if (ResponseFile != nullptr) { 2160b57cec5SDimitry Andric buildArgvForResponseFile(ArgsRespFile); 2170b57cec5SDimitry Andric Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name 21806c3fb27SDimitry Andric } else if (PrependArg) { 21906c3fb27SDimitry Andric OS << ' '; 22006c3fb27SDimitry Andric llvm::sys::printArg(OS, PrependArg, /*Quote=*/true); 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty(); 2240b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 2250b57cec5SDimitry Andric const char *const Arg = Args[i]; 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric if (CrashInfo) { 2280b57cec5SDimitry Andric int NumArgs = 0; 2290b57cec5SDimitry Andric bool IsInclude = false; 2300b57cec5SDimitry Andric if (skipArgs(Arg, HaveCrashVFS, NumArgs, IsInclude)) { 2310b57cec5SDimitry Andric i += NumArgs - 1; 2320b57cec5SDimitry Andric continue; 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric // Relative includes need to be expanded to absolute paths. 2360b57cec5SDimitry Andric if (HaveCrashVFS && IsInclude) { 2370b57cec5SDimitry Andric SmallVector<SmallString<128>, 2> NewIncFlags; 2380b57cec5SDimitry Andric rewriteIncludes(Args, i, NumArgs, NewIncFlags); 2390b57cec5SDimitry Andric if (!NewIncFlags.empty()) { 2400b57cec5SDimitry Andric for (auto &F : NewIncFlags) { 2410b57cec5SDimitry Andric OS << ' '; 2425ffd83dbSDimitry Andric llvm::sys::printArg(OS, F.c_str(), Quote); 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric i += NumArgs - 1; 2450b57cec5SDimitry Andric continue; 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric 249fe6060f1SDimitry Andric auto Found = llvm::find_if(InputInfoList, [&Arg](const InputInfo &II) { 250fe6060f1SDimitry Andric return II.getFilename() == Arg; 251fe6060f1SDimitry Andric }); 252fe6060f1SDimitry Andric if (Found != InputInfoList.end() && 2530b57cec5SDimitry Andric (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) { 2540b57cec5SDimitry Andric // Replace the input file name with the crashinfo's file name. 2550b57cec5SDimitry Andric OS << ' '; 2560b57cec5SDimitry Andric StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); 2575ffd83dbSDimitry Andric llvm::sys::printArg(OS, ShortName.str(), Quote); 2580b57cec5SDimitry Andric continue; 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric OS << ' '; 2635ffd83dbSDimitry Andric llvm::sys::printArg(OS, Arg, Quote); 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric if (CrashInfo && HaveCrashVFS) { 2670b57cec5SDimitry Andric OS << ' '; 2685ffd83dbSDimitry Andric llvm::sys::printArg(OS, "-ivfsoverlay", Quote); 2690b57cec5SDimitry Andric OS << ' '; 2705ffd83dbSDimitry Andric llvm::sys::printArg(OS, CrashInfo->VFSPath.str(), Quote); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric // The leftover modules from the crash are stored in 2730b57cec5SDimitry Andric // <name>.cache/vfs/modules 2740b57cec5SDimitry Andric // Leave it untouched for pcm inspection and provide a clean/empty dir 2750b57cec5SDimitry Andric // path to contain the future generated module cache: 2760b57cec5SDimitry Andric // <name>.cache/vfs/repro-modules 2770b57cec5SDimitry Andric SmallString<128> RelModCacheDir = llvm::sys::path::parent_path( 2780b57cec5SDimitry Andric llvm::sys::path::parent_path(CrashInfo->VFSPath)); 2790b57cec5SDimitry Andric llvm::sys::path::append(RelModCacheDir, "repro-modules"); 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric std::string ModCachePath = "-fmodules-cache-path="; 2820b57cec5SDimitry Andric ModCachePath.append(RelModCacheDir.c_str()); 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric OS << ' '; 2855ffd83dbSDimitry Andric llvm::sys::printArg(OS, ModCachePath, Quote); 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric if (ResponseFile != nullptr) { 2890b57cec5SDimitry Andric OS << "\n Arguments passed via response file:\n"; 2900b57cec5SDimitry Andric writeResponseFile(OS); 2910b57cec5SDimitry Andric // Avoiding duplicated newline terminator, since FileLists are 2920b57cec5SDimitry Andric // newline-separated. 2935ffd83dbSDimitry Andric if (ResponseSupport.ResponseKind != ResponseFileSupport::RF_FileList) 2940b57cec5SDimitry Andric OS << "\n"; 2950b57cec5SDimitry Andric OS << " (end of response file)"; 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric OS << Terminator; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric void Command::setResponseFile(const char *FileName) { 3020b57cec5SDimitry Andric ResponseFile = FileName; 3035ffd83dbSDimitry Andric ResponseFileFlag = ResponseSupport.ResponseFlag; 3040b57cec5SDimitry Andric ResponseFileFlag += FileName; 3050b57cec5SDimitry Andric } 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { 3080b57cec5SDimitry Andric Environment.reserve(NewEnvironment.size() + 1); 3090b57cec5SDimitry Andric Environment.assign(NewEnvironment.begin(), NewEnvironment.end()); 3100b57cec5SDimitry Andric Environment.push_back(nullptr); 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 313bdd1243dSDimitry Andric void Command::setRedirectFiles( 314bdd1243dSDimitry Andric const std::vector<std::optional<std::string>> &Redirects) { 315bdd1243dSDimitry Andric RedirectFiles = Redirects; 316bdd1243dSDimitry Andric } 317bdd1243dSDimitry Andric 318480093f4SDimitry Andric void Command::PrintFileNames() const { 3190b57cec5SDimitry Andric if (PrintInputFilenames) { 320fe6060f1SDimitry Andric for (const auto &Arg : InputInfoList) 321fe6060f1SDimitry Andric llvm::outs() << llvm::sys::path::filename(Arg.getFilename()) << "\n"; 3220b57cec5SDimitry Andric llvm::outs().flush(); 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric 326bdd1243dSDimitry Andric int Command::Execute(ArrayRef<std::optional<StringRef>> Redirects, 327480093f4SDimitry Andric std::string *ErrMsg, bool *ExecutionFailed) const { 328480093f4SDimitry Andric PrintFileNames(); 329480093f4SDimitry Andric 330480093f4SDimitry Andric SmallVector<const char *, 128> Argv; 3310b57cec5SDimitry Andric if (ResponseFile == nullptr) { 3320b57cec5SDimitry Andric Argv.push_back(Executable); 33306c3fb27SDimitry Andric if (PrependArg) 33406c3fb27SDimitry Andric Argv.push_back(PrependArg); 3350b57cec5SDimitry Andric Argv.append(Arguments.begin(), Arguments.end()); 3360b57cec5SDimitry Andric Argv.push_back(nullptr); 337480093f4SDimitry Andric } else { 338480093f4SDimitry Andric // If the command is too large, we need to put arguments in a response file. 3390b57cec5SDimitry Andric std::string RespContents; 3400b57cec5SDimitry Andric llvm::raw_string_ostream SS(RespContents); 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric // Write file contents and build the Argv vector 3430b57cec5SDimitry Andric writeResponseFile(SS); 3440b57cec5SDimitry Andric buildArgvForResponseFile(Argv); 3450b57cec5SDimitry Andric Argv.push_back(nullptr); 3460b57cec5SDimitry Andric SS.flush(); 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric // Save the response file in the appropriate encoding 3490b57cec5SDimitry Andric if (std::error_code EC = writeFileWithEncoding( 3505ffd83dbSDimitry Andric ResponseFile, RespContents, ResponseSupport.ResponseEncoding)) { 3510b57cec5SDimitry Andric if (ErrMsg) 3520b57cec5SDimitry Andric *ErrMsg = EC.message(); 3530b57cec5SDimitry Andric if (ExecutionFailed) 3540b57cec5SDimitry Andric *ExecutionFailed = true; 355480093f4SDimitry Andric // Return -1 by convention (see llvm/include/llvm/Support/Program.h) to 356480093f4SDimitry Andric // indicate the requested executable cannot be started. 3570b57cec5SDimitry Andric return -1; 3580b57cec5SDimitry Andric } 359480093f4SDimitry Andric } 360480093f4SDimitry Andric 361bdd1243dSDimitry Andric std::optional<ArrayRef<StringRef>> Env; 362480093f4SDimitry Andric std::vector<StringRef> ArgvVectorStorage; 363480093f4SDimitry Andric if (!Environment.empty()) { 364480093f4SDimitry Andric assert(Environment.back() == nullptr && 365480093f4SDimitry Andric "Environment vector should be null-terminated by now"); 366480093f4SDimitry Andric ArgvVectorStorage = llvm::toStringRefArray(Environment.data()); 367bdd1243dSDimitry Andric Env = ArrayRef(ArgvVectorStorage); 368480093f4SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric auto Args = llvm::toStringRefArray(Argv.data()); 371bdd1243dSDimitry Andric 372bdd1243dSDimitry Andric // Use Job-specific redirect files if they are present. 373bdd1243dSDimitry Andric if (!RedirectFiles.empty()) { 374bdd1243dSDimitry Andric std::vector<std::optional<StringRef>> RedirectFilesOptional; 375bdd1243dSDimitry Andric for (const auto &Ele : RedirectFiles) 376bdd1243dSDimitry Andric if (Ele) 377bdd1243dSDimitry Andric RedirectFilesOptional.push_back(std::optional<StringRef>(*Ele)); 378bdd1243dSDimitry Andric else 379bdd1243dSDimitry Andric RedirectFilesOptional.push_back(std::nullopt); 380bdd1243dSDimitry Andric 381bdd1243dSDimitry Andric return llvm::sys::ExecuteAndWait(Executable, Args, Env, 382bdd1243dSDimitry Andric ArrayRef(RedirectFilesOptional), 383bdd1243dSDimitry Andric /*secondsToWait=*/0, /*memoryLimit=*/0, 384bdd1243dSDimitry Andric ErrMsg, ExecutionFailed, &ProcStat); 385bdd1243dSDimitry Andric } 386bdd1243dSDimitry Andric 3870b57cec5SDimitry Andric return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects, 388e8d8bef9SDimitry Andric /*secondsToWait*/ 0, /*memoryLimit*/ 0, 389e8d8bef9SDimitry Andric ErrMsg, ExecutionFailed, &ProcStat); 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 39213138422SDimitry Andric CC1Command::CC1Command(const Action &Source, const Tool &Creator, 3935ffd83dbSDimitry Andric ResponseFileSupport ResponseSupport, 39413138422SDimitry Andric const char *Executable, 39513138422SDimitry Andric const llvm::opt::ArgStringList &Arguments, 39606c3fb27SDimitry Andric ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs, 39706c3fb27SDimitry Andric const char *PrependArg) 398e8d8bef9SDimitry Andric : Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs, 39906c3fb27SDimitry Andric Outputs, PrependArg) { 40013138422SDimitry Andric InProcess = true; 40113138422SDimitry Andric } 40213138422SDimitry Andric 403480093f4SDimitry Andric void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, 404480093f4SDimitry Andric CrashReportInfo *CrashInfo) const { 40513138422SDimitry Andric if (InProcess) 40655e4f9d5SDimitry Andric OS << " (in-process)\n"; 407480093f4SDimitry Andric Command::Print(OS, Terminator, Quote, CrashInfo); 408480093f4SDimitry Andric } 409480093f4SDimitry Andric 410bdd1243dSDimitry Andric int CC1Command::Execute(ArrayRef<std::optional<StringRef>> Redirects, 411480093f4SDimitry Andric std::string *ErrMsg, bool *ExecutionFailed) const { 41213138422SDimitry Andric // FIXME: Currently, if there're more than one job, we disable 41313138422SDimitry Andric // -fintegrate-cc1. If we're no longer a integrated-cc1 job, fallback to 41413138422SDimitry Andric // out-of-process execution. See discussion in https://reviews.llvm.org/D74447 41513138422SDimitry Andric if (!InProcess) 41613138422SDimitry Andric return Command::Execute(Redirects, ErrMsg, ExecutionFailed); 41713138422SDimitry Andric 418480093f4SDimitry Andric PrintFileNames(); 419480093f4SDimitry Andric 420480093f4SDimitry Andric SmallVector<const char *, 128> Argv; 421480093f4SDimitry Andric Argv.push_back(getExecutable()); 422480093f4SDimitry Andric Argv.append(getArguments().begin(), getArguments().end()); 423480093f4SDimitry Andric Argv.push_back(nullptr); 4240eae32dcSDimitry Andric Argv.pop_back(); // The terminating null element shall not be part of the 4250eae32dcSDimitry Andric // slice (main() behavior). 426480093f4SDimitry Andric 427480093f4SDimitry Andric // This flag simply indicates that the program couldn't start, which isn't 428480093f4SDimitry Andric // applicable here. 429480093f4SDimitry Andric if (ExecutionFailed) 430480093f4SDimitry Andric *ExecutionFailed = false; 431480093f4SDimitry Andric 432480093f4SDimitry Andric llvm::CrashRecoveryContext CRC; 433480093f4SDimitry Andric CRC.DumpStackAndCleanupOnFailure = true; 434480093f4SDimitry Andric 435480093f4SDimitry Andric const void *PrettyState = llvm::SavePrettyStackState(); 436480093f4SDimitry Andric const Driver &D = getCreator().getToolChain().getDriver(); 437480093f4SDimitry Andric 438480093f4SDimitry Andric int R = 0; 439480093f4SDimitry Andric // Enter ExecuteCC1Tool() instead of starting up a new process 440480093f4SDimitry Andric if (!CRC.RunSafely([&]() { R = D.CC1Main(Argv); })) { 441480093f4SDimitry Andric llvm::RestorePrettyStackState(PrettyState); 442480093f4SDimitry Andric return CRC.RetCode; 443480093f4SDimitry Andric } 444480093f4SDimitry Andric return R; 445480093f4SDimitry Andric } 446480093f4SDimitry Andric 447480093f4SDimitry Andric void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { 448480093f4SDimitry Andric // We don't support set a new environment when calling into ExecuteCC1Tool() 449480093f4SDimitry Andric llvm_unreachable( 450480093f4SDimitry Andric "The CC1Command doesn't support changing the environment vars!"); 451480093f4SDimitry Andric } 452480093f4SDimitry Andric 4530b57cec5SDimitry Andric void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, 4540b57cec5SDimitry Andric CrashReportInfo *CrashInfo) const { 4550b57cec5SDimitry Andric for (const auto &Job : *this) 4560b57cec5SDimitry Andric Job.Print(OS, Terminator, Quote, CrashInfo); 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric void JobList::clear() { Jobs.clear(); } 460