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/None.h"
190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
210b57cec5SDimitry Andric #include "llvm/ADT/Triple.h"
220b57cec5SDimitry Andric #include "llvm/Option/ArgList.h"
230b57cec5SDimitry Andric #include "llvm/Option/OptSpecifier.h"
240b57cec5SDimitry Andric #include "llvm/Option/Option.h"
250b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
270b57cec5SDimitry Andric #include <cassert>
280b57cec5SDimitry Andric #include <string>
290b57cec5SDimitry Andric #include <system_error>
300b57cec5SDimitry Andric #include <utility>
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric using namespace clang;
330b57cec5SDimitry Andric using namespace driver;
340b57cec5SDimitry Andric using namespace llvm::opt;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
370b57cec5SDimitry Andric                          InputArgList *_Args, DerivedArgList *_TranslatedArgs,
380b57cec5SDimitry Andric                          bool ContainsError)
390b57cec5SDimitry Andric     : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
400b57cec5SDimitry Andric       TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {
410b57cec5SDimitry Andric   // The offloading host toolchain is the default toolchain.
420b57cec5SDimitry Andric   OrderedOffloadingToolchains.insert(
430b57cec5SDimitry Andric       std::make_pair(Action::OFK_Host, &DefaultToolChain));
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric Compilation::~Compilation() {
470b57cec5SDimitry Andric   // Remove temporary files. This must be done before arguments are freed, as
480b57cec5SDimitry Andric   // the file names might be derived from the input arguments.
490b57cec5SDimitry Andric   if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
500b57cec5SDimitry Andric     CleanupFileList(TempFiles);
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   delete TranslatedArgs;
530b57cec5SDimitry Andric   delete Args;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   // Free any derived arg lists.
560b57cec5SDimitry Andric   for (auto Arg : TCArgs)
570b57cec5SDimitry Andric     if (Arg.second != TranslatedArgs)
580b57cec5SDimitry Andric       delete Arg.second;
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric const DerivedArgList &
620b57cec5SDimitry Andric Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
630b57cec5SDimitry Andric                                  Action::OffloadKind DeviceOffloadKind) {
640b57cec5SDimitry Andric   if (!TC)
650b57cec5SDimitry Andric     TC = &DefaultToolChain;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
680b57cec5SDimitry Andric   if (!Entry) {
690b57cec5SDimitry Andric     SmallVector<Arg *, 4> AllocatedArgs;
700b57cec5SDimitry Andric     DerivedArgList *OpenMPArgs = nullptr;
710b57cec5SDimitry Andric     // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
720b57cec5SDimitry Andric     if (DeviceOffloadKind == Action::OFK_OpenMP) {
730b57cec5SDimitry Andric       const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
740b57cec5SDimitry Andric       bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
750b57cec5SDimitry Andric       OpenMPArgs = TC->TranslateOpenMPTargetArgs(
760b57cec5SDimitry Andric           *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
770b57cec5SDimitry Andric     }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric     if (!OpenMPArgs) {
800b57cec5SDimitry Andric       Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
810b57cec5SDimitry Andric       if (!Entry)
820b57cec5SDimitry Andric         Entry = TranslatedArgs;
830b57cec5SDimitry Andric     } else {
840b57cec5SDimitry Andric       Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind);
850b57cec5SDimitry Andric       if (!Entry)
860b57cec5SDimitry Andric         Entry = OpenMPArgs;
870b57cec5SDimitry Andric       else
880b57cec5SDimitry Andric         delete OpenMPArgs;
890b57cec5SDimitry Andric     }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric     // Add allocated arguments to the final DAL.
920b57cec5SDimitry Andric     for (auto ArgPtr : AllocatedArgs)
930b57cec5SDimitry Andric       Entry->AddSynthesizedArg(ArgPtr);
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   return *Entry;
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
1000b57cec5SDimitry Andric   // FIXME: Why are we trying to remove files that we have not created? For
1010b57cec5SDimitry Andric   // example we should only try to remove a temporary assembly file if
1020b57cec5SDimitry Andric   // "clang -cc1" succeed in writing it. Was this a workaround for when
1030b57cec5SDimitry Andric   // clang was writing directly to a .s file and sometimes leaving it behind
1040b57cec5SDimitry Andric   // during a failure?
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   // FIXME: If this is necessary, we can still try to split
1070b57cec5SDimitry Andric   // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
1080b57cec5SDimitry Andric   // duplicated stat from is_regular_file.
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   // Don't try to remove files which we don't have write access to (but may be
1110b57cec5SDimitry Andric   // able to remove), or non-regular files. Underlying tools may have
1120b57cec5SDimitry Andric   // intentionally not overwritten them.
1130b57cec5SDimitry Andric   if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
1140b57cec5SDimitry Andric     return true;
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   if (std::error_code EC = llvm::sys::fs::remove(File)) {
1170b57cec5SDimitry Andric     // Failure is only failure if the file exists and is "regular". We checked
1180b57cec5SDimitry Andric     // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
1190b57cec5SDimitry Andric     // so we don't need to check again.
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric     if (IssueErrors)
1220b57cec5SDimitry Andric       getDriver().Diag(diag::err_drv_unable_to_remove_file)
1230b57cec5SDimitry Andric         << EC.message();
1240b57cec5SDimitry Andric     return false;
1250b57cec5SDimitry Andric   }
1260b57cec5SDimitry Andric   return true;
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric bool Compilation::CleanupFileList(const llvm::opt::ArgStringList &Files,
1300b57cec5SDimitry Andric                                   bool IssueErrors) const {
1310b57cec5SDimitry Andric   bool Success = true;
1320b57cec5SDimitry Andric   for (const auto &File: Files)
1330b57cec5SDimitry Andric     Success &= CleanupFile(File, IssueErrors);
1340b57cec5SDimitry Andric   return Success;
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric bool Compilation::CleanupFileMap(const ArgStringMap &Files,
1380b57cec5SDimitry Andric                                  const JobAction *JA,
1390b57cec5SDimitry Andric                                  bool IssueErrors) const {
1400b57cec5SDimitry Andric   bool Success = true;
1410b57cec5SDimitry Andric   for (const auto &File : Files) {
1420b57cec5SDimitry Andric     // If specified, only delete the files associated with the JobAction.
1430b57cec5SDimitry Andric     // Otherwise, delete all files in the map.
1440b57cec5SDimitry Andric     if (JA && File.first != JA)
1450b57cec5SDimitry Andric       continue;
1460b57cec5SDimitry Andric     Success &= CleanupFile(File.second, IssueErrors);
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric   return Success;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric int Compilation::ExecuteCommand(const Command &C,
1520b57cec5SDimitry Andric                                 const Command *&FailingCommand) const {
1530b57cec5SDimitry Andric   if ((getDriver().CCPrintOptions ||
1540b57cec5SDimitry Andric        getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
1550b57cec5SDimitry Andric     raw_ostream *OS = &llvm::errs();
1560b57cec5SDimitry Andric     std::unique_ptr<llvm::raw_fd_ostream> OwnedStream;
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric     // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
1590b57cec5SDimitry Andric     // output stream.
1600b57cec5SDimitry Andric     if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
1610b57cec5SDimitry Andric       std::error_code EC;
1620b57cec5SDimitry Andric       OwnedStream.reset(new llvm::raw_fd_ostream(
1630b57cec5SDimitry Andric           getDriver().CCPrintOptionsFilename, EC,
164a7dea167SDimitry Andric           llvm::sys::fs::OF_Append | llvm::sys::fs::OF_Text));
1650b57cec5SDimitry Andric       if (EC) {
1660b57cec5SDimitry Andric         getDriver().Diag(diag::err_drv_cc_print_options_failure)
1670b57cec5SDimitry Andric             << EC.message();
1680b57cec5SDimitry Andric         FailingCommand = &C;
1690b57cec5SDimitry Andric         return 1;
1700b57cec5SDimitry Andric       }
1710b57cec5SDimitry Andric       OS = OwnedStream.get();
1720b57cec5SDimitry Andric     }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric     if (getDriver().CCPrintOptions)
17555e4f9d5SDimitry Andric       *OS << "[Logging clang options]\n";
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric     C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   std::string Error;
1810b57cec5SDimitry Andric   bool ExecutionFailed;
1820b57cec5SDimitry Andric   int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
1830b57cec5SDimitry Andric   if (!Error.empty()) {
1840b57cec5SDimitry Andric     assert(Res && "Error string set with 0 result code!");
1850b57cec5SDimitry Andric     getDriver().Diag(diag::err_drv_command_failure) << Error;
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   if (Res)
1890b57cec5SDimitry Andric     FailingCommand = &C;
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   return ExecutionFailed ? 1 : Res;
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric static bool ActionFailed(const Action *A,
1970b57cec5SDimitry Andric                          const FailingCommandList &FailingCommands) {
1980b57cec5SDimitry Andric   if (FailingCommands.empty())
1990b57cec5SDimitry Andric     return false;
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   // CUDA/HIP can have the same input source code compiled multiple times so do
2020b57cec5SDimitry Andric   // not compiled again if there are already failures. It is OK to abort the
2030b57cec5SDimitry Andric   // CUDA pipeline on errors.
2040b57cec5SDimitry Andric   if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP))
2050b57cec5SDimitry Andric     return true;
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   for (const auto &CI : FailingCommands)
2080b57cec5SDimitry Andric     if (A == &(CI.second->getSource()))
2090b57cec5SDimitry Andric       return true;
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   for (const auto *AI : A->inputs())
2120b57cec5SDimitry Andric     if (ActionFailed(AI, FailingCommands))
2130b57cec5SDimitry Andric       return true;
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   return false;
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric static bool InputsOk(const Command &C,
2190b57cec5SDimitry Andric                      const FailingCommandList &FailingCommands) {
2200b57cec5SDimitry Andric   return !ActionFailed(&C.getSource(), FailingCommands);
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric void Compilation::ExecuteJobs(const JobList &Jobs,
2240b57cec5SDimitry Andric                               FailingCommandList &FailingCommands) const {
2250b57cec5SDimitry Andric   // According to UNIX standard, driver need to continue compiling all the
2260b57cec5SDimitry Andric   // inputs on the command line even one of them failed.
2270b57cec5SDimitry Andric   // In all but CLMode, execute all the jobs unless the necessary inputs for the
2280b57cec5SDimitry Andric   // job is missing due to previous failures.
2290b57cec5SDimitry Andric   for (const auto &Job : Jobs) {
2300b57cec5SDimitry Andric     if (!InputsOk(Job, FailingCommands))
2310b57cec5SDimitry Andric       continue;
2320b57cec5SDimitry Andric     const Command *FailingCommand = nullptr;
2330b57cec5SDimitry Andric     if (int Res = ExecuteCommand(Job, FailingCommand)) {
2340b57cec5SDimitry Andric       FailingCommands.push_back(std::make_pair(Res, FailingCommand));
2350b57cec5SDimitry Andric       // Bail as soon as one command fails in cl driver mode.
2360b57cec5SDimitry Andric       if (TheDriver.IsCLMode())
2370b57cec5SDimitry Andric         return;
2380b57cec5SDimitry Andric     }
2390b57cec5SDimitry Andric   }
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric void Compilation::initCompilationForDiagnostics() {
2430b57cec5SDimitry Andric   ForDiagnostics = true;
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   // Free actions and jobs.
2460b57cec5SDimitry Andric   Actions.clear();
2470b57cec5SDimitry Andric   AllActions.clear();
2480b57cec5SDimitry Andric   Jobs.clear();
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   // Remove temporary files.
2510b57cec5SDimitry Andric   if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
2520b57cec5SDimitry Andric     CleanupFileList(TempFiles);
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   // Clear temporary/results file lists.
2550b57cec5SDimitry Andric   TempFiles.clear();
2560b57cec5SDimitry Andric   ResultFiles.clear();
2570b57cec5SDimitry Andric   FailureResultFiles.clear();
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   // Remove any user specified output.  Claim any unclaimed arguments, so as
2600b57cec5SDimitry Andric   // to avoid emitting warnings about unused args.
2610b57cec5SDimitry Andric   OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
2620b57cec5SDimitry Andric                                 options::OPT_MMD };
2630b57cec5SDimitry Andric   for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
2640b57cec5SDimitry Andric     if (TranslatedArgs->hasArg(OutputOpts[i]))
2650b57cec5SDimitry Andric       TranslatedArgs->eraseArg(OutputOpts[i]);
2660b57cec5SDimitry Andric   }
2670b57cec5SDimitry Andric   TranslatedArgs->ClaimAllArgs();
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   // Redirect stdout/stderr to /dev/null.
2700b57cec5SDimitry Andric   Redirects = {None, {""}, {""}};
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   // Temporary files added by diagnostics should be kept.
2730b57cec5SDimitry Andric   ForceKeepTempFiles = true;
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric StringRef Compilation::getSysRoot() const {
2770b57cec5SDimitry Andric   return getDriver().SysRoot;
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
2810b57cec5SDimitry Andric   this->Redirects = Redirects;
2820b57cec5SDimitry Andric }
283