17330f729Sjoerg //===- Job.cpp - Command to Execute ---------------------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "clang/Driver/Job.h"
107330f729Sjoerg #include "InputInfo.h"
117330f729Sjoerg #include "clang/Basic/LLVM.h"
127330f729Sjoerg #include "clang/Driver/Driver.h"
137330f729Sjoerg #include "clang/Driver/DriverDiagnostic.h"
147330f729Sjoerg #include "clang/Driver/Tool.h"
157330f729Sjoerg #include "clang/Driver/ToolChain.h"
167330f729Sjoerg #include "llvm/ADT/ArrayRef.h"
177330f729Sjoerg #include "llvm/ADT/SmallString.h"
187330f729Sjoerg #include "llvm/ADT/SmallVector.h"
197330f729Sjoerg #include "llvm/ADT/StringRef.h"
207330f729Sjoerg #include "llvm/ADT/StringSet.h"
217330f729Sjoerg #include "llvm/ADT/StringSwitch.h"
22*e038c9c4Sjoerg #include "llvm/Support/CrashRecoveryContext.h"
237330f729Sjoerg #include "llvm/Support/FileSystem.h"
247330f729Sjoerg #include "llvm/Support/Path.h"
25*e038c9c4Sjoerg #include "llvm/Support/PrettyStackTrace.h"
267330f729Sjoerg #include "llvm/Support/Program.h"
277330f729Sjoerg #include "llvm/Support/raw_ostream.h"
287330f729Sjoerg #include <algorithm>
297330f729Sjoerg #include <cassert>
307330f729Sjoerg #include <cstddef>
317330f729Sjoerg #include <string>
327330f729Sjoerg #include <system_error>
337330f729Sjoerg #include <utility>
347330f729Sjoerg
357330f729Sjoerg using namespace clang;
367330f729Sjoerg using namespace driver;
377330f729Sjoerg
Command(const Action & Source,const Tool & Creator,ResponseFileSupport ResponseSupport,const char * Executable,const llvm::opt::ArgStringList & Arguments,ArrayRef<InputInfo> Inputs,ArrayRef<InputInfo> Outputs)387330f729Sjoerg Command::Command(const Action &Source, const Tool &Creator,
39*e038c9c4Sjoerg ResponseFileSupport ResponseSupport, const char *Executable,
407330f729Sjoerg const llvm::opt::ArgStringList &Arguments,
41*e038c9c4Sjoerg ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs)
42*e038c9c4Sjoerg : Source(Source), Creator(Creator), ResponseSupport(ResponseSupport),
43*e038c9c4Sjoerg Executable(Executable), Arguments(Arguments) {
447330f729Sjoerg for (const auto &II : Inputs)
457330f729Sjoerg if (II.isFilename())
467330f729Sjoerg InputFilenames.push_back(II.getFilename());
47*e038c9c4Sjoerg for (const auto &II : Outputs)
48*e038c9c4Sjoerg if (II.isFilename())
49*e038c9c4Sjoerg OutputFilenames.push_back(II.getFilename());
507330f729Sjoerg }
517330f729Sjoerg
527330f729Sjoerg /// Check if the compiler flag in question should be skipped when
537330f729Sjoerg /// emitting a reproducer. Also track how many arguments it has and if the
547330f729Sjoerg /// option is some kind of include path.
skipArgs(const char * Flag,bool HaveCrashVFS,int & SkipNum,bool & IsInclude)557330f729Sjoerg static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum,
567330f729Sjoerg bool &IsInclude) {
577330f729Sjoerg SkipNum = 2;
587330f729Sjoerg // These flags are all of the form -Flag <Arg> and are treated as two
597330f729Sjoerg // arguments. Therefore, we need to skip the flag and the next argument.
607330f729Sjoerg bool ShouldSkip = llvm::StringSwitch<bool>(Flag)
617330f729Sjoerg .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true)
627330f729Sjoerg .Cases("-o", "-dependency-file", true)
637330f729Sjoerg .Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true)
647330f729Sjoerg .Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
657330f729Sjoerg .Default(false);
667330f729Sjoerg if (ShouldSkip)
677330f729Sjoerg return true;
687330f729Sjoerg
697330f729Sjoerg // Some include flags shouldn't be skipped if we have a crash VFS
707330f729Sjoerg IsInclude = llvm::StringSwitch<bool>(Flag)
717330f729Sjoerg .Cases("-include", "-header-include-file", true)
727330f729Sjoerg .Cases("-idirafter", "-internal-isystem", "-iwithprefix", true)
737330f729Sjoerg .Cases("-internal-externc-isystem", "-iprefix", true)
747330f729Sjoerg .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
757330f729Sjoerg .Cases("-isysroot", "-I", "-F", "-resource-dir", true)
767330f729Sjoerg .Cases("-iframework", "-include-pch", true)
777330f729Sjoerg .Default(false);
787330f729Sjoerg if (IsInclude)
797330f729Sjoerg return !HaveCrashVFS;
807330f729Sjoerg
817330f729Sjoerg // The remaining flags are treated as a single argument.
827330f729Sjoerg
837330f729Sjoerg // These flags are all of the form -Flag and have no second argument.
847330f729Sjoerg ShouldSkip = llvm::StringSwitch<bool>(Flag)
857330f729Sjoerg .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
867330f729Sjoerg .Case("-MMD", true)
877330f729Sjoerg .Default(false);
887330f729Sjoerg
897330f729Sjoerg // Match found.
907330f729Sjoerg SkipNum = 1;
917330f729Sjoerg if (ShouldSkip)
927330f729Sjoerg return true;
937330f729Sjoerg
947330f729Sjoerg // These flags are treated as a single argument (e.g., -F<Dir>).
957330f729Sjoerg StringRef FlagRef(Flag);
967330f729Sjoerg IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I");
977330f729Sjoerg if (IsInclude)
987330f729Sjoerg return !HaveCrashVFS;
997330f729Sjoerg if (FlagRef.startswith("-fmodules-cache-path="))
1007330f729Sjoerg return true;
1017330f729Sjoerg
1027330f729Sjoerg SkipNum = 0;
1037330f729Sjoerg return false;
1047330f729Sjoerg }
1057330f729Sjoerg
writeResponseFile(raw_ostream & OS) const1067330f729Sjoerg void Command::writeResponseFile(raw_ostream &OS) const {
1077330f729Sjoerg // In a file list, we only write the set of inputs to the response file
108*e038c9c4Sjoerg if (ResponseSupport.ResponseKind == ResponseFileSupport::RF_FileList) {
1097330f729Sjoerg for (const auto *Arg : InputFileList) {
1107330f729Sjoerg OS << Arg << '\n';
1117330f729Sjoerg }
1127330f729Sjoerg return;
1137330f729Sjoerg }
1147330f729Sjoerg
1157330f729Sjoerg // In regular response files, we send all arguments to the response file.
1167330f729Sjoerg // Wrapping all arguments in double quotes ensures that both Unix tools and
1177330f729Sjoerg // Windows tools understand the response file.
1187330f729Sjoerg for (const auto *Arg : Arguments) {
1197330f729Sjoerg OS << '"';
1207330f729Sjoerg
1217330f729Sjoerg for (; *Arg != '\0'; Arg++) {
1227330f729Sjoerg if (*Arg == '\"' || *Arg == '\\') {
1237330f729Sjoerg OS << '\\';
1247330f729Sjoerg }
1257330f729Sjoerg OS << *Arg;
1267330f729Sjoerg }
1277330f729Sjoerg
1287330f729Sjoerg OS << "\" ";
1297330f729Sjoerg }
1307330f729Sjoerg }
1317330f729Sjoerg
buildArgvForResponseFile(llvm::SmallVectorImpl<const char * > & Out) const1327330f729Sjoerg void Command::buildArgvForResponseFile(
1337330f729Sjoerg llvm::SmallVectorImpl<const char *> &Out) const {
1347330f729Sjoerg // When not a file list, all arguments are sent to the response file.
1357330f729Sjoerg // This leaves us to set the argv to a single parameter, requesting the tool
1367330f729Sjoerg // to read the response file.
137*e038c9c4Sjoerg if (ResponseSupport.ResponseKind != ResponseFileSupport::RF_FileList) {
1387330f729Sjoerg Out.push_back(Executable);
1397330f729Sjoerg Out.push_back(ResponseFileFlag.c_str());
1407330f729Sjoerg return;
1417330f729Sjoerg }
1427330f729Sjoerg
1437330f729Sjoerg llvm::StringSet<> Inputs;
1447330f729Sjoerg for (const auto *InputName : InputFileList)
1457330f729Sjoerg Inputs.insert(InputName);
1467330f729Sjoerg Out.push_back(Executable);
1477330f729Sjoerg // In a file list, build args vector ignoring parameters that will go in the
1487330f729Sjoerg // response file (elements of the InputFileList vector)
1497330f729Sjoerg bool FirstInput = true;
1507330f729Sjoerg for (const auto *Arg : Arguments) {
1517330f729Sjoerg if (Inputs.count(Arg) == 0) {
1527330f729Sjoerg Out.push_back(Arg);
1537330f729Sjoerg } else if (FirstInput) {
1547330f729Sjoerg FirstInput = false;
155*e038c9c4Sjoerg Out.push_back(ResponseSupport.ResponseFlag);
1567330f729Sjoerg Out.push_back(ResponseFile);
1577330f729Sjoerg }
1587330f729Sjoerg }
1597330f729Sjoerg }
1607330f729Sjoerg
1617330f729Sjoerg /// Rewrite relative include-like flag paths to absolute ones.
1627330f729Sjoerg static void
rewriteIncludes(const llvm::ArrayRef<const char * > & Args,size_t Idx,size_t NumArgs,llvm::SmallVectorImpl<llvm::SmallString<128>> & IncFlags)1637330f729Sjoerg rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx,
1647330f729Sjoerg size_t NumArgs,
1657330f729Sjoerg llvm::SmallVectorImpl<llvm::SmallString<128>> &IncFlags) {
1667330f729Sjoerg using namespace llvm;
1677330f729Sjoerg using namespace sys;
1687330f729Sjoerg
1697330f729Sjoerg auto getAbsPath = [](StringRef InInc, SmallVectorImpl<char> &OutInc) -> bool {
1707330f729Sjoerg if (path::is_absolute(InInc)) // Nothing to do here...
1717330f729Sjoerg return false;
1727330f729Sjoerg std::error_code EC = fs::current_path(OutInc);
1737330f729Sjoerg if (EC)
1747330f729Sjoerg return false;
1757330f729Sjoerg path::append(OutInc, InInc);
1767330f729Sjoerg return true;
1777330f729Sjoerg };
1787330f729Sjoerg
1797330f729Sjoerg SmallString<128> NewInc;
1807330f729Sjoerg if (NumArgs == 1) {
1817330f729Sjoerg StringRef FlagRef(Args[Idx + NumArgs - 1]);
1827330f729Sjoerg assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) &&
1837330f729Sjoerg "Expecting -I or -F");
1847330f729Sjoerg StringRef Inc = FlagRef.slice(2, StringRef::npos);
1857330f729Sjoerg if (getAbsPath(Inc, NewInc)) {
1867330f729Sjoerg SmallString<128> NewArg(FlagRef.slice(0, 2));
1877330f729Sjoerg NewArg += NewInc;
1887330f729Sjoerg IncFlags.push_back(std::move(NewArg));
1897330f729Sjoerg }
1907330f729Sjoerg return;
1917330f729Sjoerg }
1927330f729Sjoerg
1937330f729Sjoerg assert(NumArgs == 2 && "Not expecting more than two arguments");
1947330f729Sjoerg StringRef Inc(Args[Idx + NumArgs - 1]);
1957330f729Sjoerg if (!getAbsPath(Inc, NewInc))
1967330f729Sjoerg return;
1977330f729Sjoerg IncFlags.push_back(SmallString<128>(Args[Idx]));
1987330f729Sjoerg IncFlags.push_back(std::move(NewInc));
1997330f729Sjoerg }
2007330f729Sjoerg
Print(raw_ostream & OS,const char * Terminator,bool Quote,CrashReportInfo * CrashInfo) const2017330f729Sjoerg void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
2027330f729Sjoerg CrashReportInfo *CrashInfo) const {
2037330f729Sjoerg // Always quote the exe.
2047330f729Sjoerg OS << ' ';
205*e038c9c4Sjoerg llvm::sys::printArg(OS, Executable, /*Quote=*/true);
2067330f729Sjoerg
2077330f729Sjoerg ArrayRef<const char *> Args = Arguments;
2087330f729Sjoerg SmallVector<const char *, 128> ArgsRespFile;
2097330f729Sjoerg if (ResponseFile != nullptr) {
2107330f729Sjoerg buildArgvForResponseFile(ArgsRespFile);
2117330f729Sjoerg Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
2127330f729Sjoerg }
2137330f729Sjoerg
2147330f729Sjoerg bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
2157330f729Sjoerg for (size_t i = 0, e = Args.size(); i < e; ++i) {
2167330f729Sjoerg const char *const Arg = Args[i];
2177330f729Sjoerg
2187330f729Sjoerg if (CrashInfo) {
2197330f729Sjoerg int NumArgs = 0;
2207330f729Sjoerg bool IsInclude = false;
2217330f729Sjoerg if (skipArgs(Arg, HaveCrashVFS, NumArgs, IsInclude)) {
2227330f729Sjoerg i += NumArgs - 1;
2237330f729Sjoerg continue;
2247330f729Sjoerg }
2257330f729Sjoerg
2267330f729Sjoerg // Relative includes need to be expanded to absolute paths.
2277330f729Sjoerg if (HaveCrashVFS && IsInclude) {
2287330f729Sjoerg SmallVector<SmallString<128>, 2> NewIncFlags;
2297330f729Sjoerg rewriteIncludes(Args, i, NumArgs, NewIncFlags);
2307330f729Sjoerg if (!NewIncFlags.empty()) {
2317330f729Sjoerg for (auto &F : NewIncFlags) {
2327330f729Sjoerg OS << ' ';
233*e038c9c4Sjoerg llvm::sys::printArg(OS, F.c_str(), Quote);
2347330f729Sjoerg }
2357330f729Sjoerg i += NumArgs - 1;
2367330f729Sjoerg continue;
2377330f729Sjoerg }
2387330f729Sjoerg }
2397330f729Sjoerg
2407330f729Sjoerg auto Found = llvm::find_if(InputFilenames,
2417330f729Sjoerg [&Arg](StringRef IF) { return IF == Arg; });
2427330f729Sjoerg if (Found != InputFilenames.end() &&
2437330f729Sjoerg (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
2447330f729Sjoerg // Replace the input file name with the crashinfo's file name.
2457330f729Sjoerg OS << ' ';
2467330f729Sjoerg StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
247*e038c9c4Sjoerg llvm::sys::printArg(OS, ShortName.str(), Quote);
2487330f729Sjoerg continue;
2497330f729Sjoerg }
2507330f729Sjoerg }
2517330f729Sjoerg
2527330f729Sjoerg OS << ' ';
253*e038c9c4Sjoerg llvm::sys::printArg(OS, Arg, Quote);
2547330f729Sjoerg }
2557330f729Sjoerg
2567330f729Sjoerg if (CrashInfo && HaveCrashVFS) {
2577330f729Sjoerg OS << ' ';
258*e038c9c4Sjoerg llvm::sys::printArg(OS, "-ivfsoverlay", Quote);
2597330f729Sjoerg OS << ' ';
260*e038c9c4Sjoerg llvm::sys::printArg(OS, CrashInfo->VFSPath.str(), Quote);
2617330f729Sjoerg
2627330f729Sjoerg // The leftover modules from the crash are stored in
2637330f729Sjoerg // <name>.cache/vfs/modules
2647330f729Sjoerg // Leave it untouched for pcm inspection and provide a clean/empty dir
2657330f729Sjoerg // path to contain the future generated module cache:
2667330f729Sjoerg // <name>.cache/vfs/repro-modules
2677330f729Sjoerg SmallString<128> RelModCacheDir = llvm::sys::path::parent_path(
2687330f729Sjoerg llvm::sys::path::parent_path(CrashInfo->VFSPath));
2697330f729Sjoerg llvm::sys::path::append(RelModCacheDir, "repro-modules");
2707330f729Sjoerg
2717330f729Sjoerg std::string ModCachePath = "-fmodules-cache-path=";
2727330f729Sjoerg ModCachePath.append(RelModCacheDir.c_str());
2737330f729Sjoerg
2747330f729Sjoerg OS << ' ';
275*e038c9c4Sjoerg llvm::sys::printArg(OS, ModCachePath, Quote);
2767330f729Sjoerg }
2777330f729Sjoerg
2787330f729Sjoerg if (ResponseFile != nullptr) {
2797330f729Sjoerg OS << "\n Arguments passed via response file:\n";
2807330f729Sjoerg writeResponseFile(OS);
2817330f729Sjoerg // Avoiding duplicated newline terminator, since FileLists are
2827330f729Sjoerg // newline-separated.
283*e038c9c4Sjoerg if (ResponseSupport.ResponseKind != ResponseFileSupport::RF_FileList)
2847330f729Sjoerg OS << "\n";
2857330f729Sjoerg OS << " (end of response file)";
2867330f729Sjoerg }
2877330f729Sjoerg
2887330f729Sjoerg OS << Terminator;
2897330f729Sjoerg }
2907330f729Sjoerg
setResponseFile(const char * FileName)2917330f729Sjoerg void Command::setResponseFile(const char *FileName) {
2927330f729Sjoerg ResponseFile = FileName;
293*e038c9c4Sjoerg ResponseFileFlag = ResponseSupport.ResponseFlag;
2947330f729Sjoerg ResponseFileFlag += FileName;
2957330f729Sjoerg }
2967330f729Sjoerg
setEnvironment(llvm::ArrayRef<const char * > NewEnvironment)2977330f729Sjoerg void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
2987330f729Sjoerg Environment.reserve(NewEnvironment.size() + 1);
2997330f729Sjoerg Environment.assign(NewEnvironment.begin(), NewEnvironment.end());
3007330f729Sjoerg Environment.push_back(nullptr);
3017330f729Sjoerg }
3027330f729Sjoerg
PrintFileNames() const303*e038c9c4Sjoerg void Command::PrintFileNames() const {
3047330f729Sjoerg if (PrintInputFilenames) {
3057330f729Sjoerg for (const char *Arg : InputFilenames)
3067330f729Sjoerg llvm::outs() << llvm::sys::path::filename(Arg) << "\n";
3077330f729Sjoerg llvm::outs().flush();
3087330f729Sjoerg }
3097330f729Sjoerg }
3107330f729Sjoerg
Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,std::string * ErrMsg,bool * ExecutionFailed) const311*e038c9c4Sjoerg int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
312*e038c9c4Sjoerg std::string *ErrMsg, bool *ExecutionFailed) const {
313*e038c9c4Sjoerg PrintFileNames();
314*e038c9c4Sjoerg
315*e038c9c4Sjoerg SmallVector<const char *, 128> Argv;
3167330f729Sjoerg if (ResponseFile == nullptr) {
3177330f729Sjoerg Argv.push_back(Executable);
3187330f729Sjoerg Argv.append(Arguments.begin(), Arguments.end());
3197330f729Sjoerg Argv.push_back(nullptr);
320*e038c9c4Sjoerg } else {
321*e038c9c4Sjoerg // If the command is too large, we need to put arguments in a response file.
3227330f729Sjoerg std::string RespContents;
3237330f729Sjoerg llvm::raw_string_ostream SS(RespContents);
3247330f729Sjoerg
3257330f729Sjoerg // Write file contents and build the Argv vector
3267330f729Sjoerg writeResponseFile(SS);
3277330f729Sjoerg buildArgvForResponseFile(Argv);
3287330f729Sjoerg Argv.push_back(nullptr);
3297330f729Sjoerg SS.flush();
3307330f729Sjoerg
3317330f729Sjoerg // Save the response file in the appropriate encoding
3327330f729Sjoerg if (std::error_code EC = writeFileWithEncoding(
333*e038c9c4Sjoerg ResponseFile, RespContents, ResponseSupport.ResponseEncoding)) {
3347330f729Sjoerg if (ErrMsg)
3357330f729Sjoerg *ErrMsg = EC.message();
3367330f729Sjoerg if (ExecutionFailed)
3377330f729Sjoerg *ExecutionFailed = true;
338*e038c9c4Sjoerg // Return -1 by convention (see llvm/include/llvm/Support/Program.h) to
339*e038c9c4Sjoerg // indicate the requested executable cannot be started.
3407330f729Sjoerg return -1;
3417330f729Sjoerg }
342*e038c9c4Sjoerg }
343*e038c9c4Sjoerg
344*e038c9c4Sjoerg Optional<ArrayRef<StringRef>> Env;
345*e038c9c4Sjoerg std::vector<StringRef> ArgvVectorStorage;
346*e038c9c4Sjoerg if (!Environment.empty()) {
347*e038c9c4Sjoerg assert(Environment.back() == nullptr &&
348*e038c9c4Sjoerg "Environment vector should be null-terminated by now");
349*e038c9c4Sjoerg ArgvVectorStorage = llvm::toStringRefArray(Environment.data());
350*e038c9c4Sjoerg Env = makeArrayRef(ArgvVectorStorage);
351*e038c9c4Sjoerg }
3527330f729Sjoerg
3537330f729Sjoerg auto Args = llvm::toStringRefArray(Argv.data());
3547330f729Sjoerg return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects,
355*e038c9c4Sjoerg /*secondsToWait*/ 0, /*memoryLimit*/ 0,
356*e038c9c4Sjoerg ErrMsg, ExecutionFailed, &ProcStat);
3577330f729Sjoerg }
3587330f729Sjoerg
CC1Command(const Action & Source,const Tool & Creator,ResponseFileSupport ResponseSupport,const char * Executable,const llvm::opt::ArgStringList & Arguments,ArrayRef<InputInfo> Inputs,ArrayRef<InputInfo> Outputs)359*e038c9c4Sjoerg CC1Command::CC1Command(const Action &Source, const Tool &Creator,
360*e038c9c4Sjoerg ResponseFileSupport ResponseSupport,
361*e038c9c4Sjoerg const char *Executable,
362*e038c9c4Sjoerg const llvm::opt::ArgStringList &Arguments,
363*e038c9c4Sjoerg ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs)
364*e038c9c4Sjoerg : Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs,
365*e038c9c4Sjoerg Outputs) {
366*e038c9c4Sjoerg InProcess = true;
3677330f729Sjoerg }
3687330f729Sjoerg
Print(raw_ostream & OS,const char * Terminator,bool Quote,CrashReportInfo * CrashInfo) const369*e038c9c4Sjoerg void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
370*e038c9c4Sjoerg CrashReportInfo *CrashInfo) const {
371*e038c9c4Sjoerg if (InProcess)
372*e038c9c4Sjoerg OS << " (in-process)\n";
373*e038c9c4Sjoerg Command::Print(OS, Terminator, Quote, CrashInfo);
3747330f729Sjoerg }
3757330f729Sjoerg
Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,std::string * ErrMsg,bool * ExecutionFailed) const376*e038c9c4Sjoerg int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
3777330f729Sjoerg std::string *ErrMsg, bool *ExecutionFailed) const {
378*e038c9c4Sjoerg // FIXME: Currently, if there're more than one job, we disable
379*e038c9c4Sjoerg // -fintegrate-cc1. If we're no longer a integrated-cc1 job, fallback to
380*e038c9c4Sjoerg // out-of-process execution. See discussion in https://reviews.llvm.org/D74447
381*e038c9c4Sjoerg if (!InProcess)
382*e038c9c4Sjoerg return Command::Execute(Redirects, ErrMsg, ExecutionFailed);
3837330f729Sjoerg
384*e038c9c4Sjoerg PrintFileNames();
385*e038c9c4Sjoerg
386*e038c9c4Sjoerg SmallVector<const char *, 128> Argv;
387*e038c9c4Sjoerg Argv.push_back(getExecutable());
388*e038c9c4Sjoerg Argv.append(getArguments().begin(), getArguments().end());
389*e038c9c4Sjoerg Argv.push_back(nullptr);
390*e038c9c4Sjoerg
391*e038c9c4Sjoerg // This flag simply indicates that the program couldn't start, which isn't
392*e038c9c4Sjoerg // applicable here.
3937330f729Sjoerg if (ExecutionFailed)
3947330f729Sjoerg *ExecutionFailed = false;
3957330f729Sjoerg
396*e038c9c4Sjoerg llvm::CrashRecoveryContext CRC;
397*e038c9c4Sjoerg CRC.DumpStackAndCleanupOnFailure = true;
3987330f729Sjoerg
399*e038c9c4Sjoerg const void *PrettyState = llvm::SavePrettyStackState();
400*e038c9c4Sjoerg const Driver &D = getCreator().getToolChain().getDriver();
401*e038c9c4Sjoerg
402*e038c9c4Sjoerg int R = 0;
403*e038c9c4Sjoerg // Enter ExecuteCC1Tool() instead of starting up a new process
404*e038c9c4Sjoerg if (!CRC.RunSafely([&]() { R = D.CC1Main(Argv); })) {
405*e038c9c4Sjoerg llvm::RestorePrettyStackState(PrettyState);
406*e038c9c4Sjoerg return CRC.RetCode;
407*e038c9c4Sjoerg }
408*e038c9c4Sjoerg return R;
409*e038c9c4Sjoerg }
410*e038c9c4Sjoerg
setEnvironment(llvm::ArrayRef<const char * > NewEnvironment)411*e038c9c4Sjoerg void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
412*e038c9c4Sjoerg // We don't support set a new environment when calling into ExecuteCC1Tool()
413*e038c9c4Sjoerg llvm_unreachable(
414*e038c9c4Sjoerg "The CC1Command doesn't support changing the environment vars!");
4157330f729Sjoerg }
4167330f729Sjoerg
ForceSuccessCommand(const Action & Source_,const Tool & Creator_,ResponseFileSupport ResponseSupport,const char * Executable_,const llvm::opt::ArgStringList & Arguments_,ArrayRef<InputInfo> Inputs,ArrayRef<InputInfo> Outputs)4177330f729Sjoerg ForceSuccessCommand::ForceSuccessCommand(
418*e038c9c4Sjoerg const Action &Source_, const Tool &Creator_,
419*e038c9c4Sjoerg ResponseFileSupport ResponseSupport, const char *Executable_,
420*e038c9c4Sjoerg const llvm::opt::ArgStringList &Arguments_, ArrayRef<InputInfo> Inputs,
421*e038c9c4Sjoerg ArrayRef<InputInfo> Outputs)
422*e038c9c4Sjoerg : Command(Source_, Creator_, ResponseSupport, Executable_, Arguments_,
423*e038c9c4Sjoerg Inputs, Outputs) {}
4247330f729Sjoerg
Print(raw_ostream & OS,const char * Terminator,bool Quote,CrashReportInfo * CrashInfo) const4257330f729Sjoerg void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator,
4267330f729Sjoerg bool Quote, CrashReportInfo *CrashInfo) const {
4277330f729Sjoerg Command::Print(OS, "", Quote, CrashInfo);
4287330f729Sjoerg OS << " || (exit 0)" << Terminator;
4297330f729Sjoerg }
4307330f729Sjoerg
Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,std::string * ErrMsg,bool * ExecutionFailed) const4317330f729Sjoerg int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
4327330f729Sjoerg std::string *ErrMsg,
4337330f729Sjoerg bool *ExecutionFailed) const {
4347330f729Sjoerg int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
4357330f729Sjoerg (void)Status;
4367330f729Sjoerg if (ExecutionFailed)
4377330f729Sjoerg *ExecutionFailed = false;
4387330f729Sjoerg return 0;
4397330f729Sjoerg }
4407330f729Sjoerg
Print(raw_ostream & OS,const char * Terminator,bool Quote,CrashReportInfo * CrashInfo) const4417330f729Sjoerg void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
4427330f729Sjoerg CrashReportInfo *CrashInfo) const {
4437330f729Sjoerg for (const auto &Job : *this)
4447330f729Sjoerg Job.Print(OS, Terminator, Quote, CrashInfo);
4457330f729Sjoerg }
4467330f729Sjoerg
clear()4477330f729Sjoerg void JobList::clear() { Jobs.clear(); }
448