1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/Basic/CharInfo.h" |
14 | #include "clang/Frontend/Utils.h" |
15 | #include "clang/Lex/Preprocessor.h" |
16 | #include "clang/Serialization/ASTReader.h" |
17 | #include "llvm/ADT/iterator_range.h" |
18 | #include "llvm/Config/llvm-config.h" |
19 | #include "llvm/Support/FileSystem.h" |
20 | #include "llvm/Support/Path.h" |
21 | #include "llvm/Support/raw_ostream.h" |
22 | |
23 | using namespace clang; |
24 | |
25 | namespace { |
26 | |
27 | class ModuleDependencyListener : public ASTReaderListener { |
28 | ModuleDependencyCollector &Collector; |
29 | public: |
30 | ModuleDependencyListener(ModuleDependencyCollector &Collector) |
31 | : Collector(Collector) {} |
32 | bool needsInputFileVisitation() override { return true; } |
33 | bool needsSystemInputFileVisitation() override { return true; } |
34 | bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden, |
35 | bool IsExplicitModule) override { |
36 | Collector.addFile(Filename); |
37 | return true; |
38 | } |
39 | }; |
40 | |
41 | struct ModuleDependencyPPCallbacks : public PPCallbacks { |
42 | ModuleDependencyCollector &Collector; |
43 | SourceManager &SM; |
44 | ModuleDependencyPPCallbacks(ModuleDependencyCollector &Collector, |
45 | SourceManager &SM) |
46 | : Collector(Collector), SM(SM) {} |
47 | |
48 | void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, |
49 | StringRef FileName, bool IsAngled, |
50 | CharSourceRange FilenameRange, const FileEntry *File, |
51 | StringRef SearchPath, StringRef RelativePath, |
52 | const Module *Imported, |
53 | SrcMgr::CharacteristicKind FileType) override { |
54 | if (!File) |
55 | return; |
56 | Collector.addFile(File->getName()); |
57 | } |
58 | }; |
59 | |
60 | struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks { |
61 | ModuleDependencyCollector &Collector; |
62 | ModuleDependencyMMCallbacks(ModuleDependencyCollector &Collector) |
63 | : Collector(Collector) {} |
64 | |
65 | void (StringRef ) override { |
66 | if (llvm::sys::path::is_absolute(HeaderPath)) |
67 | Collector.addFile(HeaderPath); |
68 | } |
69 | void (FileManager *FileMgr, |
70 | const FileEntry *) override { |
71 | StringRef = Header->getName(); |
72 | moduleMapAddHeader(HeaderFilename); |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | StringRef = |
87 | llvm::sys::path::parent_path(HeaderFilename); |
88 | StringRef UmbrellaDir = Header->getDir()->getName(); |
89 | if (!UmbrellaDir.equals(UmbreallDirFromHeader)) { |
90 | SmallString<128> ; |
91 | llvm::sys::path::append(AltHeaderFilename, UmbrellaDir, |
92 | llvm::sys::path::filename(HeaderFilename)); |
93 | if (FileMgr->getFile(AltHeaderFilename)) |
94 | moduleMapAddHeader(AltHeaderFilename); |
95 | } |
96 | } |
97 | }; |
98 | |
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.addPPCallbacks(llvm::make_unique<ModuleDependencyPPCallbacks>( |
107 | *this, PP.getSourceManager())); |
108 | PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks( |
109 | llvm::make_unique<ModuleDependencyMMCallbacks>(*this)); |
110 | } |
111 | |
112 | static bool isCaseSensitivePath(StringRef Path) { |
113 | SmallString<256> TmpDest = Path, UpperDest, RealDest; |
114 | |
115 | if (llvm::sys::fs::real_path(Path, TmpDest)) |
116 | return true; |
117 | Path = TmpDest; |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | for (auto &C : Path) |
124 | UpperDest.push_back(toUppercase(C)); |
125 | if (!llvm::sys::fs::real_path(UpperDest, RealDest) && Path.equals(RealDest)) |
126 | return false; |
127 | return true; |
128 | } |
129 | |
130 | void ModuleDependencyCollector::writeFileMap() { |
131 | if (Seen.empty()) |
132 | return; |
133 | |
134 | StringRef VFSDir = getDest(); |
135 | |
136 | |
137 | |
138 | VFSWriter.setOverlayDir(VFSDir); |
139 | |
140 | |
141 | |
142 | VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir)); |
143 | |
144 | |
145 | |
146 | VFSWriter.setUseExternalNames(false); |
147 | |
148 | std::error_code EC; |
149 | SmallString<256> YAMLPath = VFSDir; |
150 | llvm::sys::path::append(YAMLPath, "vfs.yaml"); |
151 | llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::F_Text); |
152 | if (EC) { |
153 | HasErrors = true; |
154 | return; |
155 | } |
156 | VFSWriter.write(OS); |
157 | } |
158 | |
159 | bool ModuleDependencyCollector::getRealPath(StringRef SrcPath, |
160 | SmallVectorImpl<char> &Result) { |
161 | using namespace llvm::sys; |
162 | SmallString<256> RealPath; |
163 | StringRef FileName = path::filename(SrcPath); |
164 | std::string Dir = path::parent_path(SrcPath).str(); |
165 | auto DirWithSymLink = SymLinkMap.find(Dir); |
166 | |
167 | |
168 | |
169 | |
170 | if (DirWithSymLink == SymLinkMap.end()) { |
171 | if (llvm::sys::fs::real_path(Dir, RealPath)) |
172 | return false; |
173 | SymLinkMap[Dir] = RealPath.str(); |
174 | } else { |
175 | RealPath = DirWithSymLink->second; |
176 | } |
177 | |
178 | path::append(RealPath, FileName); |
179 | Result.swap(RealPath); |
180 | return true; |
181 | } |
182 | |
183 | std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src, |
184 | StringRef Dst) { |
185 | using namespace llvm::sys; |
186 | |
187 | |
188 | SmallString<256> AbsoluteSrc = Src; |
189 | fs::make_absolute(AbsoluteSrc); |
190 | |
191 | path::native(AbsoluteSrc); |
192 | |
193 | AbsoluteSrc = path::remove_leading_dotslash(AbsoluteSrc); |
194 | |
195 | |
196 | SmallString<256> VirtualPath = AbsoluteSrc; |
197 | path::remove_dots(VirtualPath, ); |
198 | |
199 | |
200 | |
201 | |
202 | SmallString<256> CopyFrom; |
203 | if (!getRealPath(AbsoluteSrc, CopyFrom)) |
204 | CopyFrom = VirtualPath; |
205 | SmallString<256> CacheDst = getDest(); |
206 | |
207 | if (Dst.empty()) { |
208 | |
209 | |
210 | path::append(CacheDst, path::relative_path(CopyFrom)); |
211 | } else { |
212 | |
213 | |
214 | if (!fs::exists(Dst)) |
215 | return std::error_code(); |
216 | path::append(CacheDst, Dst); |
217 | CopyFrom = Dst; |
218 | } |
219 | |
220 | |
221 | if (std::error_code EC = fs::create_directories(path::parent_path(CacheDst), |
222 | )) |
223 | return EC; |
224 | if (std::error_code EC = fs::copy_file(CopyFrom, CacheDst)) |
225 | return EC; |
226 | |
227 | |
228 | |
229 | |
230 | |
231 | |
232 | addFileMapping(VirtualPath, CacheDst); |
233 | return std::error_code(); |
234 | } |
235 | |
236 | void ModuleDependencyCollector::addFile(StringRef Filename, StringRef FileDst) { |
237 | if (insertSeen(Filename)) |
238 | if (copyToRoot(Filename, FileDst)) |
239 | HasErrors = true; |
240 | } |
241 | |