//===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Collect the dependencies of a set of modules. // //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTReader.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace clang; namespace { /// Private implementation for ModuleDependencyCollector class ModuleDependencyListener : public ASTReaderListener { ModuleDependencyCollector &Collector; std::error_code copyToRoot(StringRef Src); public: ModuleDependencyListener(ModuleDependencyCollector &Collector) : Collector(Collector) {} bool needsInputFileVisitation() override { return true; } bool needsSystemInputFileVisitation() override { return true; } bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden) override; }; } void ModuleDependencyCollector::attachToASTReader(ASTReader &R) { R.addListener(llvm::make_unique(*this)); } void ModuleDependencyCollector::writeFileMap() { if (Seen.empty()) return; SmallString<256> Dest = getDest(); llvm::sys::path::append(Dest, "vfs.yaml"); std::error_code EC; llvm::raw_fd_ostream OS(Dest, EC, llvm::sys::fs::F_Text); if (EC) { setHasErrors(); return; } VFSWriter.write(OS); } /// Remove traversal (ie, . or ..) from the given absolute path. static void removePathTraversal(SmallVectorImpl &Path) { using namespace llvm::sys; SmallVector ComponentStack; StringRef P(Path.data(), Path.size()); // Skip the root path, then look for traversal in the components. StringRef Rel = path::relative_path(P); for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) { if (C == ".") continue; if (C == "..") { assert(ComponentStack.size() && "Path traverses out of parent"); ComponentStack.pop_back(); } else ComponentStack.push_back(C); } // The stack is now the path without any directory traversal. SmallString<256> Buffer = path::root_path(P); for (StringRef C : ComponentStack) path::append(Buffer, C); // Put the result in Path. Path.swap(Buffer); } std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) { using namespace llvm::sys; // We need an absolute path to append to the root. SmallString<256> AbsoluteSrc = Src; fs::make_absolute(AbsoluteSrc); removePathTraversal(AbsoluteSrc); // Build the destination path. SmallString<256> Dest = Collector.getDest(); path::append(Dest, path::relative_path(AbsoluteSrc)); // Copy the file into place. if (std::error_code EC = fs::create_directories(path::parent_path(Dest), /*IgnoreExisting=*/true)) return EC; if (std::error_code EC = fs::copy_file(AbsoluteSrc.str(), Dest.str())) return EC; // Use the absolute path under the root for the file mapping. Collector.addFileMapping(AbsoluteSrc.str(), Dest.str()); return std::error_code(); } bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden) { if (Collector.insertSeen(Filename)) if (copyToRoot(Filename)) Collector.setHasErrors(); return true; }