clang API Documentation

DependencyFile.cpp
Go to the documentation of this file.
00001 //===--- DependencyFile.cpp - Generate dependency file --------------------===//
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 // This code generates dependency files.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "clang/Frontend/Utils.h"
00015 #include "clang/Basic/FileManager.h"
00016 #include "clang/Basic/SourceManager.h"
00017 #include "clang/Frontend/DependencyOutputOptions.h"
00018 #include "clang/Frontend/FrontendDiagnostic.h"
00019 #include "clang/Lex/DirectoryLookup.h"
00020 #include "clang/Lex/LexDiagnostic.h"
00021 #include "clang/Lex/PPCallbacks.h"
00022 #include "clang/Lex/Preprocessor.h"
00023 #include "clang/Serialization/ASTReader.h"
00024 #include "llvm/ADT/StringSet.h"
00025 #include "llvm/ADT/StringSwitch.h"
00026 #include "llvm/Support/FileSystem.h"
00027 #include "llvm/Support/Path.h"
00028 #include "llvm/Support/raw_ostream.h"
00029 
00030 using namespace clang;
00031 
00032 namespace {
00033 struct DepCollectorPPCallbacks : public PPCallbacks {
00034   DependencyCollector &DepCollector;
00035   SourceManager &SM;
00036   DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM)
00037       : DepCollector(L), SM(SM) { }
00038 
00039   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
00040                    SrcMgr::CharacteristicKind FileType,
00041                    FileID PrevFID) override {
00042     if (Reason != PPCallbacks::EnterFile)
00043       return;
00044 
00045     // Dependency generation really does want to go all the way to the
00046     // file entry for a source location to find out what is depended on.
00047     // We do not want #line markers to affect dependency generation!
00048     const FileEntry *FE =
00049         SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
00050     if (!FE)
00051       return;
00052 
00053     StringRef Filename = FE->getName();
00054 
00055     // Remove leading "./" (or ".//" or "././" etc.)
00056     while (Filename.size() > 2 && Filename[0] == '.' &&
00057            llvm::sys::path::is_separator(Filename[1])) {
00058       Filename = Filename.substr(1);
00059       while (llvm::sys::path::is_separator(Filename[0]))
00060         Filename = Filename.substr(1);
00061     }
00062 
00063     DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
00064                                    FileType != SrcMgr::C_User,
00065                                    /*IsModuleFile*/false, /*IsMissing*/false);
00066   }
00067 
00068   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
00069                           StringRef FileName, bool IsAngled,
00070                           CharSourceRange FilenameRange, const FileEntry *File,
00071                           StringRef SearchPath, StringRef RelativePath,
00072                           const Module *Imported) override {
00073     if (!File)
00074       DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
00075                                      /*IsSystem*/false, /*IsModuleFile*/false,
00076                                      /*IsMissing*/true);
00077     // Files that actually exist are handled by FileChanged.
00078   }
00079 
00080   void EndOfMainFile() override {
00081     DepCollector.finishedMainFile();
00082   }
00083 };
00084 
00085 struct DepCollectorASTListener : public ASTReaderListener {
00086   DependencyCollector &DepCollector;
00087   DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
00088   bool needsInputFileVisitation() override { return true; }
00089   bool needsSystemInputFileVisitation() override {
00090     return DepCollector.needSystemDependencies();
00091   }
00092   void visitModuleFile(StringRef Filename) override {
00093     DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
00094                                    /*IsSystem*/false, /*IsModuleFile*/true,
00095                                    /*IsMissing*/false);
00096   }
00097   bool visitInputFile(StringRef Filename, bool IsSystem,
00098                       bool IsOverridden) override {
00099     if (IsOverridden)
00100       return true;
00101 
00102     DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
00103                                    /*IsModuleFile*/false, /*IsMissing*/false);
00104     return true;
00105   }
00106 };
00107 } // end anonymous namespace
00108 
00109 void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule,
00110                                             bool IsSystem, bool IsModuleFile,
00111                                             bool IsMissing) {
00112   if (Seen.insert(Filename) &&
00113       sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
00114     Dependencies.push_back(Filename);
00115 }
00116 
00117 static bool isSpecialFilename(StringRef Filename) {
00118   return llvm::StringSwitch<bool>(Filename)
00119       .Case("<built-in>", true)
00120       .Case("<stdin>", true)
00121       .Default(false);
00122 }
00123 
00124 bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
00125                                        bool IsSystem, bool IsModuleFile,
00126                                        bool IsMissing) {
00127   return !isSpecialFilename(Filename) &&
00128          (needSystemDependencies() || !IsSystem);
00129 }
00130 
00131 DependencyCollector::~DependencyCollector() { }
00132 void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
00133   PP.addPPCallbacks(
00134       llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager()));
00135 }
00136 void DependencyCollector::attachToASTReader(ASTReader &R) {
00137   R.addListener(llvm::make_unique<DepCollectorASTListener>(*this));
00138 }
00139 
00140 namespace {
00141 /// Private implementation for DependencyFileGenerator
00142 class DFGImpl : public PPCallbacks {
00143   std::vector<std::string> Files;
00144   llvm::StringSet<> FilesSet;
00145   const Preprocessor *PP;
00146   std::string OutputFile;
00147   std::vector<std::string> Targets;
00148   bool IncludeSystemHeaders;
00149   bool PhonyTarget;
00150   bool AddMissingHeaderDeps;
00151   bool SeenMissingHeader;
00152   bool IncludeModuleFiles;
00153 private:
00154   bool FileMatchesDepCriteria(const char *Filename,
00155                               SrcMgr::CharacteristicKind FileType);
00156   void OutputDependencyFile();
00157 
00158 public:
00159   DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts)
00160     : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
00161       IncludeSystemHeaders(Opts.IncludeSystemHeaders),
00162       PhonyTarget(Opts.UsePhonyTargets),
00163       AddMissingHeaderDeps(Opts.AddMissingHeaderDeps),
00164       SeenMissingHeader(false),
00165       IncludeModuleFiles(Opts.IncludeModuleFiles) {}
00166 
00167   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
00168                    SrcMgr::CharacteristicKind FileType,
00169                    FileID PrevFID) override;
00170   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
00171                           StringRef FileName, bool IsAngled,
00172                           CharSourceRange FilenameRange, const FileEntry *File,
00173                           StringRef SearchPath, StringRef RelativePath,
00174                           const Module *Imported) override;
00175 
00176   void EndOfMainFile() override {
00177     OutputDependencyFile();
00178   }
00179 
00180   void AddFilename(StringRef Filename);
00181   bool includeSystemHeaders() const { return IncludeSystemHeaders; }
00182   bool includeModuleFiles() const { return IncludeModuleFiles; }
00183 };
00184 
00185 class DFGASTReaderListener : public ASTReaderListener {
00186   DFGImpl &Parent;
00187 public:
00188   DFGASTReaderListener(DFGImpl &Parent)
00189   : Parent(Parent) { }
00190   bool needsInputFileVisitation() override { return true; }
00191   bool needsSystemInputFileVisitation() override {
00192     return Parent.includeSystemHeaders();
00193   }
00194   void visitModuleFile(StringRef Filename) override;
00195   bool visitInputFile(StringRef Filename, bool isSystem,
00196                       bool isOverridden) override;
00197 };
00198 }
00199 
00200 DependencyFileGenerator::DependencyFileGenerator(void *Impl)
00201 : Impl(Impl) { }
00202 
00203 DependencyFileGenerator *DependencyFileGenerator::CreateAndAttachToPreprocessor(
00204     clang::Preprocessor &PP, const clang::DependencyOutputOptions &Opts) {
00205 
00206   if (Opts.Targets.empty()) {
00207     PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
00208     return nullptr;
00209   }
00210 
00211   // Disable the "file not found" diagnostic if the -MG option was given.
00212   if (Opts.AddMissingHeaderDeps)
00213     PP.SetSuppressIncludeNotFoundError(true);
00214 
00215   DFGImpl *Callback = new DFGImpl(&PP, Opts);
00216   PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callback));
00217   return new DependencyFileGenerator(Callback);
00218 }
00219 
00220 void DependencyFileGenerator::AttachToASTReader(ASTReader &R) {
00221   DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl);
00222   assert(I && "missing implementation");
00223   R.addListener(llvm::make_unique<DFGASTReaderListener>(*I));
00224 }
00225 
00226 /// FileMatchesDepCriteria - Determine whether the given Filename should be
00227 /// considered as a dependency.
00228 bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
00229                                      SrcMgr::CharacteristicKind FileType) {
00230   if (isSpecialFilename(Filename))
00231     return false;
00232 
00233   if (IncludeSystemHeaders)
00234     return true;
00235 
00236   return FileType == SrcMgr::C_User;
00237 }
00238 
00239 void DFGImpl::FileChanged(SourceLocation Loc,
00240                           FileChangeReason Reason,
00241                           SrcMgr::CharacteristicKind FileType,
00242                           FileID PrevFID) {
00243   if (Reason != PPCallbacks::EnterFile)
00244     return;
00245 
00246   // Dependency generation really does want to go all the way to the
00247   // file entry for a source location to find out what is depended on.
00248   // We do not want #line markers to affect dependency generation!
00249   SourceManager &SM = PP->getSourceManager();
00250 
00251   const FileEntry *FE =
00252     SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
00253   if (!FE) return;
00254 
00255   StringRef Filename = FE->getName();
00256   if (!FileMatchesDepCriteria(Filename.data(), FileType))
00257     return;
00258 
00259   // Remove leading "./" (or ".//" or "././" etc.)
00260   while (Filename.size() > 2 && Filename[0] == '.' &&
00261          llvm::sys::path::is_separator(Filename[1])) {
00262     Filename = Filename.substr(1);
00263     while (llvm::sys::path::is_separator(Filename[0]))
00264       Filename = Filename.substr(1);
00265   }
00266     
00267   AddFilename(Filename);
00268 }
00269 
00270 void DFGImpl::InclusionDirective(SourceLocation HashLoc,
00271                                  const Token &IncludeTok,
00272                                  StringRef FileName,
00273                                  bool IsAngled,
00274                                  CharSourceRange FilenameRange,
00275                                  const FileEntry *File,
00276                                  StringRef SearchPath,
00277                                  StringRef RelativePath,
00278                                  const Module *Imported) {
00279   if (!File) {
00280     if (AddMissingHeaderDeps)
00281       AddFilename(FileName);
00282     else
00283       SeenMissingHeader = true;
00284   }
00285 }
00286 
00287 void DFGImpl::AddFilename(StringRef Filename) {
00288   if (FilesSet.insert(Filename))
00289     Files.push_back(Filename);
00290 }
00291 
00292 /// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or
00293 /// other scary characters.
00294 static void PrintFilename(raw_ostream &OS, StringRef Filename) {
00295   for (unsigned i = 0, e = Filename.size(); i != e; ++i) {
00296     if (Filename[i] == ' ' || Filename[i] == '#')
00297       OS << '\\';
00298     else if (Filename[i] == '$') // $ is escaped by $$.
00299       OS << '$';
00300     OS << Filename[i];
00301   }
00302 }
00303 
00304 void DFGImpl::OutputDependencyFile() {
00305   if (SeenMissingHeader) {
00306     llvm::sys::fs::remove(OutputFile);
00307     return;
00308   }
00309 
00310   std::error_code EC;
00311   llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
00312   if (EC) {
00313     PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
00314                                                             << EC.message();
00315     return;
00316   }
00317 
00318   // Write out the dependency targets, trying to avoid overly long
00319   // lines when possible. We try our best to emit exactly the same
00320   // dependency file as GCC (4.2), assuming the included files are the
00321   // same.
00322   const unsigned MaxColumns = 75;
00323   unsigned Columns = 0;
00324 
00325   for (std::vector<std::string>::iterator
00326          I = Targets.begin(), E = Targets.end(); I != E; ++I) {
00327     unsigned N = I->length();
00328     if (Columns == 0) {
00329       Columns += N;
00330     } else if (Columns + N + 2 > MaxColumns) {
00331       Columns = N + 2;
00332       OS << " \\\n  ";
00333     } else {
00334       Columns += N + 1;
00335       OS << ' ';
00336     }
00337     // Targets already quoted as needed.
00338     OS << *I;
00339   }
00340 
00341   OS << ':';
00342   Columns += 1;
00343 
00344   // Now add each dependency in the order it was seen, but avoiding
00345   // duplicates.
00346   for (std::vector<std::string>::iterator I = Files.begin(),
00347          E = Files.end(); I != E; ++I) {
00348     // Start a new line if this would exceed the column limit. Make
00349     // sure to leave space for a trailing " \" in case we need to
00350     // break the line on the next iteration.
00351     unsigned N = I->length();
00352     if (Columns + (N + 1) + 2 > MaxColumns) {
00353       OS << " \\\n ";
00354       Columns = 2;
00355     }
00356     OS << ' ';
00357     PrintFilename(OS, *I);
00358     Columns += N + 1;
00359   }
00360   OS << '\n';
00361 
00362   // Create phony targets if requested.
00363   if (PhonyTarget && !Files.empty()) {
00364     // Skip the first entry, this is always the input file itself.
00365     for (std::vector<std::string>::iterator I = Files.begin() + 1,
00366            E = Files.end(); I != E; ++I) {
00367       OS << '\n';
00368       PrintFilename(OS, *I);
00369       OS << ":\n";
00370     }
00371   }
00372 }
00373 
00374 bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
00375                                           bool IsSystem, bool IsOverridden) {
00376   assert(!IsSystem || needsSystemInputFileVisitation());
00377   if (IsOverridden)
00378     return true;
00379 
00380   Parent.AddFilename(Filename);
00381   return true;
00382 }
00383 
00384 void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename) {
00385   if (Parent.includeModuleFiles())
00386     Parent.AddFilename(Filename);
00387 }