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