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