clang 20.0.0git
Compilation.cpp
Go to the documentation of this file.
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
10#include "clang/Basic/LLVM.h"
11#include "clang/Driver/Action.h"
12#include "clang/Driver/Driver.h"
13#include "clang/Driver/Job.h"
16#include "clang/Driver/Util.h"
17#include "llvm/Option/ArgList.h"
18#include "llvm/Option/OptSpecifier.h"
19#include "llvm/Option/Option.h"
20#include "llvm/Support/FileSystem.h"
21#include "llvm/Support/raw_ostream.h"
22#include "llvm/TargetParser/Triple.h"
23#include <cassert>
24#include <string>
25#include <system_error>
26#include <utility>
27
28using namespace clang;
29using namespace driver;
30using namespace llvm::opt;
31
32Compilation::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
43 // Remove temporary files. This must be done before arguments are freed, as
44 // the file names might be derived from the input arguments.
45 if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
46 CleanupFileList(TempFiles);
47
48 delete TranslatedArgs;
49 delete Args;
50
51 // Free any derived arg lists.
52 for (auto Arg : TCArgs)
53 if (Arg.second != TranslatedArgs)
54 delete Arg.second;
55}
56
57const DerivedArgList &
58Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
59 Action::OffloadKind DeviceOffloadKind) {
60 if (!TC)
61 TC = &DefaultToolChain;
62
63 DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
64 if (!Entry) {
65 SmallVector<Arg *, 4> AllocatedArgs;
66 DerivedArgList *OpenMPArgs = nullptr;
67 // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
68 if (DeviceOffloadKind == Action::OFK_OpenMP) {
69 const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
70 bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
71 OpenMPArgs = TC->TranslateOpenMPTargetArgs(
72 *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
73 }
74
75 DerivedArgList *NewDAL = nullptr;
76 if (!OpenMPArgs) {
77 NewDAL = TC->TranslateXarchArgs(*TranslatedArgs, BoundArch,
78 DeviceOffloadKind, &AllocatedArgs);
79 } else {
80 NewDAL = TC->TranslateXarchArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind,
81 &AllocatedArgs);
82 if (!NewDAL)
83 NewDAL = OpenMPArgs;
84 else
85 delete OpenMPArgs;
86 }
87
88 if (!NewDAL) {
89 Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
90 if (!Entry)
91 Entry = TranslatedArgs;
92 } else {
93 Entry = TC->TranslateArgs(*NewDAL, BoundArch, DeviceOffloadKind);
94 if (!Entry)
95 Entry = NewDAL;
96 else
97 delete NewDAL;
98 }
99
100 // Add allocated arguments to the final DAL.
101 for (auto *ArgPtr : AllocatedArgs)
102 Entry->AddSynthesizedArg(ArgPtr);
103 }
104
105 return *Entry;
106}
107
108bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
109 // FIXME: Why are we trying to remove files that we have not created? For
110 // example we should only try to remove a temporary assembly file if
111 // "clang -cc1" succeed in writing it. Was this a workaround for when
112 // clang was writing directly to a .s file and sometimes leaving it behind
113 // during a failure?
114
115 // FIXME: If this is necessary, we can still try to split
116 // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
117 // duplicated stat from is_regular_file.
118
119 // Don't try to remove files which we don't have write access to (but may be
120 // able to remove), or non-regular files. Underlying tools may have
121 // intentionally not overwritten them.
122 if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
123 return true;
124
125 if (std::error_code EC = llvm::sys::fs::remove(File)) {
126 // Failure is only failure if the file exists and is "regular". We checked
127 // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
128 // so we don't need to check again.
129
130 if (IssueErrors)
131 getDriver().Diag(diag::err_drv_unable_to_remove_file)
132 << EC.message();
133 return false;
134 }
135 return true;
136}
137
138bool Compilation::CleanupFileList(const llvm::opt::ArgStringList &Files,
139 bool IssueErrors) const {
140 bool Success = true;
141 for (const auto &File: Files)
142 Success &= CleanupFile(File, IssueErrors);
143 return Success;
144}
145
147 const JobAction *JA,
148 bool IssueErrors) const {
149 bool Success = true;
150 for (const auto &File : Files) {
151 // If specified, only delete the files associated with the JobAction.
152 // Otherwise, delete all files in the map.
153 if (JA && File.first != JA)
154 continue;
155 Success &= CleanupFile(File.second, IssueErrors);
156 }
157 return Success;
158}
159
161 const Command *&FailingCommand,
162 bool LogOnly) const {
163 if ((getDriver().CCPrintOptions ||
164 getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
165 raw_ostream *OS = &llvm::errs();
166 std::unique_ptr<llvm::raw_fd_ostream> OwnedStream;
167
168 // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
169 // output stream.
170 if (getDriver().CCPrintOptions &&
171 !getDriver().CCPrintOptionsFilename.empty()) {
172 std::error_code EC;
173 OwnedStream.reset(new llvm::raw_fd_ostream(
174 getDriver().CCPrintOptionsFilename, EC,
175 llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF));
176 if (EC) {
177 getDriver().Diag(diag::err_drv_cc_print_options_failure)
178 << EC.message();
179 FailingCommand = &C;
180 return 1;
181 }
182 OS = OwnedStream.get();
183 }
184
185 if (getDriver().CCPrintOptions)
186 *OS << "[Logging clang options]\n";
187
188 C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
189 }
190
191 if (LogOnly)
192 return 0;
193
194 std::string Error;
195 bool ExecutionFailed;
196 int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
197 if (PostCallback)
198 PostCallback(C, Res);
199 if (!Error.empty()) {
200 assert(Res && "Error string set with 0 result code!");
201 getDriver().Diag(diag::err_drv_command_failure) << Error;
202 }
203
204 if (Res)
205 FailingCommand = &C;
206
207 return ExecutionFailed ? 1 : Res;
208}
209
211
212static bool ActionFailed(const Action *A,
213 const FailingCommandList &FailingCommands) {
214 if (FailingCommands.empty())
215 return false;
216
217 // CUDA/HIP can have the same input source code compiled multiple times so do
218 // not compiled again if there are already failures. It is OK to abort the
219 // CUDA pipeline on errors.
221 return true;
222
223 for (const auto &CI : FailingCommands)
224 if (A == &(CI.second->getSource()))
225 return true;
226
227 for (const auto *AI : A->inputs())
228 if (ActionFailed(AI, FailingCommands))
229 return true;
230
231 return false;
232}
233
234static bool InputsOk(const Command &C,
235 const FailingCommandList &FailingCommands) {
236 return !ActionFailed(&C.getSource(), FailingCommands);
237}
238
240 FailingCommandList &FailingCommands,
241 bool LogOnly) const {
242 // According to UNIX standard, driver need to continue compiling all the
243 // inputs on the command line even one of them failed.
244 // In all but CLMode, execute all the jobs unless the necessary inputs for the
245 // job is missing due to previous failures.
246 for (const auto &Job : Jobs) {
247 if (!InputsOk(Job, FailingCommands))
248 continue;
249 const Command *FailingCommand = nullptr;
250 if (int Res = ExecuteCommand(Job, FailingCommand, LogOnly)) {
251 FailingCommands.push_back(std::make_pair(Res, FailingCommand));
252 // Bail as soon as one command fails in cl driver mode.
253 if (TheDriver.IsCLMode())
254 return;
255 }
256 }
257}
258
260 ForDiagnostics = true;
261
262 // Free actions and jobs.
263 Actions.clear();
264 AllActions.clear();
265 Jobs.clear();
266
267 // Remove temporary files.
268 if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
269 CleanupFileList(TempFiles);
270
271 // Clear temporary/results file lists.
272 TempFiles.clear();
273 ResultFiles.clear();
274 FailureResultFiles.clear();
275
276 // Remove any user specified output. Claim any unclaimed arguments, so as
277 // to avoid emitting warnings about unused args.
278 OptSpecifier OutputOpts[] = {
279 options::OPT_o, options::OPT_MD, options::OPT_MMD, options::OPT_M,
280 options::OPT_MM, options::OPT_MF, options::OPT_MG, options::OPT_MJ,
281 options::OPT_MQ, options::OPT_MT, options::OPT_MV};
282 for (const auto &Opt : OutputOpts) {
283 if (TranslatedArgs->hasArg(Opt))
284 TranslatedArgs->eraseArg(Opt);
285 }
286 TranslatedArgs->ClaimAllArgs();
287
288 // Force re-creation of the toolchain Args, otherwise our modifications just
289 // above will have no effect.
290 for (auto Arg : TCArgs)
291 if (Arg.second != TranslatedArgs)
292 delete Arg.second;
293 TCArgs.clear();
294
295 // Redirect stdout/stderr to /dev/null.
296 Redirects = {std::nullopt, {""}, {""}};
297
298 // Temporary files added by diagnostics should be kept.
299 ForceKeepTempFiles = true;
300}
301
302StringRef Compilation::getSysRoot() const {
303 return getDriver().SysRoot;
304}
305
306void Compilation::Redirect(ArrayRef<std::optional<StringRef>> Redirects) {
307 this->Redirects = Redirects;
308}
const Decl * D
static bool ActionFailed(const Action *A, const FailingCommandList &FailingCommands)
static bool InputsOk(const Command &C, const FailingCommandList &FailingCommands)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Action - Represent an abstract compilation step to perform.
Definition: Action.h:47
input_range inputs()
Definition: Action.h:157
bool isOffloading(OffloadKind OKind) const
Definition: Action.h:224
Command - An executable path/name and argument vector to execute.
Definition: Job.h:106
const llvm::opt::DerivedArgList & getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind)
getArgsForToolChain - Return the derived argument list for the tool chain TC (or the default tool cha...
Definition: Compilation.cpp:58
int ExecuteCommand(const Command &C, const Command *&FailingCommand, bool LogOnly=false) const
ExecuteCommand - Execute an actual command.
bool CleanupFileMap(const ArgStringMap &Files, const JobAction *JA, bool IssueErrors=false) const
CleanupFileMap - Remove the files in the given map.
bool CleanupFile(const char *File, bool IssueErrors=false) const
CleanupFile - Delete a given file.
Compilation(const Driver &D, const ToolChain &DefaultToolChain, llvm::opt::InputArgList *Args, llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError)
Definition: Compilation.cpp:32
bool CleanupFileList(const llvm::opt::ArgStringList &Files, bool IssueErrors=false) const
CleanupFileList - Remove the files in the given list.
StringRef getSysRoot() const
Returns the sysroot path.
void Redirect(ArrayRef< std::optional< StringRef > > Redirects)
Redirect - Redirect output of this compilation.
void initCompilationForDiagnostics()
initCompilationForDiagnostics - Remove stale state and suppress output so compilation can be reexecut...
const llvm::opt::DerivedArgList & getArgs() const
Definition: Compilation.h:201
void ExecuteJobs(const JobList &Jobs, SmallVectorImpl< std::pair< int, const Command * > > &FailingCommands, bool LogOnly=false) const
ExecuteJob - Execute a single job.
const Driver & getDriver() const
Definition: Compilation.h:141
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:77
std::string SysRoot
sysroot, if present
Definition: Driver.h:180
bool isSaveTempsEnabled() const
Definition: Driver.h:429
bool IsCLMode() const
Whether the driver should follow cl.exe like behavior.
Definition: Driver.h:222
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:144
JobList - A sequence of jobs to perform.
Definition: Job.h:260
void clear()
Clear the job list.
Definition: Job.cpp:456
ToolChain - Access to tools for a single platform.
Definition: ToolChain.h:92
virtual llvm::opt::DerivedArgList * TranslateOpenMPTargetArgs(const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost, SmallVectorImpl< llvm::opt::Arg * > &AllocatedArgs) const
TranslateOpenMPTargetArgs - Create a new derived argument list for that contains the OpenMP target sp...
Definition: ToolChain.cpp:1550
virtual llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const
TranslateArgs - Create a new derived argument list for any argument translations this ToolChain may w...
Definition: ToolChain.h:358
const llvm::Triple & getTriple() const
Definition: ToolChain.h:254
virtual void TranslateXarchArgs(const llvm::opt::DerivedArgList &Args, llvm::opt::Arg *&A, llvm::opt::DerivedArgList *DAL, SmallVectorImpl< llvm::opt::Arg * > *AllocatedArgs=nullptr) const
Append the argument following A to DAL assuming A is an Xarch argument.
Definition: ToolChain.cpp:1627
llvm::DenseMap< const JobAction *, const char * > ArgStringMap
ArgStringMap - Type used to map a JobAction to its result file.
Definition: Util.h:22
The JSON file list parser is used to communicate input to InstallAPI.
@ Success
Template argument deduction was successful.