Compilation.cpp revision 208954
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>
23using namespace clang::driver;
24
25Compilation::Compilation(const Driver &D,
26                         const ToolChain &_DefaultToolChain,
27                         InputArgList *_Args)
28  : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args) {
29}
30
31Compilation::~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
46const 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
58void 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
93bool 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
129int 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
184int 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