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/ToolChain.h"
17 
18 #include "llvm/Support/raw_ostream.h"
19 #include "llvm/System/Program.h"
20 #include <sys/stat.h>
21 #include <errno.h>
22 using namespace clang::driver;
23 
24 Compilation::Compilation(const Driver &D,
25                          const ToolChain &_DefaultToolChain,
26                          InputArgList *_Args)
27   : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args) {
28 }
29 
30 Compilation::~Compilation() {
31   delete Args;
32 
33   // Free any derived arg lists.
34   for (llvm::DenseMap<std::pair<const ToolChain*, const char*>,
35                       DerivedArgList*>::iterator it = TCArgs.begin(),
36          ie = TCArgs.end(); it != ie; ++it)
37     delete it->second;
38 
39   // Free the actions, if built.
40   for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
41        it != ie; ++it)
42     delete *it;
43 }
44 
45 const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
46                                                        const char *BoundArch) {
47   if (!TC)
48     TC = &DefaultToolChain;
49 
50   DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)];
51   if (!Entry)
52     Entry = TC->TranslateArgs(*Args, BoundArch);
53 
54   return *Entry;
55 }
56 
57 void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J,
58                            const char *Terminator, bool Quote) const {
59   if (const Command *C = dyn_cast<Command>(&J)) {
60     OS << " \"" << C->getExecutable() << '"';
61     for (ArgStringList::const_iterator it = C->getArguments().begin(),
62            ie = C->getArguments().end(); it != ie; ++it) {
63       if (Quote)
64         OS << " \"" << *it << '"';
65       else
66         OS << ' ' << *it;
67     }
68     OS << Terminator;
69   } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
70     for (PipedJob::const_iterator
71            it = PJ->begin(), ie = PJ->end(); it != ie; ++it)
72       PrintJob(OS, **it, (it + 1 != PJ->end()) ? " |\n" : "\n", Quote);
73   } else {
74     const JobList *Jobs = cast<JobList>(&J);
75     for (JobList::const_iterator
76            it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
77       PrintJob(OS, **it, Terminator, Quote);
78   }
79 }
80 
81 bool Compilation::CleanupFileList(const ArgStringList &Files,
82                                   bool IssueErrors) const {
83   bool Success = true;
84 
85   for (ArgStringList::const_iterator
86          it = Files.begin(), ie = Files.end(); it != ie; ++it) {
87     llvm::sys::Path P(*it);
88     std::string Error;
89 
90     if (P.eraseFromDisk(false, &Error)) {
91       // Failure is only failure if the file doesn't exist. There is a
92       // race condition here due to the limited interface of
93       // llvm::sys::Path, we want to know if the removal gave E_NOENT.
94 
95       // FIXME: Grumble, P.exists() is broken. PR3837.
96       struct stat buf;
97       if (::stat(P.c_str(), &buf) == 0
98           || errno != ENOENT) {
99         if (IssueErrors)
100           getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
101             << Error;
102         Success = false;
103       }
104     }
105   }
106 
107   return Success;
108 }
109 
110 int Compilation::ExecuteCommand(const Command &C,
111                                 const Command *&FailingCommand) const {
112   llvm::sys::Path Prog(C.getExecutable());
113   const char **Argv = new const char*[C.getArguments().size() + 2];
114   Argv[0] = C.getExecutable();
115   std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
116   Argv[C.getArguments().size() + 1] = 0;
117 
118   if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v))
119     PrintJob(llvm::errs(), C, "\n", false);
120 
121   std::string Error;
122   int Res =
123     llvm::sys::Program::ExecuteAndWait(Prog, Argv,
124                                        /*env*/0, /*redirects*/0,
125                                        /*secondsToWait*/0, /*memoryLimit*/0,
126                                        &Error);
127   if (!Error.empty()) {
128     assert(Res && "Error string set with 0 result code!");
129     getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
130   }
131 
132   if (Res)
133     FailingCommand = &C;
134 
135   delete[] Argv;
136   return Res;
137 }
138 
139 int Compilation::ExecuteJob(const Job &J,
140                             const Command *&FailingCommand) const {
141   if (const Command *C = dyn_cast<Command>(&J)) {
142     return ExecuteCommand(*C, FailingCommand);
143   } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
144     // Piped commands with a single job are easy.
145     if (PJ->size() == 1)
146       return ExecuteCommand(**PJ->begin(), FailingCommand);
147 
148     FailingCommand = *PJ->begin();
149     getDriver().Diag(clang::diag::err_drv_unsupported_opt) << "-pipe";
150     return 1;
151   } else {
152     const JobList *Jobs = cast<JobList>(&J);
153     for (JobList::const_iterator
154            it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
155       if (int Res = ExecuteJob(**it, FailingCommand))
156         return Res;
157     return 0;
158   }
159 }
160