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