Home | History | Annotate | Download | only in Frontend
      1 //===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//
      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 // Collect the dependencies of a set of modules.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "clang/Basic/CharInfo.h"
     15 #include "clang/Frontend/Utils.h"
     16 #include "clang/Lex/Preprocessor.h"
     17 #include "clang/Serialization/ASTReader.h"
     18 #include "llvm/ADT/StringMap.h"
     19 #include "llvm/ADT/iterator_range.h"
     20 #include "llvm/Support/FileSystem.h"
     21 #include "llvm/Support/Path.h"
     22 #include "llvm/Support/raw_ostream.h"
     23 
     24 using namespace clang;
     25 
     26 namespace {
     27 /// Private implementations for ModuleDependencyCollector
     28 class ModuleDependencyListener : public ASTReaderListener {
     29   ModuleDependencyCollector &Collector;
     30 public:
     31   ModuleDependencyListener(ModuleDependencyCollector &Collector)
     32       : Collector(Collector) {}
     33   bool needsInputFileVisitation() override { return true; }
     34   bool needsSystemInputFileVisitation() override { return true; }
     35   bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
     36                       bool IsExplicitModule) override {
     37     Collector.addFile(Filename);
     38     return true;
     39   }
     40 };
     41 
     42 struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks {
     43   ModuleDependencyCollector &Collector;
     44   ModuleDependencyMMCallbacks(ModuleDependencyCollector &Collector)
     45       : Collector(Collector) {}
     46 
     47   void moduleMapAddHeader(StringRef HeaderPath) override {
     48     if (llvm::sys::path::is_absolute(HeaderPath))
     49       Collector.addFile(HeaderPath);
     50   }
     51   void moduleMapAddUmbrellaHeader(FileManager *FileMgr,
     52                                   const FileEntry *Header) override {
     53     StringRef HeaderFilename = Header->getName();
     54     moduleMapAddHeader(HeaderFilename);
     55     // The FileManager can find and cache the symbolic link for a framework
     56     // header before its real path, this means a module can have some of its
     57     // headers to use other paths. Although this is usually not a problem, it's
     58     // inconsistent, and not collecting the original path header leads to
     59     // umbrella clashes while rebuilding modules in the crash reproducer. For
     60     // example:
     61     //    ApplicationServices.framework/Frameworks/ImageIO.framework/ImageIO.h
     62     // instead of:
     63     //    ImageIO.framework/ImageIO.h
     64     //
     65     // FIXME: this shouldn't be necessary once we have FileName instances
     66     // around instead of FileEntry ones. For now, make sure we collect all
     67     // that we need for the reproducer to work correctly.
     68     StringRef UmbreallDirFromHeader =
     69         llvm::sys::path::parent_path(HeaderFilename);
     70     StringRef UmbrellaDir = Header->getDir()->getName();
     71     if (!UmbrellaDir.equals(UmbreallDirFromHeader)) {
     72       SmallString<128> AltHeaderFilename;
     73       llvm::sys::path::append(AltHeaderFilename, UmbrellaDir,
     74                               llvm::sys::path::filename(HeaderFilename));
     75       if (FileMgr->getFile(AltHeaderFilename))
     76         moduleMapAddHeader(AltHeaderFilename);
     77     }
     78   }
     79 };
     80 
     81 }
     82 
     83 // TODO: move this to Support/Path.h and check for HAVE_REALPATH?
     84 static bool real_path(StringRef SrcPath, SmallVectorImpl<char> &RealPath) {
     85 #ifdef LLVM_ON_UNIX
     86   char CanonicalPath[PATH_MAX];
     87 
     88   // TODO: emit a warning in case this fails...?
     89   if (!realpath(SrcPath.str().c_str(), CanonicalPath))
     90     return false;
     91 
     92   SmallString<256> RPath(CanonicalPath);
     93   RealPath.swap(RPath);
     94   return true;
     95 #else
     96   // FIXME: Add support for systems without realpath.
     97   return false;
     98 #endif
     99 }
    100 
    101 void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
    102   R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
    103 }
    104 
    105 void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) {
    106   PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
    107       llvm::make_unique<ModuleDependencyMMCallbacks>(*this));
    108 }
    109 
    110 static bool isCaseSensitivePath(StringRef Path) {
    111   SmallString<256> TmpDest = Path, UpperDest, RealDest;
    112   // Remove component traversals, links, etc.
    113   if (!real_path(Path, TmpDest))
    114     return true; // Current default value in vfs.yaml
    115   Path = TmpDest;
    116 
    117   // Change path to all upper case and ask for its real path, if the latter
    118   // exists and is equal to Path, it's not case sensitive. Default to case
    119   // sensitive in the absense of realpath, since this is what the VFSWriter
    120   // already expects when sensitivity isn't setup.
    121   for (auto &C : Path)
    122     UpperDest.push_back(toUppercase(C));
    123   if (real_path(UpperDest, RealDest) && Path.equals(RealDest))
    124     return false;
    125   return true;
    126 }
    127 
    128 void ModuleDependencyCollector::writeFileMap() {
    129   if (Seen.empty())
    130     return;
    131 
    132   StringRef VFSDir = getDest();
    133 
    134   // Default to use relative overlay directories in the VFS yaml file. This
    135   // allows crash reproducer scripts to work across machines.
    136   VFSWriter.setOverlayDir(VFSDir);
    137 
    138   // Explicitly set case sensitivity for the YAML writer. For that, find out
    139   // the sensitivity at the path where the headers all collected to.
    140   VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir));
    141 
    142   // Do not rely on real path names when executing the crash reproducer scripts
    143   // since we only want to actually use the files we have on the VFS cache.
    144   VFSWriter.setUseExternalNames(false);
    145 
    146   std::error_code EC;
    147   SmallString<256> YAMLPath = VFSDir;
    148   llvm::sys::path::append(YAMLPath, "vfs.yaml");
    149   llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::F_Text);
    150   if (EC) {
    151     HasErrors = true;
    152     return;
    153   }
    154   VFSWriter.write(OS);
    155 }
    156 
    157 bool ModuleDependencyCollector::getRealPath(StringRef SrcPath,
    158                                             SmallVectorImpl<char> &Result) {
    159   using namespace llvm::sys;
    160   SmallString<256> RealPath;
    161   StringRef FileName = path::filename(SrcPath);
    162   std::string Dir = path::parent_path(SrcPath).str();
    163   auto DirWithSymLink = SymLinkMap.find(Dir);
    164 
    165   // Use real_path to fix any symbolic link component present in a path.
    166   // Computing the real path is expensive, cache the search through the
    167   // parent path directory.
    168   if (DirWithSymLink == SymLinkMap.end()) {
    169     if (!real_path(Dir, RealPath))
    170       return false;
    171     SymLinkMap[Dir] = RealPath.str();
    172   } else {
    173     RealPath = DirWithSymLink->second;
    174   }
    175 
    176   path::append(RealPath, FileName);
    177   Result.swap(RealPath);
    178   return true;
    179 }
    180 
    181 std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src) {
    182   using namespace llvm::sys;
    183 
    184   // We need an absolute src path to append to the root.
    185   SmallString<256> AbsoluteSrc = Src;
    186   fs::make_absolute(AbsoluteSrc);
    187   // Canonicalize src to a native path to avoid mixed separator styles.
    188   path::native(AbsoluteSrc);
    189   // Remove redundant leading "./" pieces and consecutive separators.
    190   AbsoluteSrc = path::remove_leading_dotslash(AbsoluteSrc);
    191 
    192   // Canonicalize the source path by removing "..", "." components.
    193   SmallString<256> CanonicalPath = AbsoluteSrc;
    194   path::remove_dots(CanonicalPath, /*remove_dot_dot=*/true);
    195 
    196   // If a ".." component is present after a symlink component, remove_dots may
    197   // lead to the wrong real destination path. Let the source be canonicalized
    198   // like that but make sure we always use the real path for the destination.
    199   SmallString<256> RealPath;
    200   if (!getRealPath(AbsoluteSrc, RealPath))
    201     RealPath = CanonicalPath;
    202   SmallString<256> Dest = getDest();
    203   path::append(Dest, path::relative_path(RealPath));
    204 
    205   // Copy the file into place.
    206   if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
    207                                                    /*IgnoreExisting=*/true))
    208     return EC;
    209   if (std::error_code EC = fs::copy_file(RealPath, Dest))
    210     return EC;
    211 
    212   // Always map a canonical src path to its real path into the YAML, by doing
    213   // this we map different virtual src paths to the same entry in the VFS
    214   // overlay, which is a way to emulate symlink inside the VFS; this is also
    215   // needed for correctness, not doing that can lead to module redifinition
    216   // errors.
    217   addFileMapping(CanonicalPath, Dest);
    218   return std::error_code();
    219 }
    220 
    221 void ModuleDependencyCollector::addFile(StringRef Filename) {
    222   if (insertSeen(Filename))
    223     if (copyToRoot(Filename))
    224       HasErrors = true;
    225 }
    226