Home | History | Annotate | Download | only in Driver
      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 #include "clang/Driver/Action.h"
     12 #include "clang/Driver/Driver.h"
     13 #include "clang/Driver/DriverDiagnostic.h"
     14 #include "clang/Driver/Options.h"
     15 #include "clang/Driver/ToolChain.h"
     16 #include "llvm/ADT/STLExtras.h"
     17 #include "llvm/Option/ArgList.h"
     18 #include "llvm/Support/FileSystem.h"
     19 #include "llvm/Support/raw_ostream.h"
     20 
     21 using namespace clang::driver;
     22 using namespace clang;
     23 using namespace llvm::opt;
     24 
     25 Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
     26                          InputArgList *_Args, DerivedArgList *_TranslatedArgs)
     27     : TheDriver(D), DefaultToolChain(_DefaultToolChain),
     28       CudaHostToolChain(&DefaultToolChain), CudaDeviceToolChain(nullptr),
     29       Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
     30       ForDiagnostics(false) {}
     31 
     32 Compilation::~Compilation() {
     33   delete TranslatedArgs;
     34   delete Args;
     35 
     36   // Free any derived arg lists.
     37   for (llvm::DenseMap<std::pair<const ToolChain*, const char*>,
     38                       DerivedArgList*>::iterator it = TCArgs.begin(),
     39          ie = TCArgs.end(); it != ie; ++it)
     40     if (it->second != TranslatedArgs)
     41       delete it->second;
     42 
     43   // Free the actions, if built.
     44   for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
     45        it != ie; ++it)
     46     delete *it;
     47 
     48   // Free redirections of stdout/stderr.
     49   if (Redirects) {
     50     delete Redirects[1];
     51     delete Redirects[2];
     52     delete [] Redirects;
     53   }
     54 }
     55 
     56 const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
     57                                                        const char *BoundArch) {
     58   if (!TC)
     59     TC = &DefaultToolChain;
     60 
     61   DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)];
     62   if (!Entry) {
     63     Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch);
     64     if (!Entry)
     65       Entry = TranslatedArgs;
     66   }
     67 
     68   return *Entry;
     69 }
     70 
     71 bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
     72   // FIXME: Why are we trying to remove files that we have not created? For
     73   // example we should only try to remove a temporary assembly file if
     74   // "clang -cc1" succeed in writing it. Was this a workaround for when
     75   // clang was writing directly to a .s file and sometimes leaving it behind
     76   // during a failure?
     77 
     78   // FIXME: If this is necessary, we can still try to split
     79   // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
     80   // duplicated stat from is_regular_file.
     81 
     82   // Don't try to remove files which we don't have write access to (but may be
     83   // able to remove), or non-regular files. Underlying tools may have
     84   // intentionally not overwritten them.
     85   if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
     86     return true;
     87 
     88   if (std::error_code EC = llvm::sys::fs::remove(File)) {
     89     // Failure is only failure if the file exists and is "regular". We checked
     90     // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
     91     // so we don't need to check again.
     92 
     93     if (IssueErrors)
     94       getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
     95         << EC.message();
     96     return false;
     97   }
     98   return true;
     99 }
    100 
    101 bool Compilation::CleanupFileList(const ArgStringList &Files,
    102                                   bool IssueErrors) const {
    103   bool Success = true;
    104   for (ArgStringList::const_iterator
    105          it = Files.begin(), ie = Files.end(); it != ie; ++it)
    106     Success &= CleanupFile(*it, IssueErrors);
    107   return Success;
    108 }
    109 
    110 bool Compilation::CleanupFileMap(const ArgStringMap &Files,
    111                                  const JobAction *JA,
    112                                  bool IssueErrors) const {
    113   bool Success = true;
    114   for (ArgStringMap::const_iterator
    115          it = Files.begin(), ie = Files.end(); it != ie; ++it) {
    116 
    117     // If specified, only delete the files associated with the JobAction.
    118     // Otherwise, delete all files in the map.
    119     if (JA && it->first != JA)
    120       continue;
    121     Success &= CleanupFile(it->second, IssueErrors);
    122   }
    123   return Success;
    124 }
    125 
    126 int Compilation::ExecuteCommand(const Command &C,
    127                                 const Command *&FailingCommand) const {
    128   if ((getDriver().CCPrintOptions ||
    129        getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
    130     raw_ostream *OS = &llvm::errs();
    131 
    132     // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
    133     // output stream.
    134     if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
    135       std::error_code EC;
    136       OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, EC,
    137                                     llvm::sys::fs::F_Append |
    138                                         llvm::sys::fs::F_Text);
    139       if (EC) {
    140         getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
    141             << EC.message();
    142         FailingCommand = &C;
    143         delete OS;
    144         return 1;
    145       }
    146     }
    147 
    148     if (getDriver().CCPrintOptions)
    149       *OS << "[Logging clang options]";
    150 
    151     C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
    152 
    153     if (OS != &llvm::errs())
    154       delete OS;
    155   }
    156 
    157   std::string Error;
    158   bool ExecutionFailed;
    159   int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
    160   if (!Error.empty()) {
    161     assert(Res && "Error string set with 0 result code!");
    162     getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
    163   }
    164 
    165   if (Res)
    166     FailingCommand = &C;
    167 
    168   return ExecutionFailed ? 1 : Res;
    169 }
    170 
    171 typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList;
    172 
    173 static bool ActionFailed(const Action *A,
    174                          const FailingCommandList &FailingCommands) {
    175 
    176   if (FailingCommands.empty())
    177     return false;
    178 
    179   for (FailingCommandList::const_iterator CI = FailingCommands.begin(),
    180          CE = FailingCommands.end(); CI != CE; ++CI)
    181     if (A == &(CI->second->getSource()))
    182       return true;
    183 
    184   for (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI)
    185     if (ActionFailed(*AI, FailingCommands))
    186       return true;
    187 
    188   return false;
    189 }
    190 
    191 static bool InputsOk(const Command &C,
    192                      const FailingCommandList &FailingCommands) {
    193   return !ActionFailed(&C.getSource(), FailingCommands);
    194 }
    195 
    196 void Compilation::ExecuteJobs(const JobList &Jobs,
    197                               FailingCommandList &FailingCommands) const {
    198   for (const auto &Job : Jobs) {
    199     if (!InputsOk(Job, FailingCommands))
    200       continue;
    201     const Command *FailingCommand = nullptr;
    202     if (int Res = ExecuteCommand(Job, FailingCommand))
    203       FailingCommands.push_back(std::make_pair(Res, FailingCommand));
    204   }
    205 }
    206 
    207 void Compilation::initCompilationForDiagnostics() {
    208   ForDiagnostics = true;
    209 
    210   // Free actions and jobs.
    211   DeleteContainerPointers(Actions);
    212   Jobs.clear();
    213 
    214   // Clear temporary/results file lists.
    215   TempFiles.clear();
    216   ResultFiles.clear();
    217   FailureResultFiles.clear();
    218 
    219   // Remove any user specified output.  Claim any unclaimed arguments, so as
    220   // to avoid emitting warnings about unused args.
    221   OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
    222                                 options::OPT_MMD };
    223   for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
    224     if (TranslatedArgs->hasArg(OutputOpts[i]))
    225       TranslatedArgs->eraseArg(OutputOpts[i]);
    226   }
    227   TranslatedArgs->ClaimAllArgs();
    228 
    229   // Redirect stdout/stderr to /dev/null.
    230   Redirects = new const StringRef*[3]();
    231   Redirects[0] = nullptr;
    232   Redirects[1] = new StringRef();
    233   Redirects[2] = new StringRef();
    234 }
    235 
    236 StringRef Compilation::getSysRoot() const {
    237   return getDriver().SysRoot;
    238 }
    239