Home | History | Annotate | Download | only in Driver
      1 //===--- Job.cpp - Command to Execute -------------------------------------===//
      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 "InputInfo.h"
     11 #include "clang/Driver/Driver.h"
     12 #include "clang/Driver/DriverDiagnostic.h"
     13 #include "clang/Driver/Job.h"
     14 #include "clang/Driver/Tool.h"
     15 #include "clang/Driver/ToolChain.h"
     16 #include "llvm/ADT/ArrayRef.h"
     17 #include "llvm/ADT/STLExtras.h"
     18 #include "llvm/ADT/StringRef.h"
     19 #include "llvm/ADT/StringSet.h"
     20 #include "llvm/ADT/StringSwitch.h"
     21 #include "llvm/Support/Program.h"
     22 #include "llvm/Support/raw_ostream.h"
     23 #include <cassert>
     24 using namespace clang::driver;
     25 using llvm::raw_ostream;
     26 using llvm::StringRef;
     27 using llvm::ArrayRef;
     28 
     29 Command::Command(const Action &Source, const Tool &Creator,
     30                  const char *Executable, const ArgStringList &Arguments,
     31                  ArrayRef<InputInfo> Inputs)
     32     : Source(Source), Creator(Creator), Executable(Executable),
     33       Arguments(Arguments), ResponseFile(nullptr) {
     34   for (const auto &II : Inputs)
     35     if (II.isFilename())
     36       InputFilenames.push_back(II.getFilename());
     37 }
     38 
     39 static int skipArgs(const char *Flag, bool HaveCrashVFS) {
     40   // These flags are all of the form -Flag <Arg> and are treated as two
     41   // arguments.  Therefore, we need to skip the flag and the next argument.
     42   bool Res = llvm::StringSwitch<bool>(Flag)
     43     .Cases("-I", "-MF", "-MT", "-MQ", true)
     44     .Cases("-o", "-coverage-file", "-dependency-file", true)
     45     .Cases("-fdebug-compilation-dir", "-idirafter", true)
     46     .Cases("-include", "-include-pch", "-internal-isystem", true)
     47     .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
     48     .Cases("-iwithprefixbefore", "-isystem", "-iquote", true)
     49     .Cases("-resource-dir", "-serialize-diagnostic-file", true)
     50     .Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
     51     .Cases("-header-include-file", "-diagnostic-log-file", true)
     52     // Some include flags shouldn't be skipped if we have a crash VFS
     53     .Case("-isysroot", !HaveCrashVFS)
     54     .Default(false);
     55 
     56   // Match found.
     57   if (Res)
     58     return 2;
     59 
     60   // The remaining flags are treated as a single argument.
     61 
     62   // These flags are all of the form -Flag and have no second argument.
     63   Res = llvm::StringSwitch<bool>(Flag)
     64     .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
     65     .Case("-MMD", true)
     66     .Default(false);
     67 
     68   // Match found.
     69   if (Res)
     70     return 1;
     71 
     72   // These flags are treated as a single argument (e.g., -F<Dir>).
     73   StringRef FlagRef(Flag);
     74   if (FlagRef.startswith("-F") || FlagRef.startswith("-I") ||
     75       FlagRef.startswith("-fmodules-cache-path="))
     76     return 1;
     77 
     78   return 0;
     79 }
     80 
     81 void Command::printArg(raw_ostream &OS, const char *Arg, bool Quote) {
     82   const bool Escape = std::strpbrk(Arg, "\"\\$");
     83 
     84   if (!Quote && !Escape) {
     85     OS << Arg;
     86     return;
     87   }
     88 
     89   // Quote and escape. This isn't really complete, but good enough.
     90   OS << '"';
     91   while (const char c = *Arg++) {
     92     if (c == '"' || c == '\\' || c == '$')
     93       OS << '\\';
     94     OS << c;
     95   }
     96   OS << '"';
     97 }
     98 
     99 void Command::writeResponseFile(raw_ostream &OS) const {
    100   // In a file list, we only write the set of inputs to the response file
    101   if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
    102     for (const char *Arg : InputFileList) {
    103       OS << Arg << '\n';
    104     }
    105     return;
    106   }
    107 
    108   // In regular response files, we send all arguments to the response file.
    109   // Wrapping all arguments in double quotes ensures that both Unix tools and
    110   // Windows tools understand the response file.
    111   for (const char *Arg : Arguments) {
    112     OS << '"';
    113 
    114     for (; *Arg != '\0'; Arg++) {
    115       if (*Arg == '\"' || *Arg == '\\') {
    116         OS << '\\';
    117       }
    118       OS << *Arg;
    119     }
    120 
    121     OS << "\" ";
    122   }
    123 }
    124 
    125 void Command::buildArgvForResponseFile(
    126     llvm::SmallVectorImpl<const char *> &Out) const {
    127   // When not a file list, all arguments are sent to the response file.
    128   // This leaves us to set the argv to a single parameter, requesting the tool
    129   // to read the response file.
    130   if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
    131     Out.push_back(Executable);
    132     Out.push_back(ResponseFileFlag.c_str());
    133     return;
    134   }
    135 
    136   llvm::StringSet<> Inputs;
    137   for (const char *InputName : InputFileList)
    138     Inputs.insert(InputName);
    139   Out.push_back(Executable);
    140   // In a file list, build args vector ignoring parameters that will go in the
    141   // response file (elements of the InputFileList vector)
    142   bool FirstInput = true;
    143   for (const char *Arg : Arguments) {
    144     if (Inputs.count(Arg) == 0) {
    145       Out.push_back(Arg);
    146     } else if (FirstInput) {
    147       FirstInput = false;
    148       Out.push_back(Creator.getResponseFileFlag());
    149       Out.push_back(ResponseFile);
    150     }
    151   }
    152 }
    153 
    154 void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
    155                     CrashReportInfo *CrashInfo) const {
    156   // Always quote the exe.
    157   OS << ' ';
    158   printArg(OS, Executable, /*Quote=*/true);
    159 
    160   llvm::ArrayRef<const char *> Args = Arguments;
    161   llvm::SmallVector<const char *, 128> ArgsRespFile;
    162   if (ResponseFile != nullptr) {
    163     buildArgvForResponseFile(ArgsRespFile);
    164     Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
    165   }
    166 
    167   bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
    168   for (size_t i = 0, e = Args.size(); i < e; ++i) {
    169     const char *const Arg = Args[i];
    170 
    171     if (CrashInfo) {
    172       if (int Skip = skipArgs(Arg, HaveCrashVFS)) {
    173         i += Skip - 1;
    174         continue;
    175       }
    176       auto Found = std::find_if(InputFilenames.begin(), InputFilenames.end(),
    177                                 [&Arg](StringRef IF) { return IF == Arg; });
    178       if (Found != InputFilenames.end() &&
    179           (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
    180         // Replace the input file name with the crashinfo's file name.
    181         OS << ' ';
    182         StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
    183         printArg(OS, ShortName.str().c_str(), Quote);
    184         continue;
    185       }
    186     }
    187 
    188     OS << ' ';
    189     printArg(OS, Arg, Quote);
    190   }
    191 
    192   if (CrashInfo && HaveCrashVFS) {
    193     OS << ' ';
    194     printArg(OS, "-ivfsoverlay", Quote);
    195     OS << ' ';
    196     printArg(OS, CrashInfo->VFSPath.str().c_str(), Quote);
    197   }
    198 
    199   if (ResponseFile != nullptr) {
    200     OS << "\n Arguments passed via response file:\n";
    201     writeResponseFile(OS);
    202     // Avoiding duplicated newline terminator, since FileLists are
    203     // newline-separated.
    204     if (Creator.getResponseFilesSupport() != Tool::RF_FileList)
    205       OS << "\n";
    206     OS << " (end of response file)";
    207   }
    208 
    209   OS << Terminator;
    210 }
    211 
    212 void Command::setResponseFile(const char *FileName) {
    213   ResponseFile = FileName;
    214   ResponseFileFlag = Creator.getResponseFileFlag();
    215   ResponseFileFlag += FileName;
    216 }
    217 
    218 int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
    219                      bool *ExecutionFailed) const {
    220   SmallVector<const char*, 128> Argv;
    221 
    222   if (ResponseFile == nullptr) {
    223     Argv.push_back(Executable);
    224     Argv.append(Arguments.begin(), Arguments.end());
    225     Argv.push_back(nullptr);
    226 
    227     return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
    228                                      Redirects, /*secondsToWait*/ 0,
    229                                      /*memoryLimit*/ 0, ErrMsg,
    230                                      ExecutionFailed);
    231   }
    232 
    233   // We need to put arguments in a response file (command is too large)
    234   // Open stream to store the response file contents
    235   std::string RespContents;
    236   llvm::raw_string_ostream SS(RespContents);
    237 
    238   // Write file contents and build the Argv vector
    239   writeResponseFile(SS);
    240   buildArgvForResponseFile(Argv);
    241   Argv.push_back(nullptr);
    242   SS.flush();
    243 
    244   // Save the response file in the appropriate encoding
    245   if (std::error_code EC = writeFileWithEncoding(
    246           ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
    247     if (ErrMsg)
    248       *ErrMsg = EC.message();
    249     if (ExecutionFailed)
    250       *ExecutionFailed = true;
    251     return -1;
    252   }
    253 
    254   return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
    255                                    Redirects, /*secondsToWait*/ 0,
    256                                    /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
    257 }
    258 
    259 FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
    260                                  const char *Executable_,
    261                                  const ArgStringList &Arguments_,
    262                                  ArrayRef<InputInfo> Inputs,
    263                                  std::unique_ptr<Command> Fallback_)
    264     : Command(Source_, Creator_, Executable_, Arguments_, Inputs),
    265       Fallback(std::move(Fallback_)) {}
    266 
    267 void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
    268                             bool Quote, CrashReportInfo *CrashInfo) const {
    269   Command::Print(OS, "", Quote, CrashInfo);
    270   OS << " ||";
    271   Fallback->Print(OS, Terminator, Quote, CrashInfo);
    272 }
    273 
    274 static bool ShouldFallback(int ExitCode) {
    275   // FIXME: We really just want to fall back for internal errors, such
    276   // as when some symbol cannot be mangled, when we should be able to
    277   // parse something but can't, etc.
    278   return ExitCode != 0;
    279 }
    280 
    281 int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
    282                              bool *ExecutionFailed) const {
    283   int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
    284   if (!ShouldFallback(PrimaryStatus))
    285     return PrimaryStatus;
    286 
    287   // Clear ExecutionFailed and ErrMsg before falling back.
    288   if (ErrMsg)
    289     ErrMsg->clear();
    290   if (ExecutionFailed)
    291     *ExecutionFailed = false;
    292 
    293   const Driver &D = getCreator().getToolChain().getDriver();
    294   D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
    295 
    296   int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
    297   return SecondaryStatus;
    298 }
    299 
    300 void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
    301                     CrashReportInfo *CrashInfo) const {
    302   for (const auto &Job : *this)
    303     Job.Print(OS, Terminator, Quote, CrashInfo);
    304 }
    305 
    306 void JobList::clear() { Jobs.clear(); }
    307