clang API Documentation

Job.cpp
Go to the documentation of this file.
00001 //===--- Job.cpp - Command to Execute -------------------------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "clang/Driver/Driver.h"
00011 #include "clang/Driver/DriverDiagnostic.h"
00012 #include "clang/Driver/Job.h"
00013 #include "clang/Driver/Tool.h"
00014 #include "clang/Driver/ToolChain.h"
00015 #include "llvm/ADT/ArrayRef.h"
00016 #include "llvm/ADT/STLExtras.h"
00017 #include "llvm/ADT/StringRef.h"
00018 #include "llvm/ADT/StringSet.h"
00019 #include "llvm/ADT/StringSwitch.h"
00020 #include "llvm/Support/Program.h"
00021 #include "llvm/Support/raw_ostream.h"
00022 #include <cassert>
00023 using namespace clang::driver;
00024 using llvm::raw_ostream;
00025 using llvm::StringRef;
00026 using llvm::ArrayRef;
00027 
00028 Job::~Job() {}
00029 
00030 Command::Command(const Action &_Source, const Tool &_Creator,
00031                  const char *_Executable,
00032                  const ArgStringList &_Arguments)
00033     : Job(CommandClass), Source(_Source), Creator(_Creator),
00034       Executable(_Executable), Arguments(_Arguments),
00035       ResponseFile(nullptr) {}
00036 
00037 static int skipArgs(const char *Flag) {
00038   // These flags are all of the form -Flag <Arg> and are treated as two
00039   // arguments.  Therefore, we need to skip the flag and the next argument.
00040   bool Res = llvm::StringSwitch<bool>(Flag)
00041     .Cases("-I", "-MF", "-MT", "-MQ", true)
00042     .Cases("-o", "-coverage-file", "-dependency-file", true)
00043     .Cases("-fdebug-compilation-dir", "-idirafter", true)
00044     .Cases("-include", "-include-pch", "-internal-isystem", true)
00045     .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
00046     .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
00047     .Cases("-resource-dir", "-serialize-diagnostic-file", true)
00048     .Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
00049     .Default(false);
00050 
00051   // Match found.
00052   if (Res)
00053     return 2;
00054 
00055   // The remaining flags are treated as a single argument.
00056 
00057   // These flags are all of the form -Flag and have no second argument.
00058   Res = llvm::StringSwitch<bool>(Flag)
00059     .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
00060     .Case("-MMD", true)
00061     .Default(false);
00062 
00063   // Match found.
00064   if (Res)
00065     return 1;
00066 
00067   // These flags are treated as a single argument (e.g., -F<Dir>).
00068   StringRef FlagRef(Flag);
00069   if (FlagRef.startswith("-F") || FlagRef.startswith("-I") ||
00070       FlagRef.startswith("-fmodules-cache-path="))
00071     return 1;
00072 
00073   return 0;
00074 }
00075 
00076 static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) {
00077   const bool Escape = std::strpbrk(Arg, "\"\\$");
00078 
00079   if (!Quote && !Escape) {
00080     OS << Arg;
00081     return;
00082   }
00083 
00084   // Quote and escape. This isn't really complete, but good enough.
00085   OS << '"';
00086   while (const char c = *Arg++) {
00087     if (c == '"' || c == '\\' || c == '$')
00088       OS << '\\';
00089     OS << c;
00090   }
00091   OS << '"';
00092 }
00093 
00094 void Command::writeResponseFile(raw_ostream &OS) const {
00095   // In a file list, we only write the set of inputs to the response file
00096   if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
00097     for (const char *Arg : InputFileList) {
00098       OS << Arg << '\n';
00099     }
00100     return;
00101   }
00102 
00103   // In regular response files, we send all arguments to the response file
00104   for (const char *Arg : Arguments) {
00105     OS << '"';
00106 
00107     for (; *Arg != '\0'; Arg++) {
00108       if (*Arg == '\"' || *Arg == '\\') {
00109         OS << '\\';
00110       }
00111       OS << *Arg;
00112     }
00113 
00114     OS << "\" ";
00115   }
00116 }
00117 
00118 void Command::buildArgvForResponseFile(
00119     llvm::SmallVectorImpl<const char *> &Out) const {
00120   // When not a file list, all arguments are sent to the response file.
00121   // This leaves us to set the argv to a single parameter, requesting the tool
00122   // to read the response file.
00123   if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
00124     Out.push_back(Executable);
00125     Out.push_back(ResponseFileFlag.c_str());
00126     return;
00127   }
00128 
00129   llvm::StringSet<> Inputs;
00130   for (const char *InputName : InputFileList)
00131     Inputs.insert(InputName);
00132   Out.push_back(Executable);
00133   // In a file list, build args vector ignoring parameters that will go in the
00134   // response file (elements of the InputFileList vector)
00135   bool FirstInput = true;
00136   for (const char *Arg : Arguments) {
00137     if (Inputs.count(Arg) == 0) {
00138       Out.push_back(Arg);
00139     } else if (FirstInput) {
00140       FirstInput = false;
00141       Out.push_back(Creator.getResponseFileFlag());
00142       Out.push_back(ResponseFile);
00143     }
00144   }
00145 }
00146 
00147 void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
00148                     CrashReportInfo *CrashInfo) const {
00149   // Always quote the exe.
00150   OS << ' ';
00151   PrintArg(OS, Executable, /*Quote=*/true);
00152 
00153   llvm::ArrayRef<const char *> Args = Arguments;
00154   llvm::SmallVector<const char *, 128> ArgsRespFile;
00155   if (ResponseFile != nullptr) {
00156     buildArgvForResponseFile(ArgsRespFile);
00157     Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
00158   }
00159 
00160   StringRef MainFilename;
00161   // We'll need the argument to -main-file-name to find the input file name.
00162   if (CrashInfo)
00163     for (size_t I = 0, E = Args.size(); I + 1 < E; ++I)
00164       if (StringRef(Args[I]).equals("-main-file-name"))
00165         MainFilename = Args[I + 1];
00166 
00167   for (size_t i = 0, e = Args.size(); i < e; ++i) {
00168     const char *const Arg = Args[i];
00169 
00170     if (CrashInfo) {
00171       if (int Skip = skipArgs(Arg)) {
00172         i += Skip - 1;
00173         continue;
00174       } else if (llvm::sys::path::filename(Arg) == MainFilename &&
00175                  (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) {
00176         // Replace the input file name with the crashinfo's file name.
00177         OS << ' ';
00178         StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename);
00179         PrintArg(OS, ShortName.str().c_str(), Quote);
00180         continue;
00181       }
00182     }
00183 
00184     OS << ' ';
00185     PrintArg(OS, Arg, Quote);
00186   }
00187 
00188   if (CrashInfo && !CrashInfo->VFSPath.empty()) {
00189     OS << ' ';
00190     PrintArg(OS, "-ivfsoverlay", Quote);
00191     OS << ' ';
00192     PrintArg(OS, CrashInfo->VFSPath.str().c_str(), Quote);
00193   }
00194 
00195   if (ResponseFile != nullptr) {
00196     OS << "\n Arguments passed via response file:\n";
00197     writeResponseFile(OS);
00198     // Avoiding duplicated newline terminator, since FileLists are
00199     // newline-separated.
00200     if (Creator.getResponseFilesSupport() != Tool::RF_FileList)
00201       OS << "\n";
00202     OS << " (end of response file)";
00203   }
00204 
00205   OS << Terminator;
00206 }
00207 
00208 void Command::setResponseFile(const char *FileName) {
00209   ResponseFile = FileName;
00210   ResponseFileFlag = Creator.getResponseFileFlag();
00211   ResponseFileFlag += FileName;
00212 }
00213 
00214 int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
00215                      bool *ExecutionFailed) const {
00216   SmallVector<const char*, 128> Argv;
00217 
00218   if (ResponseFile == nullptr) {
00219     Argv.push_back(Executable);
00220     for (size_t i = 0, e = Arguments.size(); i != e; ++i)
00221       Argv.push_back(Arguments[i]);
00222     Argv.push_back(nullptr);
00223 
00224     return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
00225                                      Redirects, /*secondsToWait*/ 0,
00226                                      /*memoryLimit*/ 0, ErrMsg,
00227                                      ExecutionFailed);
00228   }
00229 
00230   // We need to put arguments in a response file (command is too large)
00231   // Open stream to store the response file contents
00232   std::string RespContents;
00233   llvm::raw_string_ostream SS(RespContents);
00234 
00235   // Write file contents and build the Argv vector
00236   writeResponseFile(SS);
00237   buildArgvForResponseFile(Argv);
00238   Argv.push_back(nullptr);
00239   SS.flush();
00240 
00241   // Save the response file in the appropriate encoding
00242   if (std::error_code EC = writeFileWithEncoding(
00243           ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
00244     if (ErrMsg)
00245       *ErrMsg = EC.message();
00246     if (ExecutionFailed)
00247       *ExecutionFailed = true;
00248     return -1;
00249   }
00250 
00251   return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
00252                                    Redirects, /*secondsToWait*/ 0,
00253                                    /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
00254 }
00255 
00256 FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
00257                                  const char *Executable_,
00258                                  const ArgStringList &Arguments_,
00259                                  std::unique_ptr<Command> Fallback_)
00260     : Command(Source_, Creator_, Executable_, Arguments_),
00261       Fallback(std::move(Fallback_)) {}
00262 
00263 void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
00264                             bool Quote, CrashReportInfo *CrashInfo) const {
00265   Command::Print(OS, "", Quote, CrashInfo);
00266   OS << " ||";
00267   Fallback->Print(OS, Terminator, Quote, CrashInfo);
00268 }
00269 
00270 static bool ShouldFallback(int ExitCode) {
00271   // FIXME: We really just want to fall back for internal errors, such
00272   // as when some symbol cannot be mangled, when we should be able to
00273   // parse something but can't, etc.
00274   return ExitCode != 0;
00275 }
00276 
00277 int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
00278                              bool *ExecutionFailed) const {
00279   int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
00280   if (!ShouldFallback(PrimaryStatus))
00281     return PrimaryStatus;
00282 
00283   // Clear ExecutionFailed and ErrMsg before falling back.
00284   if (ErrMsg)
00285     ErrMsg->clear();
00286   if (ExecutionFailed)
00287     *ExecutionFailed = false;
00288 
00289   const Driver &D = getCreator().getToolChain().getDriver();
00290   D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
00291 
00292   int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
00293   return SecondaryStatus;
00294 }
00295 
00296 JobList::JobList() : Job(JobListClass) {}
00297 
00298 void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
00299                     CrashReportInfo *CrashInfo) const {
00300   for (const auto &Job : *this)
00301     Job.Print(OS, Terminator, Quote, CrashInfo);
00302 }
00303 
00304 void JobList::clear() { Jobs.clear(); }