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/Frontend/Utils.h" 15 #include "clang/Serialization/ASTReader.h" 16 #include "llvm/ADT/iterator_range.h" 17 #include "llvm/ADT/StringSet.h" 18 #include "llvm/Support/FileSystem.h" 19 #include "llvm/Support/Path.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 using namespace clang; 23 24 namespace { 25 /// Private implementation for ModuleDependencyCollector 26 class ModuleDependencyListener : public ASTReaderListener { 27 ModuleDependencyCollector &Collector; 28 29 std::error_code copyToRoot(StringRef Src); 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, 36 bool IsOverridden) override; 37 }; 38 } 39 40 void ModuleDependencyCollector::attachToASTReader(ASTReader &R) { 41 R.addListener(new ModuleDependencyListener(*this)); 42 } 43 44 void ModuleDependencyCollector::writeFileMap() { 45 if (Seen.empty()) 46 return; 47 48 SmallString<256> Dest = getDest(); 49 llvm::sys::path::append(Dest, "vfs.yaml"); 50 51 std::string ErrorInfo; 52 llvm::raw_fd_ostream OS(Dest.c_str(), ErrorInfo, llvm::sys::fs::F_Text); 53 if (!ErrorInfo.empty()) { 54 setHasErrors(); 55 return; 56 } 57 VFSWriter.write(OS); 58 } 59 60 /// Remove traversal (ie, . or ..) from the given absolute path. 61 static void removePathTraversal(SmallVectorImpl<char> &Path) { 62 using namespace llvm::sys; 63 SmallVector<StringRef, 16> ComponentStack; 64 StringRef P(Path.data(), Path.size()); 65 66 // Skip the root path, then look for traversal in the components. 67 StringRef Rel = path::relative_path(P); 68 for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) { 69 if (C == ".") 70 continue; 71 if (C == "..") { 72 assert(ComponentStack.size() && "Path traverses out of parent"); 73 ComponentStack.pop_back(); 74 } else 75 ComponentStack.push_back(C); 76 } 77 78 // The stack is now the path without any directory traversal. 79 SmallString<256> Buffer = path::root_path(P); 80 for (StringRef C : ComponentStack) 81 path::append(Buffer, C); 82 83 // Put the result in Path. 84 Path.swap(Buffer); 85 } 86 87 std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) { 88 using namespace llvm::sys; 89 90 // We need an absolute path to append to the root. 91 SmallString<256> AbsoluteSrc = Src; 92 fs::make_absolute(AbsoluteSrc); 93 removePathTraversal(AbsoluteSrc); 94 95 // Build the destination path. 96 SmallString<256> Dest = Collector.getDest(); 97 path::append(Dest, path::relative_path(AbsoluteSrc)); 98 99 // Copy the file into place. 100 if (std::error_code EC = fs::create_directories(path::parent_path(Dest), 101 /*IgnoreExisting=*/true)) 102 return EC; 103 if (std::error_code EC = fs::copy_file(AbsoluteSrc.str(), Dest.str())) 104 return EC; 105 // Use the absolute path under the root for the file mapping. 106 Collector.addFileMapping(AbsoluteSrc.str(), Dest.str()); 107 return std::error_code(); 108 } 109 110 bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem, 111 bool IsOverridden) { 112 if (Collector.insertSeen(Filename)) 113 if (copyToRoot(Filename)) 114 Collector.setHasErrors(); 115 return true; 116 } 117