1*0a6a1f1dSLionel Sambuc //===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//
2*0a6a1f1dSLionel Sambuc //
3*0a6a1f1dSLionel Sambuc // The LLVM Compiler Infrastructure
4*0a6a1f1dSLionel Sambuc //
5*0a6a1f1dSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6*0a6a1f1dSLionel Sambuc // License. See LICENSE.TXT for details.
7*0a6a1f1dSLionel Sambuc //
8*0a6a1f1dSLionel Sambuc //===----------------------------------------------------------------------===//
9*0a6a1f1dSLionel Sambuc //
10*0a6a1f1dSLionel Sambuc // Collect the dependencies of a set of modules.
11*0a6a1f1dSLionel Sambuc //
12*0a6a1f1dSLionel Sambuc //===----------------------------------------------------------------------===//
13*0a6a1f1dSLionel Sambuc
14*0a6a1f1dSLionel Sambuc #include "clang/Frontend/Utils.h"
15*0a6a1f1dSLionel Sambuc #include "clang/Serialization/ASTReader.h"
16*0a6a1f1dSLionel Sambuc #include "llvm/ADT/StringSet.h"
17*0a6a1f1dSLionel Sambuc #include "llvm/ADT/iterator_range.h"
18*0a6a1f1dSLionel Sambuc #include "llvm/Support/FileSystem.h"
19*0a6a1f1dSLionel Sambuc #include "llvm/Support/Path.h"
20*0a6a1f1dSLionel Sambuc #include "llvm/Support/raw_ostream.h"
21*0a6a1f1dSLionel Sambuc
22*0a6a1f1dSLionel Sambuc using namespace clang;
23*0a6a1f1dSLionel Sambuc
24*0a6a1f1dSLionel Sambuc namespace {
25*0a6a1f1dSLionel Sambuc /// Private implementation for ModuleDependencyCollector
26*0a6a1f1dSLionel Sambuc class ModuleDependencyListener : public ASTReaderListener {
27*0a6a1f1dSLionel Sambuc ModuleDependencyCollector &Collector;
28*0a6a1f1dSLionel Sambuc
29*0a6a1f1dSLionel Sambuc std::error_code copyToRoot(StringRef Src);
30*0a6a1f1dSLionel Sambuc public:
ModuleDependencyListener(ModuleDependencyCollector & Collector)31*0a6a1f1dSLionel Sambuc ModuleDependencyListener(ModuleDependencyCollector &Collector)
32*0a6a1f1dSLionel Sambuc : Collector(Collector) {}
needsInputFileVisitation()33*0a6a1f1dSLionel Sambuc bool needsInputFileVisitation() override { return true; }
needsSystemInputFileVisitation()34*0a6a1f1dSLionel Sambuc bool needsSystemInputFileVisitation() override { return true; }
35*0a6a1f1dSLionel Sambuc bool visitInputFile(StringRef Filename, bool IsSystem,
36*0a6a1f1dSLionel Sambuc bool IsOverridden) override;
37*0a6a1f1dSLionel Sambuc };
38*0a6a1f1dSLionel Sambuc }
39*0a6a1f1dSLionel Sambuc
attachToASTReader(ASTReader & R)40*0a6a1f1dSLionel Sambuc void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
41*0a6a1f1dSLionel Sambuc R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
42*0a6a1f1dSLionel Sambuc }
43*0a6a1f1dSLionel Sambuc
writeFileMap()44*0a6a1f1dSLionel Sambuc void ModuleDependencyCollector::writeFileMap() {
45*0a6a1f1dSLionel Sambuc if (Seen.empty())
46*0a6a1f1dSLionel Sambuc return;
47*0a6a1f1dSLionel Sambuc
48*0a6a1f1dSLionel Sambuc SmallString<256> Dest = getDest();
49*0a6a1f1dSLionel Sambuc llvm::sys::path::append(Dest, "vfs.yaml");
50*0a6a1f1dSLionel Sambuc
51*0a6a1f1dSLionel Sambuc std::error_code EC;
52*0a6a1f1dSLionel Sambuc llvm::raw_fd_ostream OS(Dest, EC, llvm::sys::fs::F_Text);
53*0a6a1f1dSLionel Sambuc if (EC) {
54*0a6a1f1dSLionel Sambuc setHasErrors();
55*0a6a1f1dSLionel Sambuc return;
56*0a6a1f1dSLionel Sambuc }
57*0a6a1f1dSLionel Sambuc VFSWriter.write(OS);
58*0a6a1f1dSLionel Sambuc }
59*0a6a1f1dSLionel Sambuc
copyToRoot(StringRef Src)60*0a6a1f1dSLionel Sambuc std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) {
61*0a6a1f1dSLionel Sambuc using namespace llvm::sys;
62*0a6a1f1dSLionel Sambuc
63*0a6a1f1dSLionel Sambuc // We need an absolute path to append to the root.
64*0a6a1f1dSLionel Sambuc SmallString<256> AbsoluteSrc = Src;
65*0a6a1f1dSLionel Sambuc fs::make_absolute(AbsoluteSrc);
66*0a6a1f1dSLionel Sambuc // Canonicalize to a native path to avoid mixed separator styles.
67*0a6a1f1dSLionel Sambuc path::native(AbsoluteSrc);
68*0a6a1f1dSLionel Sambuc // TODO: We probably need to handle .. as well as . in order to have valid
69*0a6a1f1dSLionel Sambuc // input to the YAMLVFSWriter.
70*0a6a1f1dSLionel Sambuc FileManager::removeDotPaths(AbsoluteSrc);
71*0a6a1f1dSLionel Sambuc
72*0a6a1f1dSLionel Sambuc // Build the destination path.
73*0a6a1f1dSLionel Sambuc SmallString<256> Dest = Collector.getDest();
74*0a6a1f1dSLionel Sambuc path::append(Dest, path::relative_path(AbsoluteSrc));
75*0a6a1f1dSLionel Sambuc
76*0a6a1f1dSLionel Sambuc // Copy the file into place.
77*0a6a1f1dSLionel Sambuc if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
78*0a6a1f1dSLionel Sambuc /*IgnoreExisting=*/true))
79*0a6a1f1dSLionel Sambuc return EC;
80*0a6a1f1dSLionel Sambuc if (std::error_code EC = fs::copy_file(AbsoluteSrc.str(), Dest.str()))
81*0a6a1f1dSLionel Sambuc return EC;
82*0a6a1f1dSLionel Sambuc // Use the absolute path under the root for the file mapping.
83*0a6a1f1dSLionel Sambuc Collector.addFileMapping(AbsoluteSrc.str(), Dest.str());
84*0a6a1f1dSLionel Sambuc return std::error_code();
85*0a6a1f1dSLionel Sambuc }
86*0a6a1f1dSLionel Sambuc
visitInputFile(StringRef Filename,bool IsSystem,bool IsOverridden)87*0a6a1f1dSLionel Sambuc bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem,
88*0a6a1f1dSLionel Sambuc bool IsOverridden) {
89*0a6a1f1dSLionel Sambuc if (Collector.insertSeen(Filename))
90*0a6a1f1dSLionel Sambuc if (copyToRoot(Filename))
91*0a6a1f1dSLionel Sambuc Collector.setHasErrors();
92*0a6a1f1dSLionel Sambuc return true;
93*0a6a1f1dSLionel Sambuc }
94