clang  3.9.0
ModuleDependencyCollector.cpp
Go to the documentation of this file.
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"
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 
102  R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
103 }
104 
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 
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 
222  if (insertSeen(Filename))
223  if (copyToRoot(Filename))
224  HasErrors = true;
225 }
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:117
void setOverlayDir(StringRef OverlayDirectory)
void attachToASTReader(ASTReader &R) override
ModuleMap & getModuleMap()
Retrieve the module map.
Definition: HeaderSearch.h:590
void write(llvm::raw_ostream &OS)
HeaderSearch & getHeaderSearchInfo() const
Definition: Preprocessor.h:695
void attachToPreprocessor(Preprocessor &PP) override
void addModuleMapCallbacks(std::unique_ptr< ModuleMapCallbacks > Callback)
Add a module map callback.
Definition: ModuleMap.h:309
const FileEntry * getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
StringRef Filename
Definition: Format.cpp:1194
void addFileMapping(StringRef VPath, StringRef RPath)
Definition: Utils.h:136
Defines the clang::Preprocessor interface.
void setCaseSensitivity(bool CaseSensitive)
A mechanism to observe the actions of the module map parser as it reads module map files...
Definition: ModuleMap.h:41
Collects the dependencies for imported modules into a directory.
Definition: Utils.h:122
StringRef FileName
Definition: Format.cpp:1313
void addListener(std::unique_ptr< ASTReaderListener > L)
Add an AST callback listener.
Definition: ASTReader.h:1422
const char * getName() const
Definition: FileManager.h:85
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:53
const char * getName() const
Definition: FileManager.h:45
static bool isCaseSensitivePath(StringRef Path)
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:312
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:104
void setUseExternalNames(bool UseExtNames)
static LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
Definition: CharInfo.h:174
const DirectoryEntry * getDir() const
Return the directory the file lives in.
Definition: FileManager.h:95
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:97
static bool real_path(StringRef SrcPath, SmallVectorImpl< char > &RealPath)
bool insertSeen(StringRef Filename)
Definition: Utils.h:134