clang API Documentation
00001 //===--- Compilation.cpp - Compilation Task Implementation ----------------===// 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/Compilation.h" 00011 #include "clang/Driver/Action.h" 00012 #include "clang/Driver/Driver.h" 00013 #include "clang/Driver/DriverDiagnostic.h" 00014 #include "clang/Driver/Options.h" 00015 #include "clang/Driver/ToolChain.h" 00016 #include "llvm/ADT/STLExtras.h" 00017 #include "llvm/Option/ArgList.h" 00018 #include "llvm/Support/FileSystem.h" 00019 #include "llvm/Support/raw_ostream.h" 00020 00021 using namespace clang::driver; 00022 using namespace clang; 00023 using namespace llvm::opt; 00024 00025 Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, 00026 InputArgList *_Args, DerivedArgList *_TranslatedArgs) 00027 : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args), 00028 TranslatedArgs(_TranslatedArgs), Redirects(nullptr), 00029 ForDiagnostics(false) {} 00030 00031 Compilation::~Compilation() { 00032 delete TranslatedArgs; 00033 delete Args; 00034 00035 // Free any derived arg lists. 00036 for (llvm::DenseMap<std::pair<const ToolChain*, const char*>, 00037 DerivedArgList*>::iterator it = TCArgs.begin(), 00038 ie = TCArgs.end(); it != ie; ++it) 00039 if (it->second != TranslatedArgs) 00040 delete it->second; 00041 00042 // Free the actions, if built. 00043 for (ActionList::iterator it = Actions.begin(), ie = Actions.end(); 00044 it != ie; ++it) 00045 delete *it; 00046 00047 // Free redirections of stdout/stderr. 00048 if (Redirects) { 00049 delete Redirects[1]; 00050 delete Redirects[2]; 00051 delete [] Redirects; 00052 } 00053 } 00054 00055 const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC, 00056 const char *BoundArch) { 00057 if (!TC) 00058 TC = &DefaultToolChain; 00059 00060 DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)]; 00061 if (!Entry) { 00062 Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch); 00063 if (!Entry) 00064 Entry = TranslatedArgs; 00065 } 00066 00067 return *Entry; 00068 } 00069 00070 bool Compilation::CleanupFile(const char *File, bool IssueErrors) const { 00071 // FIXME: Why are we trying to remove files that we have not created? For 00072 // example we should only try to remove a temporary assembly file if 00073 // "clang -cc1" succeed in writing it. Was this a workaround for when 00074 // clang was writing directly to a .s file and sometimes leaving it behind 00075 // during a failure? 00076 00077 // FIXME: If this is necessary, we can still try to split 00078 // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the 00079 // duplicated stat from is_regular_file. 00080 00081 // Don't try to remove files which we don't have write access to (but may be 00082 // able to remove), or non-regular files. Underlying tools may have 00083 // intentionally not overwritten them. 00084 if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File)) 00085 return true; 00086 00087 if (std::error_code EC = llvm::sys::fs::remove(File)) { 00088 // Failure is only failure if the file exists and is "regular". We checked 00089 // for it being regular before, and llvm::sys::fs::remove ignores ENOENT, 00090 // so we don't need to check again. 00091 00092 if (IssueErrors) 00093 getDriver().Diag(clang::diag::err_drv_unable_to_remove_file) 00094 << EC.message(); 00095 return false; 00096 } 00097 return true; 00098 } 00099 00100 bool Compilation::CleanupFileList(const ArgStringList &Files, 00101 bool IssueErrors) const { 00102 bool Success = true; 00103 for (ArgStringList::const_iterator 00104 it = Files.begin(), ie = Files.end(); it != ie; ++it) 00105 Success &= CleanupFile(*it, IssueErrors); 00106 return Success; 00107 } 00108 00109 bool Compilation::CleanupFileMap(const ArgStringMap &Files, 00110 const JobAction *JA, 00111 bool IssueErrors) const { 00112 bool Success = true; 00113 for (ArgStringMap::const_iterator 00114 it = Files.begin(), ie = Files.end(); it != ie; ++it) { 00115 00116 // If specified, only delete the files associated with the JobAction. 00117 // Otherwise, delete all files in the map. 00118 if (JA && it->first != JA) 00119 continue; 00120 Success &= CleanupFile(it->second, IssueErrors); 00121 } 00122 return Success; 00123 } 00124 00125 int Compilation::ExecuteCommand(const Command &C, 00126 const Command *&FailingCommand) const { 00127 if ((getDriver().CCPrintOptions || 00128 getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { 00129 raw_ostream *OS = &llvm::errs(); 00130 00131 // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the 00132 // output stream. 00133 if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) { 00134 std::error_code EC; 00135 OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, EC, 00136 llvm::sys::fs::F_Append | 00137 llvm::sys::fs::F_Text); 00138 if (EC) { 00139 getDriver().Diag(clang::diag::err_drv_cc_print_options_failure) 00140 << EC.message(); 00141 FailingCommand = &C; 00142 delete OS; 00143 return 1; 00144 } 00145 } 00146 00147 if (getDriver().CCPrintOptions) 00148 *OS << "[Logging clang options]"; 00149 00150 C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions); 00151 00152 if (OS != &llvm::errs()) 00153 delete OS; 00154 } 00155 00156 std::string Error; 00157 bool ExecutionFailed; 00158 int Res = C.Execute(Redirects, &Error, &ExecutionFailed); 00159 if (!Error.empty()) { 00160 assert(Res && "Error string set with 0 result code!"); 00161 getDriver().Diag(clang::diag::err_drv_command_failure) << Error; 00162 } 00163 00164 if (Res) 00165 FailingCommand = &C; 00166 00167 return ExecutionFailed ? 1 : Res; 00168 } 00169 00170 typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList; 00171 00172 static bool ActionFailed(const Action *A, 00173 const FailingCommandList &FailingCommands) { 00174 00175 if (FailingCommands.empty()) 00176 return false; 00177 00178 for (FailingCommandList::const_iterator CI = FailingCommands.begin(), 00179 CE = FailingCommands.end(); CI != CE; ++CI) 00180 if (A == &(CI->second->getSource())) 00181 return true; 00182 00183 for (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI) 00184 if (ActionFailed(*AI, FailingCommands)) 00185 return true; 00186 00187 return false; 00188 } 00189 00190 static bool InputsOk(const Command &C, 00191 const FailingCommandList &FailingCommands) { 00192 return !ActionFailed(&C.getSource(), FailingCommands); 00193 } 00194 00195 void Compilation::ExecuteJob(const Job &J, 00196 FailingCommandList &FailingCommands) const { 00197 if (const Command *C = dyn_cast<Command>(&J)) { 00198 if (!InputsOk(*C, FailingCommands)) 00199 return; 00200 const Command *FailingCommand = nullptr; 00201 if (int Res = ExecuteCommand(*C, FailingCommand)) 00202 FailingCommands.push_back(std::make_pair(Res, FailingCommand)); 00203 } else { 00204 const JobList *Jobs = cast<JobList>(&J); 00205 for (const auto &Job : *Jobs) 00206 ExecuteJob(Job, FailingCommands); 00207 } 00208 } 00209 00210 void Compilation::initCompilationForDiagnostics() { 00211 ForDiagnostics = true; 00212 00213 // Free actions and jobs. 00214 DeleteContainerPointers(Actions); 00215 Jobs.clear(); 00216 00217 // Clear temporary/results file lists. 00218 TempFiles.clear(); 00219 ResultFiles.clear(); 00220 FailureResultFiles.clear(); 00221 00222 // Remove any user specified output. Claim any unclaimed arguments, so as 00223 // to avoid emitting warnings about unused args. 00224 OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD, 00225 options::OPT_MMD }; 00226 for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) { 00227 if (TranslatedArgs->hasArg(OutputOpts[i])) 00228 TranslatedArgs->eraseArg(OutputOpts[i]); 00229 } 00230 TranslatedArgs->ClaimAllArgs(); 00231 00232 // Redirect stdout/stderr to /dev/null. 00233 Redirects = new const StringRef*[3](); 00234 Redirects[0] = nullptr; 00235 Redirects[1] = new StringRef(); 00236 Redirects[2] = new StringRef(); 00237 } 00238 00239 StringRef Compilation::getSysRoot() const { 00240 return getDriver().SysRoot; 00241 }