10b57cec5SDimitry Andric //===- Compilation.cpp - Compilation Task Implementation ------------------===//
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/Compilation.h"
100b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
110b57cec5SDimitry Andric #include "clang/Driver/Action.h"
120b57cec5SDimitry Andric #include "clang/Driver/Driver.h"
130b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
140b57cec5SDimitry Andric #include "clang/Driver/Job.h"
150b57cec5SDimitry Andric #include "clang/Driver/Options.h"
160b57cec5SDimitry Andric #include "clang/Driver/ToolChain.h"
170b57cec5SDimitry Andric #include "clang/Driver/Util.h"
180b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
190b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
200b57cec5SDimitry Andric #include "llvm/Option/ArgList.h"
210b57cec5SDimitry Andric #include "llvm/Option/OptSpecifier.h"
220b57cec5SDimitry Andric #include "llvm/Option/Option.h"
230b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
2506c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
260b57cec5SDimitry Andric #include <cassert>
270b57cec5SDimitry Andric #include <string>
280b57cec5SDimitry Andric #include <system_error>
290b57cec5SDimitry Andric #include <utility>
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace clang;
320b57cec5SDimitry Andric using namespace driver;
330b57cec5SDimitry Andric using namespace llvm::opt;
340b57cec5SDimitry Andric 
Compilation(const Driver & D,const ToolChain & _DefaultToolChain,InputArgList * _Args,DerivedArgList * _TranslatedArgs,bool ContainsError)350b57cec5SDimitry Andric Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
360b57cec5SDimitry Andric                          InputArgList *_Args, DerivedArgList *_TranslatedArgs,
370b57cec5SDimitry Andric                          bool ContainsError)
380b57cec5SDimitry Andric     : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
390b57cec5SDimitry Andric       TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {
400b57cec5SDimitry Andric   // The offloading host toolchain is the default toolchain.
410b57cec5SDimitry Andric   OrderedOffloadingToolchains.insert(
420b57cec5SDimitry Andric       std::make_pair(Action::OFK_Host, &DefaultToolChain));
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric 
~Compilation()450b57cec5SDimitry Andric Compilation::~Compilation() {
460b57cec5SDimitry Andric   // Remove temporary files. This must be done before arguments are freed, as
470b57cec5SDimitry Andric   // the file names might be derived from the input arguments.
480b57cec5SDimitry Andric   if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
490b57cec5SDimitry Andric     CleanupFileList(TempFiles);
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   delete TranslatedArgs;
520b57cec5SDimitry Andric   delete Args;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   // Free any derived arg lists.
550b57cec5SDimitry Andric   for (auto Arg : TCArgs)
560b57cec5SDimitry Andric     if (Arg.second != TranslatedArgs)
570b57cec5SDimitry Andric       delete Arg.second;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric const DerivedArgList &
getArgsForToolChain(const ToolChain * TC,StringRef BoundArch,Action::OffloadKind DeviceOffloadKind)610b57cec5SDimitry Andric Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
620b57cec5SDimitry Andric                                  Action::OffloadKind DeviceOffloadKind) {
630b57cec5SDimitry Andric   if (!TC)
640b57cec5SDimitry Andric     TC = &DefaultToolChain;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
670b57cec5SDimitry Andric   if (!Entry) {
680b57cec5SDimitry Andric     SmallVector<Arg *, 4> AllocatedArgs;
690b57cec5SDimitry Andric     DerivedArgList *OpenMPArgs = nullptr;
700b57cec5SDimitry Andric     // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
710b57cec5SDimitry Andric     if (DeviceOffloadKind == Action::OFK_OpenMP) {
720b57cec5SDimitry Andric       const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
730b57cec5SDimitry Andric       bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
740b57cec5SDimitry Andric       OpenMPArgs = TC->TranslateOpenMPTargetArgs(
750b57cec5SDimitry Andric           *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
760b57cec5SDimitry Andric     }
770b57cec5SDimitry Andric 
785ffd83dbSDimitry Andric     DerivedArgList *NewDAL = nullptr;
790b57cec5SDimitry Andric     if (!OpenMPArgs) {
805ffd83dbSDimitry Andric       NewDAL = TC->TranslateXarchArgs(*TranslatedArgs, BoundArch,
815ffd83dbSDimitry Andric                                       DeviceOffloadKind, &AllocatedArgs);
825ffd83dbSDimitry Andric     } else {
835ffd83dbSDimitry Andric       NewDAL = TC->TranslateXarchArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind,
845ffd83dbSDimitry Andric                                       &AllocatedArgs);
855ffd83dbSDimitry Andric       if (!NewDAL)
865ffd83dbSDimitry Andric         NewDAL = OpenMPArgs;
875ffd83dbSDimitry Andric       else
885ffd83dbSDimitry Andric         delete OpenMPArgs;
895ffd83dbSDimitry Andric     }
905ffd83dbSDimitry Andric 
915ffd83dbSDimitry Andric     if (!NewDAL) {
920b57cec5SDimitry Andric       Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
930b57cec5SDimitry Andric       if (!Entry)
940b57cec5SDimitry Andric         Entry = TranslatedArgs;
950b57cec5SDimitry Andric     } else {
965ffd83dbSDimitry Andric       Entry = TC->TranslateArgs(*NewDAL, BoundArch, DeviceOffloadKind);
970b57cec5SDimitry Andric       if (!Entry)
985ffd83dbSDimitry Andric         Entry = NewDAL;
990b57cec5SDimitry Andric       else
1005ffd83dbSDimitry Andric         delete NewDAL;
1010b57cec5SDimitry Andric     }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric     // Add allocated arguments to the final DAL.
104bdd1243dSDimitry Andric     for (auto *ArgPtr : AllocatedArgs)
1050b57cec5SDimitry Andric       Entry->AddSynthesizedArg(ArgPtr);
1060b57cec5SDimitry Andric   }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   return *Entry;
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
CleanupFile(const char * File,bool IssueErrors) const1110b57cec5SDimitry Andric bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
1120b57cec5SDimitry Andric   // FIXME: Why are we trying to remove files that we have not created? For
1130b57cec5SDimitry Andric   // example we should only try to remove a temporary assembly file if
1140b57cec5SDimitry Andric   // "clang -cc1" succeed in writing it. Was this a workaround for when
1150b57cec5SDimitry Andric   // clang was writing directly to a .s file and sometimes leaving it behind
1160b57cec5SDimitry Andric   // during a failure?
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   // FIXME: If this is necessary, we can still try to split
1190b57cec5SDimitry Andric   // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
1200b57cec5SDimitry Andric   // duplicated stat from is_regular_file.
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // Don't try to remove files which we don't have write access to (but may be
1230b57cec5SDimitry Andric   // able to remove), or non-regular files. Underlying tools may have
1240b57cec5SDimitry Andric   // intentionally not overwritten them.
1250b57cec5SDimitry Andric   if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
1260b57cec5SDimitry Andric     return true;
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   if (std::error_code EC = llvm::sys::fs::remove(File)) {
1290b57cec5SDimitry Andric     // Failure is only failure if the file exists and is "regular". We checked
1300b57cec5SDimitry Andric     // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
1310b57cec5SDimitry Andric     // so we don't need to check again.
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric     if (IssueErrors)
1340b57cec5SDimitry Andric       getDriver().Diag(diag::err_drv_unable_to_remove_file)
1350b57cec5SDimitry Andric         << EC.message();
1360b57cec5SDimitry Andric     return false;
1370b57cec5SDimitry Andric   }
1380b57cec5SDimitry Andric   return true;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
CleanupFileList(const llvm::opt::ArgStringList & Files,bool IssueErrors) const1410b57cec5SDimitry Andric bool Compilation::CleanupFileList(const llvm::opt::ArgStringList &Files,
1420b57cec5SDimitry Andric                                   bool IssueErrors) const {
1430b57cec5SDimitry Andric   bool Success = true;
1440b57cec5SDimitry Andric   for (const auto &File: Files)
1450b57cec5SDimitry Andric     Success &= CleanupFile(File, IssueErrors);
1460b57cec5SDimitry Andric   return Success;
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric 
CleanupFileMap(const ArgStringMap & Files,const JobAction * JA,bool IssueErrors) const1490b57cec5SDimitry Andric bool Compilation::CleanupFileMap(const ArgStringMap &Files,
1500b57cec5SDimitry Andric                                  const JobAction *JA,
1510b57cec5SDimitry Andric                                  bool IssueErrors) const {
1520b57cec5SDimitry Andric   bool Success = true;
1530b57cec5SDimitry Andric   for (const auto &File : Files) {
1540b57cec5SDimitry Andric     // If specified, only delete the files associated with the JobAction.
1550b57cec5SDimitry Andric     // Otherwise, delete all files in the map.
1560b57cec5SDimitry Andric     if (JA && File.first != JA)
1570b57cec5SDimitry Andric       continue;
1580b57cec5SDimitry Andric     Success &= CleanupFile(File.second, IssueErrors);
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric   return Success;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
ExecuteCommand(const Command & C,const Command * & FailingCommand,bool LogOnly) const1630b57cec5SDimitry Andric int Compilation::ExecuteCommand(const Command &C,
16481ad6265SDimitry Andric                                 const Command *&FailingCommand,
16581ad6265SDimitry Andric                                 bool LogOnly) const {
1660b57cec5SDimitry Andric   if ((getDriver().CCPrintOptions ||
1670b57cec5SDimitry Andric        getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
1680b57cec5SDimitry Andric     raw_ostream *OS = &llvm::errs();
1690b57cec5SDimitry Andric     std::unique_ptr<llvm::raw_fd_ostream> OwnedStream;
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric     // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
1720b57cec5SDimitry Andric     // output stream.
173fe6060f1SDimitry Andric     if (getDriver().CCPrintOptions &&
174fe6060f1SDimitry Andric         !getDriver().CCPrintOptionsFilename.empty()) {
1750b57cec5SDimitry Andric       std::error_code EC;
1760b57cec5SDimitry Andric       OwnedStream.reset(new llvm::raw_fd_ostream(
177349cc55cSDimitry Andric           getDriver().CCPrintOptionsFilename, EC,
178fe6060f1SDimitry Andric           llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF));
1790b57cec5SDimitry Andric       if (EC) {
1800b57cec5SDimitry Andric         getDriver().Diag(diag::err_drv_cc_print_options_failure)
1810b57cec5SDimitry Andric             << EC.message();
1820b57cec5SDimitry Andric         FailingCommand = &C;
1830b57cec5SDimitry Andric         return 1;
1840b57cec5SDimitry Andric       }
1850b57cec5SDimitry Andric       OS = OwnedStream.get();
1860b57cec5SDimitry Andric     }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric     if (getDriver().CCPrintOptions)
18955e4f9d5SDimitry Andric       *OS << "[Logging clang options]\n";
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric     C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
19481ad6265SDimitry Andric   if (LogOnly)
19581ad6265SDimitry Andric     return 0;
19681ad6265SDimitry Andric 
1970b57cec5SDimitry Andric   std::string Error;
1980b57cec5SDimitry Andric   bool ExecutionFailed;
1990b57cec5SDimitry Andric   int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
200e8d8bef9SDimitry Andric   if (PostCallback)
201e8d8bef9SDimitry Andric     PostCallback(C, Res);
2020b57cec5SDimitry Andric   if (!Error.empty()) {
2030b57cec5SDimitry Andric     assert(Res && "Error string set with 0 result code!");
2040b57cec5SDimitry Andric     getDriver().Diag(diag::err_drv_command_failure) << Error;
2050b57cec5SDimitry Andric   }
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   if (Res)
2080b57cec5SDimitry Andric     FailingCommand = &C;
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   return ExecutionFailed ? 1 : Res;
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;
2140b57cec5SDimitry Andric 
ActionFailed(const Action * A,const FailingCommandList & FailingCommands)2150b57cec5SDimitry Andric static bool ActionFailed(const Action *A,
2160b57cec5SDimitry Andric                          const FailingCommandList &FailingCommands) {
2170b57cec5SDimitry Andric   if (FailingCommands.empty())
2180b57cec5SDimitry Andric     return false;
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   // CUDA/HIP can have the same input source code compiled multiple times so do
2210b57cec5SDimitry Andric   // not compiled again if there are already failures. It is OK to abort the
2220b57cec5SDimitry Andric   // CUDA pipeline on errors.
2230b57cec5SDimitry Andric   if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP))
2240b57cec5SDimitry Andric     return true;
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   for (const auto &CI : FailingCommands)
2270b57cec5SDimitry Andric     if (A == &(CI.second->getSource()))
2280b57cec5SDimitry Andric       return true;
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   for (const auto *AI : A->inputs())
2310b57cec5SDimitry Andric     if (ActionFailed(AI, FailingCommands))
2320b57cec5SDimitry Andric       return true;
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   return false;
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
InputsOk(const Command & C,const FailingCommandList & FailingCommands)2370b57cec5SDimitry Andric static bool InputsOk(const Command &C,
2380b57cec5SDimitry Andric                      const FailingCommandList &FailingCommands) {
2390b57cec5SDimitry Andric   return !ActionFailed(&C.getSource(), FailingCommands);
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
ExecuteJobs(const JobList & Jobs,FailingCommandList & FailingCommands,bool LogOnly) const2420b57cec5SDimitry Andric void Compilation::ExecuteJobs(const JobList &Jobs,
24381ad6265SDimitry Andric                               FailingCommandList &FailingCommands,
24481ad6265SDimitry Andric                               bool LogOnly) const {
2450b57cec5SDimitry Andric   // According to UNIX standard, driver need to continue compiling all the
2460b57cec5SDimitry Andric   // inputs on the command line even one of them failed.
2470b57cec5SDimitry Andric   // In all but CLMode, execute all the jobs unless the necessary inputs for the
2480b57cec5SDimitry Andric   // job is missing due to previous failures.
2490b57cec5SDimitry Andric   for (const auto &Job : Jobs) {
2500b57cec5SDimitry Andric     if (!InputsOk(Job, FailingCommands))
2510b57cec5SDimitry Andric       continue;
2520b57cec5SDimitry Andric     const Command *FailingCommand = nullptr;
25381ad6265SDimitry Andric     if (int Res = ExecuteCommand(Job, FailingCommand, LogOnly)) {
2540b57cec5SDimitry Andric       FailingCommands.push_back(std::make_pair(Res, FailingCommand));
2550b57cec5SDimitry Andric       // Bail as soon as one command fails in cl driver mode.
2560b57cec5SDimitry Andric       if (TheDriver.IsCLMode())
2570b57cec5SDimitry Andric         return;
2580b57cec5SDimitry Andric     }
2590b57cec5SDimitry Andric   }
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric 
initCompilationForDiagnostics()2620b57cec5SDimitry Andric void Compilation::initCompilationForDiagnostics() {
2630b57cec5SDimitry Andric   ForDiagnostics = true;
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   // Free actions and jobs.
2660b57cec5SDimitry Andric   Actions.clear();
2670b57cec5SDimitry Andric   AllActions.clear();
2680b57cec5SDimitry Andric   Jobs.clear();
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   // Remove temporary files.
2710b57cec5SDimitry Andric   if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
2720b57cec5SDimitry Andric     CleanupFileList(TempFiles);
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   // Clear temporary/results file lists.
2750b57cec5SDimitry Andric   TempFiles.clear();
2760b57cec5SDimitry Andric   ResultFiles.clear();
2770b57cec5SDimitry Andric   FailureResultFiles.clear();
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   // Remove any user specified output.  Claim any unclaimed arguments, so as
2800b57cec5SDimitry Andric   // to avoid emitting warnings about unused args.
28113138422SDimitry Andric   OptSpecifier OutputOpts[] = {
28213138422SDimitry Andric       options::OPT_o,  options::OPT_MD, options::OPT_MMD, options::OPT_M,
28313138422SDimitry Andric       options::OPT_MM, options::OPT_MF, options::OPT_MG,  options::OPT_MJ,
28413138422SDimitry Andric       options::OPT_MQ, options::OPT_MT, options::OPT_MV};
285bdd1243dSDimitry Andric   for (const auto &Opt : OutputOpts) {
286bdd1243dSDimitry Andric     if (TranslatedArgs->hasArg(Opt))
287bdd1243dSDimitry Andric       TranslatedArgs->eraseArg(Opt);
2880b57cec5SDimitry Andric   }
2890b57cec5SDimitry Andric   TranslatedArgs->ClaimAllArgs();
2900b57cec5SDimitry Andric 
29113138422SDimitry Andric   // Force re-creation of the toolchain Args, otherwise our modifications just
29213138422SDimitry Andric   // above will have no effect.
29313138422SDimitry Andric   for (auto Arg : TCArgs)
29413138422SDimitry Andric     if (Arg.second != TranslatedArgs)
29513138422SDimitry Andric       delete Arg.second;
29613138422SDimitry Andric   TCArgs.clear();
29713138422SDimitry Andric 
2980b57cec5SDimitry Andric   // Redirect stdout/stderr to /dev/null.
299bdd1243dSDimitry Andric   Redirects = {std::nullopt, {""}, {""}};
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   // Temporary files added by diagnostics should be kept.
3020b57cec5SDimitry Andric   ForceKeepTempFiles = true;
3030b57cec5SDimitry Andric }
3040b57cec5SDimitry Andric 
getSysRoot() const3050b57cec5SDimitry Andric StringRef Compilation::getSysRoot() const {
3060b57cec5SDimitry Andric   return getDriver().SysRoot;
3070b57cec5SDimitry Andric }
3080b57cec5SDimitry Andric 
Redirect(ArrayRef<std::optional<StringRef>> Redirects)309bdd1243dSDimitry Andric void Compilation::Redirect(ArrayRef<std::optional<StringRef>> Redirects) {
3100b57cec5SDimitry Andric   this->Redirects = Redirects;
3110b57cec5SDimitry Andric }
312