Compilation.cpp revision d1ca14e12ef8ac9eeafcb97a6bd4b9045c0634ec
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      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
82bool 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.isRegularFile()) {
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
118int 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
147int 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