Compilation.cpp revision 193326
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(Driver &D,
25                         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) const {
109  llvm::sys::Path Prog(C.getExecutable());
110  const char **Argv = new const char*[C.getArguments().size() + 2];
111  Argv[0] = C.getExecutable();
112  std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
113  Argv[C.getArguments().size() + 1] = 0;
114
115  if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v))
116    PrintJob(llvm::errs(), C, "\n", false);
117
118  std::string Error;
119  int Res =
120    llvm::sys::Program::ExecuteAndWait(Prog, Argv,
121                                       /*env*/0, /*redirects*/0,
122                                       /*secondsToWait*/0, /*memoryLimit*/0,
123                                       &Error);
124  if (!Error.empty()) {
125    assert(Res && "Error string set with 0 result code!");
126    getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
127  }
128
129  delete[] Argv;
130  return Res;
131}
132
133int Compilation::ExecuteJob(const Job &J) const {
134  if (const Command *C = dyn_cast<Command>(&J)) {
135    return ExecuteCommand(*C);
136  } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
137    // Piped commands with a single job are easy.
138    if (PJ->size() == 1)
139      return ExecuteCommand(**PJ->begin());
140
141    getDriver().Diag(clang::diag::err_drv_unsupported_opt) << "-pipe";
142    return 1;
143  } else {
144    const JobList *Jobs = cast<JobList>(&J);
145    for (JobList::const_iterator
146           it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
147      if (int Res = ExecuteJob(**it))
148        return Res;
149    return 0;
150  }
151}
152
153int Compilation::Execute() const {
154  // Just print if -### was present.
155  if (getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
156    PrintJob(llvm::errs(), Jobs, "\n", true);
157    return 0;
158  }
159
160  // If there were errors building the compilation, quit now.
161  if (getDriver().getDiags().getNumErrors())
162    return 1;
163
164  int Res = ExecuteJob(Jobs);
165
166  // Remove temp files.
167  CleanupFileList(TempFiles);
168
169  // If the compilation failed, remove result files as well.
170  if (Res != 0 && !getArgs().hasArg(options::OPT_save_temps))
171    CleanupFileList(ResultFiles, true);
172
173  return Res;
174}
175