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 
12 #include "clang/Driver/Action.h"
13 #include "clang/Driver/ArgList.h"
14 #include "clang/Driver/Driver.h"
15 #include "clang/Driver/DriverDiagnostic.h"
16 #include "clang/Driver/Options.h"
17 #include "clang/Driver/ToolChain.h"
18 
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/System/Program.h"
21 #include <sys/stat.h>
22 #include <errno.h>
23 using namespace clang::driver;
24 
25 Compilation::Compilation(const Driver &D,
26                          const ToolChain &_DefaultToolChain,
27                          InputArgList *_Args)
28   : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args) {
29 }
30 
31 Compilation::~Compilation() {
32   delete Args;
33 
34   // Free any derived arg lists.
35   for (llvm::DenseMap<std::pair<const ToolChain*, const char*>,
36                       DerivedArgList*>::iterator it = TCArgs.begin(),
37          ie = TCArgs.end(); it != ie; ++it)
38     delete it->second;
39 
40   // Free the actions, if built.
41   for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
42        it != ie; ++it)
43     delete *it;
44 }
45 
46 const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
47                                                        const char *BoundArch) {
48   if (!TC)
49     TC = &DefaultToolChain;
50 
51   DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)];
52   if (!Entry)
53     Entry = TC->TranslateArgs(*Args, BoundArch);
54 
55   return *Entry;
56 }
57 
58 void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J,
59                            const char *Terminator, bool Quote) const {
60   if (const Command *C = dyn_cast<Command>(&J)) {
61     OS << " \"" << C->getExecutable() << '"';
62     for (ArgStringList::const_iterator it = C->getArguments().begin(),
63            ie = C->getArguments().end(); it != ie; ++it) {
64       OS << ' ';
65       if (!Quote) {
66         OS << *it;
67         continue;
68       }
69 
70       // Quote the argument and escape shell special characters; this isn't
71       // really complete but is good enough.
72       OS << '"';
73       for (const char *s = *it; *s; ++s) {
74         if (*s == '"' || *s == '\\' || *s == '$')
75           OS << '\\';
76         OS << *s;
77       }
78       OS << '"';
79     }
80     OS << Terminator;
81   } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
82     for (PipedJob::const_iterator
83            it = PJ->begin(), ie = PJ->end(); it != ie; ++it)
84       PrintJob(OS, **it, (it + 1 != PJ->end()) ? " |\n" : "\n", Quote);
85   } else {
86     const JobList *Jobs = cast<JobList>(&J);
87     for (JobList::const_iterator
88            it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
89       PrintJob(OS, **it, Terminator, Quote);
90   }
91 }
92 
93 bool Compilation::CleanupFileList(const ArgStringList &Files,
94                                   bool IssueErrors) const {
95   bool Success = true;
96 
97   for (ArgStringList::const_iterator
98          it = Files.begin(), ie = Files.end(); it != ie; ++it) {
99 
100     llvm::sys::Path P(*it);
101     std::string Error;
102 
103     if (!P.isRegularFile()) {
104       // If we have a special file in our list, i.e. /dev/null
105       //  then don't call eraseFromDisk() and just continue.
106       continue;
107     }
108 
109     if (P.eraseFromDisk(false, &Error)) {
110       // Failure is only failure if the file doesn't exist. There is a
111       // race condition here due to the limited interface of
112       // llvm::sys::Path, we want to know if the removal gave E_NOENT.
113 
114       // FIXME: Grumble, P.exists() is broken. PR3837.
115       struct stat buf;
116       if (::stat(P.c_str(), &buf) == 0
117           || errno != ENOENT) {
118         if (IssueErrors)
119           getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
120             << Error;
121         Success = false;
122       }
123     }
124   }
125 
126   return Success;
127 }
128 
129 int Compilation::ExecuteCommand(const Command &C,
130                                 const Command *&FailingCommand) const {
131   llvm::sys::Path Prog(C.getExecutable());
132   const char **Argv = new const char*[C.getArguments().size() + 2];
133   Argv[0] = C.getExecutable();
134   std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
135   Argv[C.getArguments().size() + 1] = 0;
136 
137   if (getDriver().CCCEcho || getDriver().CCPrintOptions ||
138       getArgs().hasArg(options::OPT_v)) {
139     llvm::raw_ostream *OS = &llvm::errs();
140 
141     // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
142     // output stream.
143     if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
144       std::string Error;
145       OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename,
146                                     Error,
147                                     llvm::raw_fd_ostream::F_Append);
148       if (!Error.empty()) {
149         getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
150           << Error;
151         FailingCommand = &C;
152         delete OS;
153         return 1;
154       }
155     }
156 
157     if (getDriver().CCPrintOptions)
158       *OS << "[Logging clang options]";
159 
160     PrintJob(*OS, C, "\n", /*Quote=*/getDriver().CCPrintOptions);
161 
162     if (OS != &llvm::errs())
163       delete OS;
164   }
165 
166   std::string Error;
167   int Res =
168     llvm::sys::Program::ExecuteAndWait(Prog, Argv,
169                                        /*env*/0, /*redirects*/0,
170                                        /*secondsToWait*/0, /*memoryLimit*/0,
171                                        &Error);
172   if (!Error.empty()) {
173     assert(Res && "Error string set with 0 result code!");
174     getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
175   }
176 
177   if (Res)
178     FailingCommand = &C;
179 
180   delete[] Argv;
181   return Res;
182 }
183 
184 int Compilation::ExecuteJob(const Job &J,
185                             const Command *&FailingCommand) const {
186   if (const Command *C = dyn_cast<Command>(&J)) {
187     return ExecuteCommand(*C, FailingCommand);
188   } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
189     // Piped commands with a single job are easy.
190     if (PJ->size() == 1)
191       return ExecuteCommand(**PJ->begin(), FailingCommand);
192 
193     FailingCommand = *PJ->begin();
194     getDriver().Diag(clang::diag::err_drv_unsupported_opt) << "-pipe";
195     return 1;
196   } else {
197     const JobList *Jobs = cast<JobList>(&J);
198     for (JobList::const_iterator
199            it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
200       if (int Res = ExecuteJob(**it, FailingCommand))
201         return Res;
202     return 0;
203   }
204 }
205