]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/clang/lib/Driver/Compilation.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / tools / clang / lib / Driver / Compilation.cpp
1 //===--- Compilation.cpp - Compilation Task Implementation ----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "clang/Driver/Compilation.h"
11 #include "clang/Driver/Action.h"
12 #include "clang/Driver/ArgList.h"
13 #include "clang/Driver/Driver.h"
14 #include "clang/Driver/DriverDiagnostic.h"
15 #include "clang/Driver/Options.h"
16 #include "clang/Driver/ToolChain.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/StringSwitch.h"
19 #include "llvm/Support/Program.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include <errno.h>
22 #include <sys/stat.h>
23
24 using namespace clang::driver;
25 using namespace clang;
26
27 Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
28                          InputArgList *_Args, DerivedArgList *_TranslatedArgs)
29   : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
30     TranslatedArgs(_TranslatedArgs), Redirects(0) {
31 }
32
33 Compilation::~Compilation() {
34   delete TranslatedArgs;
35   delete Args;
36
37   // Free any derived arg lists.
38   for (llvm::DenseMap<std::pair<const ToolChain*, const char*>,
39                       DerivedArgList*>::iterator it = TCArgs.begin(),
40          ie = TCArgs.end(); it != ie; ++it)
41     if (it->second != TranslatedArgs)
42       delete it->second;
43
44   // Free the actions, if built.
45   for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
46        it != ie; ++it)
47     delete *it;
48
49   // Free redirections of stdout/stderr.
50   if (Redirects) {
51     delete Redirects[1];
52     delete Redirects[2];
53     delete [] Redirects;
54   }
55 }
56
57 const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
58                                                        const char *BoundArch) {
59   if (!TC)
60     TC = &DefaultToolChain;
61
62   DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)];
63   if (!Entry) {
64     Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch);
65     if (!Entry)
66       Entry = TranslatedArgs;
67   }
68
69   return *Entry;
70 }
71
72 void Compilation::PrintJob(raw_ostream &OS, const Job &J,
73                            const char *Terminator, bool Quote) const {
74   if (const Command *C = dyn_cast<Command>(&J)) {
75     OS << " \"" << C->getExecutable() << '"';
76     for (ArgStringList::const_iterator it = C->getArguments().begin(),
77            ie = C->getArguments().end(); it != ie; ++it) {
78       OS << ' ';
79       if (!Quote && !std::strpbrk(*it, " \"\\$")) {
80         OS << *it;
81         continue;
82       }
83
84       // Quote the argument and escape shell special characters; this isn't
85       // really complete but is good enough.
86       OS << '"';
87       for (const char *s = *it; *s; ++s) {
88         if (*s == '"' || *s == '\\' || *s == '$')
89           OS << '\\';
90         OS << *s;
91       }
92       OS << '"';
93     }
94     OS << Terminator;
95   } else {
96     const JobList *Jobs = cast<JobList>(&J);
97     for (JobList::const_iterator
98            it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
99       PrintJob(OS, **it, Terminator, Quote);
100   }
101 }
102
103 static bool skipArg(const char *Flag, bool &SkipNextArg) {
104   StringRef FlagRef(Flag);
105
106   // Assume we're going to see -Flag <Arg>.
107   SkipNextArg = true;
108
109   // These flags are all of the form -Flag <Arg> and are treated as two
110   // arguments.  Therefore, we need to skip the flag and the next argument.
111   bool Res = llvm::StringSwitch<bool>(Flag)
112     .Cases("-I", "-MF", "-MT", "-MQ", true)
113     .Cases("-o", "-coverage-file", "-dependency-file", true)
114     .Cases("-fdebug-compilation-dir", "-idirafter", true)
115     .Cases("-include", "-include-pch", "-internal-isystem", true)
116     .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
117     .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
118     .Cases("-resource-dir", "-serialize-diagnostic-file", true)
119     .Case("-dwarf-debug-flags", true)
120     .Default(false);
121
122   // Match found.
123   if (Res)
124     return Res;
125
126   // The remaining flags are treated as a single argument.
127   SkipNextArg = false;
128
129   // These flags are all of the form -Flag and have no second argument.
130   Res = llvm::StringSwitch<bool>(Flag)
131     .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
132     .Case("-MMD", true)
133     .Default(false);
134
135   // Match found.
136   if (Res)
137     return Res;
138
139   // These flags are treated as a single argument (e.g., -F<Dir>).
140   if (FlagRef.startswith("-F") || FlagRef.startswith("-I"))
141     return true;
142
143   return false;
144 }
145
146 static bool quoteNextArg(const char *flag) {
147   return llvm::StringSwitch<bool>(flag)
148     .Case("-D", true)
149     .Default(false);
150 }
151
152 void Compilation::PrintDiagnosticJob(raw_ostream &OS, const Job &J) const {
153   if (const Command *C = dyn_cast<Command>(&J)) {
154     OS << C->getExecutable();
155     unsigned QuoteNextArg = 0;
156     for (ArgStringList::const_iterator it = C->getArguments().begin(),
157            ie = C->getArguments().end(); it != ie; ++it) {
158
159       bool SkipNext;
160       if (skipArg(*it, SkipNext)) {
161         if (SkipNext) ++it;
162         continue;
163       }
164
165       if (!QuoteNextArg)
166         QuoteNextArg = quoteNextArg(*it) ? 2 : 0;
167
168       OS << ' ';
169
170       if (QuoteNextArg == 1)
171         OS << '"';
172
173       if (!std::strpbrk(*it, " \"\\$")) {
174         OS << *it;
175       } else {
176         // Quote the argument and escape shell special characters; this isn't
177         // really complete but is good enough.
178         OS << '"';
179         for (const char *s = *it; *s; ++s) {
180           if (*s == '"' || *s == '\\' || *s == '$')
181             OS << '\\';
182           OS << *s;
183         }
184         OS << '"';
185       }
186
187       if (QuoteNextArg) {
188         if (QuoteNextArg == 1)
189           OS << '"';
190         --QuoteNextArg;
191       }
192     }
193     OS << '\n';
194   } else {
195     const JobList *Jobs = cast<JobList>(&J);
196     for (JobList::const_iterator
197            it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
198       PrintDiagnosticJob(OS, **it);
199   }
200 }
201
202 bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
203   llvm::sys::Path P(File);
204   std::string Error;
205
206   // Don't try to remove files which we don't have write access to (but may be
207   // able to remove), or non-regular files. Underlying tools may have
208   // intentionally not overwritten them.
209   if (!P.canWrite() || !P.isRegularFile())
210     return true;
211
212   if (P.eraseFromDisk(false, &Error)) {
213     // Failure is only failure if the file exists and is "regular". There is
214     // a race condition here due to the limited interface of
215     // llvm::sys::Path, we want to know if the removal gave ENOENT.
216     
217     // FIXME: Grumble, P.exists() is broken. PR3837.
218     struct stat buf;
219     if (::stat(P.c_str(), &buf) == 0 ? (buf.st_mode & S_IFMT) == S_IFREG :
220         (errno != ENOENT)) {
221       if (IssueErrors)
222         getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
223           << Error;
224       return false;
225     }
226   }
227   return true;
228 }
229
230 bool Compilation::CleanupFileList(const ArgStringList &Files,
231                                   bool IssueErrors) const {
232   bool Success = true;
233   for (ArgStringList::const_iterator
234          it = Files.begin(), ie = Files.end(); it != ie; ++it)
235     Success &= CleanupFile(*it, IssueErrors);
236   return Success;
237 }
238
239 bool Compilation::CleanupFileMap(const ArgStringMap &Files,
240                                  const JobAction *JA,
241                                  bool IssueErrors) const {
242   bool Success = true;
243   for (ArgStringMap::const_iterator
244          it = Files.begin(), ie = Files.end(); it != ie; ++it) {
245
246     // If specified, only delete the files associated with the JobAction.
247     // Otherwise, delete all files in the map.
248     if (JA && it->first != JA)
249       continue;
250     Success &= CleanupFile(it->second, IssueErrors);
251   }
252   return Success;
253 }
254
255 int Compilation::ExecuteCommand(const Command &C,
256                                 const Command *&FailingCommand) const {
257   llvm::sys::Path Prog(C.getExecutable());
258   const char **Argv = new const char*[C.getArguments().size() + 2];
259   Argv[0] = C.getExecutable();
260   std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
261   Argv[C.getArguments().size() + 1] = 0;
262
263   if ((getDriver().CCCEcho || getDriver().CCPrintOptions ||
264        getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
265     raw_ostream *OS = &llvm::errs();
266
267     // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
268     // output stream.
269     if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
270       std::string Error;
271       OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename,
272                                     Error,
273                                     llvm::raw_fd_ostream::F_Append);
274       if (!Error.empty()) {
275         getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
276           << Error;
277         FailingCommand = &C;
278         delete OS;
279         return 1;
280       }
281     }
282
283     if (getDriver().CCPrintOptions)
284       *OS << "[Logging clang options]";
285
286     PrintJob(*OS, C, "\n", /*Quote=*/getDriver().CCPrintOptions);
287
288     if (OS != &llvm::errs())
289       delete OS;
290   }
291
292   std::string Error;
293   bool ExecutionFailed;
294   int Res =
295     llvm::sys::Program::ExecuteAndWait(Prog, Argv,
296                                        /*env*/0, Redirects,
297                                        /*secondsToWait*/0, /*memoryLimit*/0,
298                                        &Error, &ExecutionFailed);
299   if (!Error.empty()) {
300     assert(Res && "Error string set with 0 result code!");
301     getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
302   }
303
304   if (Res)
305     FailingCommand = &C;
306
307   delete[] Argv;
308   return ExecutionFailed ? 1 : Res;
309 }
310
311 typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList;
312
313 static bool ActionFailed(const Action *A,
314                          const FailingCommandList &FailingCommands) {
315
316   if (FailingCommands.empty())
317     return false;
318
319   for (FailingCommandList::const_iterator CI = FailingCommands.begin(),
320          CE = FailingCommands.end(); CI != CE; ++CI)
321     if (A == &(CI->second->getSource()))
322       return true;
323
324   for (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI)
325     if (ActionFailed(*AI, FailingCommands))
326       return true;
327
328   return false;
329 }
330
331 static bool InputsOk(const Command &C,
332                      const FailingCommandList &FailingCommands) {
333   return !ActionFailed(&C.getSource(), FailingCommands);
334 }
335
336 void Compilation::ExecuteJob(const Job &J,
337                              FailingCommandList &FailingCommands) const {
338   if (const Command *C = dyn_cast<Command>(&J)) {
339     if (!InputsOk(*C, FailingCommands))
340       return;
341     const Command *FailingCommand = 0;
342     if (int Res = ExecuteCommand(*C, FailingCommand))
343       FailingCommands.push_back(std::make_pair(Res, FailingCommand));
344   } else {
345     const JobList *Jobs = cast<JobList>(&J);
346     for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end();
347          it != ie; ++it)
348       ExecuteJob(**it, FailingCommands);
349   }
350 }
351
352 void Compilation::initCompilationForDiagnostics() {
353   // Free actions and jobs.
354   DeleteContainerPointers(Actions);
355   Jobs.clear();
356
357   // Clear temporary/results file lists.
358   TempFiles.clear();
359   ResultFiles.clear();
360   FailureResultFiles.clear();
361
362   // Remove any user specified output.  Claim any unclaimed arguments, so as
363   // to avoid emitting warnings about unused args.
364   OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
365                                 options::OPT_MMD };
366   for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
367     if (TranslatedArgs->hasArg(OutputOpts[i]))
368       TranslatedArgs->eraseArg(OutputOpts[i]);
369   }
370   TranslatedArgs->ClaimAllArgs();
371
372   // Redirect stdout/stderr to /dev/null.
373   Redirects = new const llvm::sys::Path*[3]();
374   Redirects[1] = new const llvm::sys::Path();
375   Redirects[2] = new const llvm::sys::Path();
376 }
377
378 StringRef Compilation::getSysRoot() const {
379   return getDriver().SysRoot;
380 }