xref: /llvm-project/clang/lib/Driver/Compilation.cpp (revision db521ec23b6de14bb833308c1d0b82f94e0670df)
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       if (Quote)
65         OS << " \"" << *it << '"';
66       else
67         OS << ' ' << *it;
68     }
69     OS << Terminator;
70   } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
71     for (PipedJob::const_iterator
72            it = PJ->begin(), ie = PJ->end(); it != ie; ++it)
73       PrintJob(OS, **it, (it + 1 != PJ->end()) ? " |\n" : "\n", Quote);
74   } else {
75     const JobList *Jobs = cast<JobList>(&J);
76     for (JobList::const_iterator
77            it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
78       PrintJob(OS, **it, Terminator, Quote);
79   }
80 }
81 
82 bool Compilation::CleanupFileList(const ArgStringList &Files,
83                                   bool IssueErrors) const {
84   bool Success = true;
85 
86   for (ArgStringList::const_iterator
87          it = Files.begin(), ie = Files.end(); it != ie; ++it) {
88 
89     llvm::sys::Path P(*it);
90     std::string Error;
91 
92     if (P.isSpecialFile()) {
93       // If we have a special file in our list, i.e. /dev/null
94       //  then don't call eraseFromDisk() and just continue.
95       continue;
96     }
97 
98     if (P.eraseFromDisk(false, &Error)) {
99       // Failure is only failure if the file doesn't exist. There is a
100       // race condition here due to the limited interface of
101       // llvm::sys::Path, we want to know if the removal gave E_NOENT.
102 
103       // FIXME: Grumble, P.exists() is broken. PR3837.
104       struct stat buf;
105       if (::stat(P.c_str(), &buf) == 0
106           || errno != ENOENT) {
107         if (IssueErrors)
108           getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
109             << Error;
110         Success = false;
111       }
112     }
113   }
114 
115   return Success;
116 }
117 
118 int Compilation::ExecuteCommand(const Command &C,
119                                 const Command *&FailingCommand) const {
120   llvm::sys::Path Prog(C.getExecutable());
121   const char **Argv = new const char*[C.getArguments().size() + 2];
122   Argv[0] = C.getExecutable();
123   std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
124   Argv[C.getArguments().size() + 1] = 0;
125 
126   if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v))
127     PrintJob(llvm::errs(), C, "\n", false);
128 
129   std::string Error;
130   int Res =
131     llvm::sys::Program::ExecuteAndWait(Prog, Argv,
132                                        /*env*/0, /*redirects*/0,
133                                        /*secondsToWait*/0, /*memoryLimit*/0,
134                                        &Error);
135   if (!Error.empty()) {
136     assert(Res && "Error string set with 0 result code!");
137     getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
138   }
139 
140   if (Res)
141     FailingCommand = &C;
142 
143   delete[] Argv;
144   return Res;
145 }
146 
147 int Compilation::ExecuteJob(const Job &J,
148                             const Command *&FailingCommand) const {
149   if (const Command *C = dyn_cast<Command>(&J)) {
150     return ExecuteCommand(*C, FailingCommand);
151   } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
152     // Piped commands with a single job are easy.
153     if (PJ->size() == 1)
154       return ExecuteCommand(**PJ->begin(), FailingCommand);
155 
156     FailingCommand = *PJ->begin();
157     getDriver().Diag(clang::diag::err_drv_unsupported_opt) << "-pipe";
158     return 1;
159   } else {
160     const JobList *Jobs = cast<JobList>(&J);
161     for (JobList::const_iterator
162            it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
163       if (int Res = ExecuteJob(**it, FailingCommand))
164         return Res;
165     return 0;
166   }
167 }
168