Compilation.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. //===- Compilation.cpp - Compilation Task Implementation ------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "clang/Driver/Compilation.h"
  9. #include "clang/Basic/LLVM.h"
  10. #include "clang/Driver/Action.h"
  11. #include "clang/Driver/Driver.h"
  12. #include "clang/Driver/DriverDiagnostic.h"
  13. #include "clang/Driver/Job.h"
  14. #include "clang/Driver/Options.h"
  15. #include "clang/Driver/ToolChain.h"
  16. #include "clang/Driver/Util.h"
  17. #include "llvm/ADT/STLExtras.h"
  18. #include "llvm/ADT/SmallVector.h"
  19. #include "llvm/ADT/Triple.h"
  20. #include "llvm/Option/ArgList.h"
  21. #include "llvm/Option/OptSpecifier.h"
  22. #include "llvm/Option/Option.h"
  23. #include "llvm/Support/FileSystem.h"
  24. #include "llvm/Support/raw_ostream.h"
  25. #include <cassert>
  26. #include <string>
  27. #include <system_error>
  28. #include <utility>
  29. using namespace clang;
  30. using namespace driver;
  31. using namespace llvm::opt;
  32. Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
  33. InputArgList *_Args, DerivedArgList *_TranslatedArgs,
  34. bool ContainsError)
  35. : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
  36. TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {
  37. // The offloading host toolchain is the default toolchain.
  38. OrderedOffloadingToolchains.insert(
  39. std::make_pair(Action::OFK_Host, &DefaultToolChain));
  40. }
  41. Compilation::~Compilation() {
  42. // Remove temporary files. This must be done before arguments are freed, as
  43. // the file names might be derived from the input arguments.
  44. if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
  45. CleanupFileList(TempFiles);
  46. delete TranslatedArgs;
  47. delete Args;
  48. // Free any derived arg lists.
  49. for (auto Arg : TCArgs)
  50. if (Arg.second != TranslatedArgs)
  51. delete Arg.second;
  52. }
  53. const DerivedArgList &
  54. Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
  55. Action::OffloadKind DeviceOffloadKind) {
  56. if (!TC)
  57. TC = &DefaultToolChain;
  58. DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
  59. if (!Entry) {
  60. SmallVector<Arg *, 4> AllocatedArgs;
  61. DerivedArgList *OpenMPArgs = nullptr;
  62. // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
  63. if (DeviceOffloadKind == Action::OFK_OpenMP) {
  64. const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
  65. bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
  66. OpenMPArgs = TC->TranslateOpenMPTargetArgs(
  67. *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
  68. }
  69. DerivedArgList *NewDAL = nullptr;
  70. if (!OpenMPArgs) {
  71. NewDAL = TC->TranslateXarchArgs(*TranslatedArgs, BoundArch,
  72. DeviceOffloadKind, &AllocatedArgs);
  73. } else {
  74. NewDAL = TC->TranslateXarchArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind,
  75. &AllocatedArgs);
  76. if (!NewDAL)
  77. NewDAL = OpenMPArgs;
  78. else
  79. delete OpenMPArgs;
  80. }
  81. if (!NewDAL) {
  82. Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
  83. if (!Entry)
  84. Entry = TranslatedArgs;
  85. } else {
  86. Entry = TC->TranslateArgs(*NewDAL, BoundArch, DeviceOffloadKind);
  87. if (!Entry)
  88. Entry = NewDAL;
  89. else
  90. delete NewDAL;
  91. }
  92. // Add allocated arguments to the final DAL.
  93. for (auto *ArgPtr : AllocatedArgs)
  94. Entry->AddSynthesizedArg(ArgPtr);
  95. }
  96. return *Entry;
  97. }
  98. bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
  99. // FIXME: Why are we trying to remove files that we have not created? For
  100. // example we should only try to remove a temporary assembly file if
  101. // "clang -cc1" succeed in writing it. Was this a workaround for when
  102. // clang was writing directly to a .s file and sometimes leaving it behind
  103. // during a failure?
  104. // FIXME: If this is necessary, we can still try to split
  105. // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
  106. // duplicated stat from is_regular_file.
  107. // Don't try to remove files which we don't have write access to (but may be
  108. // able to remove), or non-regular files. Underlying tools may have
  109. // intentionally not overwritten them.
  110. if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
  111. return true;
  112. if (std::error_code EC = llvm::sys::fs::remove(File)) {
  113. // Failure is only failure if the file exists and is "regular". We checked
  114. // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
  115. // so we don't need to check again.
  116. if (IssueErrors)
  117. getDriver().Diag(diag::err_drv_unable_to_remove_file)
  118. << EC.message();
  119. return false;
  120. }
  121. return true;
  122. }
  123. bool Compilation::CleanupFileList(const llvm::opt::ArgStringList &Files,
  124. bool IssueErrors) const {
  125. bool Success = true;
  126. for (const auto &File: Files)
  127. Success &= CleanupFile(File, IssueErrors);
  128. return Success;
  129. }
  130. bool Compilation::CleanupFileMap(const ArgStringMap &Files,
  131. const JobAction *JA,
  132. bool IssueErrors) const {
  133. bool Success = true;
  134. for (const auto &File : Files) {
  135. // If specified, only delete the files associated with the JobAction.
  136. // Otherwise, delete all files in the map.
  137. if (JA && File.first != JA)
  138. continue;
  139. Success &= CleanupFile(File.second, IssueErrors);
  140. }
  141. return Success;
  142. }
  143. int Compilation::ExecuteCommand(const Command &C,
  144. const Command *&FailingCommand,
  145. bool LogOnly) const {
  146. if ((getDriver().CCPrintOptions ||
  147. getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
  148. raw_ostream *OS = &llvm::errs();
  149. std::unique_ptr<llvm::raw_fd_ostream> OwnedStream;
  150. // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
  151. // output stream.
  152. if (getDriver().CCPrintOptions &&
  153. !getDriver().CCPrintOptionsFilename.empty()) {
  154. std::error_code EC;
  155. OwnedStream.reset(new llvm::raw_fd_ostream(
  156. getDriver().CCPrintOptionsFilename, EC,
  157. llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF));
  158. if (EC) {
  159. getDriver().Diag(diag::err_drv_cc_print_options_failure)
  160. << EC.message();
  161. FailingCommand = &C;
  162. return 1;
  163. }
  164. OS = OwnedStream.get();
  165. }
  166. if (getDriver().CCPrintOptions)
  167. *OS << "[Logging clang options]\n";
  168. C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
  169. }
  170. if (LogOnly)
  171. return 0;
  172. std::string Error;
  173. bool ExecutionFailed;
  174. int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
  175. if (PostCallback)
  176. PostCallback(C, Res);
  177. if (!Error.empty()) {
  178. assert(Res && "Error string set with 0 result code!");
  179. getDriver().Diag(diag::err_drv_command_failure) << Error;
  180. }
  181. if (Res)
  182. FailingCommand = &C;
  183. return ExecutionFailed ? 1 : Res;
  184. }
  185. using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;
  186. static bool ActionFailed(const Action *A,
  187. const FailingCommandList &FailingCommands) {
  188. if (FailingCommands.empty())
  189. return false;
  190. // CUDA/HIP can have the same input source code compiled multiple times so do
  191. // not compiled again if there are already failures. It is OK to abort the
  192. // CUDA pipeline on errors.
  193. if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP))
  194. return true;
  195. for (const auto &CI : FailingCommands)
  196. if (A == &(CI.second->getSource()))
  197. return true;
  198. for (const auto *AI : A->inputs())
  199. if (ActionFailed(AI, FailingCommands))
  200. return true;
  201. return false;
  202. }
  203. static bool InputsOk(const Command &C,
  204. const FailingCommandList &FailingCommands) {
  205. return !ActionFailed(&C.getSource(), FailingCommands);
  206. }
  207. void Compilation::ExecuteJobs(const JobList &Jobs,
  208. FailingCommandList &FailingCommands,
  209. bool LogOnly) const {
  210. // According to UNIX standard, driver need to continue compiling all the
  211. // inputs on the command line even one of them failed.
  212. // In all but CLMode, execute all the jobs unless the necessary inputs for the
  213. // job is missing due to previous failures.
  214. for (const auto &Job : Jobs) {
  215. if (!InputsOk(Job, FailingCommands))
  216. continue;
  217. const Command *FailingCommand = nullptr;
  218. if (int Res = ExecuteCommand(Job, FailingCommand, LogOnly)) {
  219. FailingCommands.push_back(std::make_pair(Res, FailingCommand));
  220. // Bail as soon as one command fails in cl driver mode.
  221. if (TheDriver.IsCLMode())
  222. return;
  223. }
  224. }
  225. }
  226. void Compilation::initCompilationForDiagnostics() {
  227. ForDiagnostics = true;
  228. // Free actions and jobs.
  229. Actions.clear();
  230. AllActions.clear();
  231. Jobs.clear();
  232. // Remove temporary files.
  233. if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
  234. CleanupFileList(TempFiles);
  235. // Clear temporary/results file lists.
  236. TempFiles.clear();
  237. ResultFiles.clear();
  238. FailureResultFiles.clear();
  239. // Remove any user specified output. Claim any unclaimed arguments, so as
  240. // to avoid emitting warnings about unused args.
  241. OptSpecifier OutputOpts[] = {
  242. options::OPT_o, options::OPT_MD, options::OPT_MMD, options::OPT_M,
  243. options::OPT_MM, options::OPT_MF, options::OPT_MG, options::OPT_MJ,
  244. options::OPT_MQ, options::OPT_MT, options::OPT_MV};
  245. for (const auto &Opt : OutputOpts) {
  246. if (TranslatedArgs->hasArg(Opt))
  247. TranslatedArgs->eraseArg(Opt);
  248. }
  249. TranslatedArgs->ClaimAllArgs();
  250. // Force re-creation of the toolchain Args, otherwise our modifications just
  251. // above will have no effect.
  252. for (auto Arg : TCArgs)
  253. if (Arg.second != TranslatedArgs)
  254. delete Arg.second;
  255. TCArgs.clear();
  256. // Redirect stdout/stderr to /dev/null.
  257. Redirects = {std::nullopt, {""}, {""}};
  258. // Temporary files added by diagnostics should be kept.
  259. ForceKeepTempFiles = true;
  260. }
  261. StringRef Compilation::getSysRoot() const {
  262. return getDriver().SysRoot;
  263. }
  264. void Compilation::Redirect(ArrayRef<std::optional<StringRef>> Redirects) {
  265. this->Redirects = Redirects;
  266. }