clang-tools 22.0.0git
ModulesBuilder.cpp
Go to the documentation of this file.
1//===----------------- ModulesBuilder.cpp ------------------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ModulesBuilder.h"
10#include "Compiler.h"
11#include "support/Logger.h"
12#include "clang/Frontend/FrontendAction.h"
13#include "clang/Frontend/FrontendActions.h"
14#include "clang/Serialization/ASTReader.h"
15#include "clang/Serialization/ModuleCache.h"
16#include "llvm/ADT/ScopeExit.h"
17#include "llvm/Support/CommandLine.h"
18
19#include <queue>
20
21namespace clang {
22namespace clangd {
23
24namespace {
25
26llvm::cl::opt<bool> DebugModulesBuilder(
27 "debug-modules-builder",
28 llvm::cl::desc("Don't remove clangd's built module files for debugging. "
29 "Remember to remove them later after debugging."),
30 llvm::cl::init(false));
31
32// Create a path to store module files. Generally it should be:
33//
34// {TEMP_DIRS}/clangd/module_files/{hashed-file-name}-%%-%%-%%-%%-%%-%%/.
35//
36// {TEMP_DIRS} is the temporary directory for the system, e.g., "/var/tmp"
37// or "C:/TEMP".
38//
39// '%%' means random value to make the generated path unique.
40//
41// \param MainFile is used to get the root of the project from global
42// compilation database.
43//
44// TODO: Move these module fils out of the temporary directory if the module
45// files are persistent.
46llvm::SmallString<256> getUniqueModuleFilesPath(PathRef MainFile) {
47 llvm::SmallString<128> HashedPrefix = llvm::sys::path::filename(MainFile);
48 // There might be multiple files with the same name in a project. So appending
49 // the hash value of the full path to make sure they won't conflict.
50 HashedPrefix += std::to_string(llvm::hash_value(MainFile));
51
52 llvm::SmallString<256> ResultPattern;
53
54 llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/true,
55 ResultPattern);
56
57 llvm::sys::path::append(ResultPattern, "clangd");
58 llvm::sys::path::append(ResultPattern, "module_files");
59
60 llvm::sys::path::append(ResultPattern, HashedPrefix);
61
62 ResultPattern.append("-%%-%%-%%-%%-%%-%%");
63
64 llvm::SmallString<256> Result;
65 llvm::sys::fs::createUniquePath(ResultPattern, Result,
66 /*MakeAbsolute=*/false);
67
68 llvm::sys::fs::create_directories(Result);
69 return Result;
70}
71
72// Get a unique module file path under \param ModuleFilesPrefix.
73std::string getModuleFilePath(llvm::StringRef ModuleName,
74 PathRef ModuleFilesPrefix) {
75 llvm::SmallString<256> ModuleFilePath(ModuleFilesPrefix);
76 auto [PrimaryModuleName, PartitionName] = ModuleName.split(':');
77 llvm::sys::path::append(ModuleFilePath, PrimaryModuleName);
78 if (!PartitionName.empty()) {
79 ModuleFilePath.append("-");
80 ModuleFilePath.append(PartitionName);
81 }
82
83 ModuleFilePath.append(".pcm");
84 return std::string(ModuleFilePath);
85}
86
87// FailedPrerequisiteModules - stands for the PrerequisiteModules which has
88// errors happened during the building process.
89class FailedPrerequisiteModules : public PrerequisiteModules {
90public:
91 ~FailedPrerequisiteModules() override = default;
92
93 // We shouldn't adjust the compilation commands based on
94 // FailedPrerequisiteModules.
95 void adjustHeaderSearchOptions(HeaderSearchOptions &Options) const override {
96 }
97
98 // FailedPrerequisiteModules can never be reused.
99 bool
100 canReuse(const CompilerInvocation &CI,
101 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) const override {
102 return false;
103 }
104};
105
106/// Represents a reference to a module file (*.pcm).
107class ModuleFile {
108protected:
109 ModuleFile(StringRef ModuleName, PathRef ModuleFilePath)
110 : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.str()) {}
111
112public:
113 ModuleFile() = delete;
114
115 ModuleFile(const ModuleFile &) = delete;
116 ModuleFile operator=(const ModuleFile &) = delete;
117
118 // The move constructor is needed for llvm::SmallVector.
119 ModuleFile(ModuleFile &&Other)
120 : ModuleName(std::move(Other.ModuleName)),
121 ModuleFilePath(std::move(Other.ModuleFilePath)) {
122 Other.ModuleName.clear();
123 Other.ModuleFilePath.clear();
124 }
125
126 ModuleFile &operator=(ModuleFile &&Other) {
127 if (this == &Other)
128 return *this;
129
130 this->~ModuleFile();
131 new (this) ModuleFile(std::move(Other));
132 return *this;
133 }
134 virtual ~ModuleFile() = default;
135
136 StringRef getModuleName() const { return ModuleName; }
137
138 StringRef getModuleFilePath() const { return ModuleFilePath; }
139
140protected:
141 std::string ModuleName;
142 std::string ModuleFilePath;
143};
144
145/// Represents a prebuilt module file which is not owned by us.
146class PrebuiltModuleFile : public ModuleFile {
147private:
148 // private class to make sure the class can only be constructed by member
149 // functions.
150 struct CtorTag {};
151
152public:
153 PrebuiltModuleFile(StringRef ModuleName, PathRef ModuleFilePath, CtorTag)
154 : ModuleFile(ModuleName, ModuleFilePath) {}
155
156 static std::shared_ptr<PrebuiltModuleFile> make(StringRef ModuleName,
157 PathRef ModuleFilePath) {
158 return std::make_shared<PrebuiltModuleFile>(ModuleName, ModuleFilePath,
159 CtorTag{});
160 }
161};
162
163/// Represents a module file built by us. We're responsible to remove it.
164class BuiltModuleFile : public ModuleFile {
165private:
166 // private class to make sure the class can only be constructed by member
167 // functions.
168 struct CtorTag {};
169
170public:
171 BuiltModuleFile(StringRef ModuleName, PathRef ModuleFilePath, CtorTag)
172 : ModuleFile(ModuleName, ModuleFilePath) {}
173
174 static std::shared_ptr<BuiltModuleFile> make(StringRef ModuleName,
175 PathRef ModuleFilePath) {
176 return std::make_shared<BuiltModuleFile>(ModuleName, ModuleFilePath,
177 CtorTag{});
178 }
179
180 virtual ~BuiltModuleFile() {
181 if (!ModuleFilePath.empty() && !DebugModulesBuilder)
182 llvm::sys::fs::remove(ModuleFilePath);
183 }
184};
185
186// ReusablePrerequisiteModules - stands for PrerequisiteModules for which all
187// the required modules are built successfully. All the module files
188// are owned by the modules builder.
189class ReusablePrerequisiteModules : public PrerequisiteModules {
190public:
191 ReusablePrerequisiteModules() = default;
192
193 ReusablePrerequisiteModules(const ReusablePrerequisiteModules &Other) =
194 default;
195 ReusablePrerequisiteModules &
196 operator=(const ReusablePrerequisiteModules &) = default;
197 ReusablePrerequisiteModules(ReusablePrerequisiteModules &&) = delete;
198 ReusablePrerequisiteModules
199 operator=(ReusablePrerequisiteModules &&) = delete;
200
201 ~ReusablePrerequisiteModules() override = default;
202
203 void adjustHeaderSearchOptions(HeaderSearchOptions &Options) const override {
204 // Appending all built module files.
205 for (const auto &RequiredModule : RequiredModules)
206 Options.PrebuiltModuleFiles.insert_or_assign(
207 RequiredModule->getModuleName().str(),
208 RequiredModule->getModuleFilePath().str());
209 }
210
211 std::string getAsString() const {
212 std::string Result;
213 llvm::raw_string_ostream OS(Result);
214 for (const auto &MF : RequiredModules) {
215 OS << "-fmodule-file=" << MF->getModuleName() << "="
216 << MF->getModuleFilePath() << " ";
217 }
218 return Result;
219 }
220
221 bool canReuse(const CompilerInvocation &CI,
222 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) const override;
223
224 bool isModuleUnitBuilt(llvm::StringRef ModuleName) const {
225 return BuiltModuleNames.contains(ModuleName);
226 }
227
228 void addModuleFile(std::shared_ptr<const ModuleFile> MF) {
229 BuiltModuleNames.insert(MF->getModuleName());
230 RequiredModules.emplace_back(std::move(MF));
231 }
232
233private:
234 llvm::SmallVector<std::shared_ptr<const ModuleFile>, 8> RequiredModules;
235 // A helper class to speedup the query if a module is built.
236 llvm::StringSet<> BuiltModuleNames;
237};
238
239bool IsModuleFileUpToDate(PathRef ModuleFilePath,
240 const PrerequisiteModules &RequisiteModules,
241 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
242 HeaderSearchOptions HSOpts;
243 RequisiteModules.adjustHeaderSearchOptions(HSOpts);
244 HSOpts.ForceCheckCXX20ModulesInputFiles = true;
245 HSOpts.ValidateASTInputFilesContent = true;
246
247 clang::clangd::IgnoreDiagnostics IgnoreDiags;
248 DiagnosticOptions DiagOpts;
249 IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
250 CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags,
251 /*ShouldOwnClient=*/false);
252
253 LangOptions LangOpts;
254 LangOpts.SkipODRCheckInGMF = true;
255
256 FileManager FileMgr(FileSystemOptions(), VFS);
257
258 SourceManager SourceMgr(*Diags, FileMgr);
259
260 HeaderSearch HeaderInfo(HSOpts, SourceMgr, *Diags, LangOpts,
261 /*Target=*/nullptr);
262
263 PreprocessorOptions PPOpts;
264 TrivialModuleLoader ModuleLoader;
265 Preprocessor PP(PPOpts, *Diags, LangOpts, SourceMgr, HeaderInfo,
266 ModuleLoader);
267
268 IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache();
269 PCHContainerOperations PCHOperations;
270 CodeGenOptions CodeGenOpts;
271 ASTReader Reader(PP, *ModCache, /*ASTContext=*/nullptr,
272 PCHOperations.getRawReader(), CodeGenOpts, {});
273
274 // We don't need any listener here. By default it will use a validator
275 // listener.
276 Reader.setListener(nullptr);
277
278 if (Reader.ReadAST(ModuleFilePath, serialization::MK_MainFile,
279 SourceLocation(),
280 ASTReader::ARR_None) != ASTReader::Success)
281 return false;
282
283 bool UpToDate = true;
284 Reader.getModuleManager().visit([&](serialization::ModuleFile &MF) -> bool {
285 Reader.visitInputFiles(
286 MF, /*IncludeSystem=*/false, /*Complain=*/false,
287 [&](const serialization::InputFile &IF, bool isSystem) {
288 if (!IF.getFile() || IF.isOutOfDate())
289 UpToDate = false;
290 });
291 return !UpToDate;
292 });
293 return UpToDate;
294}
295
296bool IsModuleFilesUpToDate(
297 llvm::SmallVector<PathRef> ModuleFilePaths,
298 const PrerequisiteModules &RequisiteModules,
299 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
300 return llvm::all_of(
301 ModuleFilePaths, [&RequisiteModules, VFS](auto ModuleFilePath) {
302 return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules, VFS);
303 });
304}
305
306/// Build a module file for module with `ModuleName`. The information of built
307/// module file are stored in \param BuiltModuleFiles.
308llvm::Expected<std::shared_ptr<BuiltModuleFile>>
309buildModuleFile(llvm::StringRef ModuleName, PathRef ModuleUnitFileName,
310 const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS,
311 const ReusablePrerequisiteModules &BuiltModuleFiles) {
312 // Try cheap operation earlier to boil-out cheaply if there are problems.
313 auto Cmd = CDB.getCompileCommand(ModuleUnitFileName);
314 if (!Cmd)
315 return llvm::createStringError(
316 llvm::formatv("No compile command for {0}", ModuleUnitFileName));
317
318 llvm::SmallString<256> ModuleFilesPrefix =
319 getUniqueModuleFilesPath(ModuleUnitFileName);
320
321 Cmd->Output = getModuleFilePath(ModuleName, ModuleFilesPrefix);
322
323 ParseInputs Inputs;
324 Inputs.TFS = &TFS;
325 Inputs.CompileCommand = std::move(*Cmd);
326
327 IgnoreDiagnostics IgnoreDiags;
328 auto CI = buildCompilerInvocation(Inputs, IgnoreDiags);
329 if (!CI)
330 return llvm::createStringError("Failed to build compiler invocation");
331
332 auto FS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
333 auto Buf = FS->getBufferForFile(Inputs.CompileCommand.Filename);
334 if (!Buf)
335 return llvm::createStringError("Failed to create buffer");
336
337 // In clang's driver, we will suppress the check for ODR violation in GMF.
338 // See the implementation of RenderModulesOptions in Clang.cpp.
339 CI->getLangOpts().SkipODRCheckInGMF = true;
340
341 // Hash the contents of input files and store the hash value to the BMI files.
342 // So that we can check if the files are still valid when we want to reuse the
343 // BMI files.
344 CI->getHeaderSearchOpts().ValidateASTInputFilesContent = true;
345
346 BuiltModuleFiles.adjustHeaderSearchOptions(CI->getHeaderSearchOpts());
347
348 CI->getFrontendOpts().OutputFile = Inputs.CompileCommand.Output;
349 auto Clang =
350 prepareCompilerInstance(std::move(CI), /*Preamble=*/nullptr,
351 std::move(*Buf), std::move(FS), IgnoreDiags);
352 if (!Clang)
353 return llvm::createStringError("Failed to prepare compiler instance");
354
355 GenerateReducedModuleInterfaceAction Action;
356 Clang->ExecuteAction(Action);
357
358 if (Clang->getDiagnostics().hasErrorOccurred()) {
359 std::string Cmds;
360 for (const auto &Arg : Inputs.CompileCommand.CommandLine) {
361 if (!Cmds.empty())
362 Cmds += " ";
363 Cmds += Arg;
364 }
365
366 clangd::vlog("Failed to compile {0} with command: {1}", ModuleUnitFileName,
367 Cmds);
368
369 std::string BuiltModuleFilesStr = BuiltModuleFiles.getAsString();
370 if (!BuiltModuleFilesStr.empty())
371 clangd::vlog("The actual used module files built by clangd is {0}",
372 BuiltModuleFilesStr);
373
374 return llvm::createStringError(
375 llvm::formatv("Failed to compile {0}. Use '--log=verbose' to view "
376 "detailed failure reasons. It is helpful to use "
377 "'--debug-modules-builder' flag to keep the clangd's "
378 "built module files to reproduce the failure for "
379 "debugging. Remember to remove them after debugging.",
380 ModuleUnitFileName));
381 }
382
383 return BuiltModuleFile::make(ModuleName, Inputs.CompileCommand.Output);
384}
385
386bool ReusablePrerequisiteModules::canReuse(
387 const CompilerInvocation &CI,
388 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) const {
389 if (RequiredModules.empty())
390 return true;
391
392 llvm::SmallVector<llvm::StringRef> BMIPaths;
393 for (auto &MF : RequiredModules)
394 BMIPaths.push_back(MF->getModuleFilePath());
395 return IsModuleFilesUpToDate(BMIPaths, *this, VFS);
396}
397
398class ModuleFileCache {
399public:
400 ModuleFileCache(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
401 const GlobalCompilationDatabase &getCDB() const { return CDB; }
402
403 std::shared_ptr<const ModuleFile> getModule(StringRef ModuleName);
404
405 void add(StringRef ModuleName, std::shared_ptr<const ModuleFile> ModuleFile) {
406 std::lock_guard<std::mutex> Lock(ModuleFilesMutex);
407
408 ModuleFiles[ModuleName] = ModuleFile;
409 }
410
411 void remove(StringRef ModuleName);
412
413private:
414 const GlobalCompilationDatabase &CDB;
415
416 llvm::StringMap<std::weak_ptr<const ModuleFile>> ModuleFiles;
417 // Mutex to guard accesses to ModuleFiles.
418 std::mutex ModuleFilesMutex;
419};
420
421std::shared_ptr<const ModuleFile>
422ModuleFileCache::getModule(StringRef ModuleName) {
423 std::lock_guard<std::mutex> Lock(ModuleFilesMutex);
424
425 auto Iter = ModuleFiles.find(ModuleName);
426 if (Iter == ModuleFiles.end())
427 return nullptr;
428
429 if (auto Res = Iter->second.lock())
430 return Res;
431
432 ModuleFiles.erase(Iter);
433 return nullptr;
434}
435
436void ModuleFileCache::remove(StringRef ModuleName) {
437 std::lock_guard<std::mutex> Lock(ModuleFilesMutex);
438
439 ModuleFiles.erase(ModuleName);
440}
441
442class ModuleNameToSourceCache {
443public:
444 std::string getSourceForModuleName(llvm::StringRef ModuleName) {
445 std::lock_guard<std::mutex> Lock(CacheMutex);
446 auto Iter = ModuleNameToSourceCache.find(ModuleName);
447 if (Iter != ModuleNameToSourceCache.end())
448 return Iter->second;
449 return "";
450 }
451
452 void addEntry(llvm::StringRef ModuleName, PathRef Source) {
453 std::lock_guard<std::mutex> Lock(CacheMutex);
454 ModuleNameToSourceCache[ModuleName] = Source.str();
455 }
456
457 void eraseEntry(llvm::StringRef ModuleName) {
458 std::lock_guard<std::mutex> Lock(CacheMutex);
459 ModuleNameToSourceCache.erase(ModuleName);
460 }
461
462private:
463 std::mutex CacheMutex;
464 llvm::StringMap<std::string> ModuleNameToSourceCache;
465};
466
467class CachingProjectModules : public ProjectModules {
468public:
469 CachingProjectModules(std::unique_ptr<ProjectModules> MDB,
470 ModuleNameToSourceCache &Cache)
471 : MDB(std::move(MDB)), Cache(Cache) {
472 assert(this->MDB && "CachingProjectModules should only be created with a "
473 "valid underlying ProjectModules");
474 }
475
476 std::vector<std::string> getRequiredModules(PathRef File) override {
477 return MDB->getRequiredModules(File);
478 }
479
480 std::string getModuleNameForSource(PathRef File) override {
481 return MDB->getModuleNameForSource(File);
482 }
483
484 std::string getSourceForModuleName(llvm::StringRef ModuleName,
485 PathRef RequiredSrcFile) override {
486 std::string CachedResult = Cache.getSourceForModuleName(ModuleName);
487
488 // Verify Cached Result by seeing if the source declaring the same module
489 // as we query.
490 if (!CachedResult.empty()) {
491 std::string ModuleNameOfCachedSource =
492 MDB->getModuleNameForSource(CachedResult);
493 if (ModuleNameOfCachedSource == ModuleName)
494 return CachedResult;
495
496 // Cached Result is invalid. Clear it.
497 Cache.eraseEntry(ModuleName);
498 }
499
500 auto Result = MDB->getSourceForModuleName(ModuleName, RequiredSrcFile);
501 Cache.addEntry(ModuleName, Result);
502
503 return Result;
504 }
505
506private:
507 std::unique_ptr<ProjectModules> MDB;
508 ModuleNameToSourceCache &Cache;
509};
510
511/// Collect the directly and indirectly required module names for \param
512/// ModuleName in topological order. The \param ModuleName is guaranteed to
513/// be the last element in \param ModuleNames.
514llvm::SmallVector<std::string> getAllRequiredModules(PathRef RequiredSource,
515 CachingProjectModules &MDB,
516 StringRef ModuleName) {
517 llvm::SmallVector<std::string> ModuleNames;
518 llvm::StringSet<> ModuleNamesSet;
519
520 auto VisitDeps = [&](StringRef ModuleName, auto Visitor) -> void {
521 ModuleNamesSet.insert(ModuleName);
522
523 for (StringRef RequiredModuleName : MDB.getRequiredModules(
524 MDB.getSourceForModuleName(ModuleName, RequiredSource)))
525 if (ModuleNamesSet.insert(RequiredModuleName).second)
526 Visitor(RequiredModuleName, Visitor);
527
528 ModuleNames.push_back(ModuleName.str());
529 };
530 VisitDeps(ModuleName, VisitDeps);
531
532 return ModuleNames;
533}
534
535} // namespace
536
538public:
540
541 ModuleNameToSourceCache &getProjectModulesCache() {
542 return ProjectModulesCache;
543 }
544 const GlobalCompilationDatabase &getCDB() const { return Cache.getCDB(); }
545
546 llvm::Error
547 getOrBuildModuleFile(PathRef RequiredSource, StringRef ModuleName,
548 const ThreadsafeFS &TFS, CachingProjectModules &MDB,
549 ReusablePrerequisiteModules &BuiltModuleFiles);
550
551private:
552 /// Try to get prebuilt module files from the compilation database.
553 void getPrebuiltModuleFile(StringRef ModuleName, PathRef ModuleUnitFileName,
554 const ThreadsafeFS &TFS,
555 ReusablePrerequisiteModules &BuiltModuleFiles);
556
557 ModuleFileCache Cache;
558 ModuleNameToSourceCache ProjectModulesCache;
559};
560
561void ModulesBuilder::ModulesBuilderImpl::getPrebuiltModuleFile(
562 StringRef ModuleName, PathRef ModuleUnitFileName, const ThreadsafeFS &TFS,
563 ReusablePrerequisiteModules &BuiltModuleFiles) {
564 auto Cmd = getCDB().getCompileCommand(ModuleUnitFileName);
565 if (!Cmd)
566 return;
567
568 ParseInputs Inputs;
569 Inputs.TFS = &TFS;
570 Inputs.CompileCommand = std::move(*Cmd);
571
572 IgnoreDiagnostics IgnoreDiags;
573 auto CI = buildCompilerInvocation(Inputs, IgnoreDiags);
574 if (!CI)
575 return;
576
577 // We don't need to check if the module files are in ModuleCache or adding
578 // them to the module cache. As even if the module files are in the module
579 // cache, we still need to validate them. And it looks not helpful to add them
580 // to the module cache, since we may always try to get the prebuilt module
581 // files before building the module files by ourselves.
582 for (auto &[ModuleName, ModuleFilePath] :
583 CI->getHeaderSearchOpts().PrebuiltModuleFiles) {
584 if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
585 continue;
586
587 if (IsModuleFileUpToDate(ModuleFilePath, BuiltModuleFiles,
588 TFS.view(std::nullopt))) {
589 log("Reusing prebuilt module file {0} of module {1} for {2}",
590 ModuleFilePath, ModuleName, ModuleUnitFileName);
591 BuiltModuleFiles.addModuleFile(
592 PrebuiltModuleFile::make(ModuleName, ModuleFilePath));
593 }
594 }
595}
596
598 PathRef RequiredSource, StringRef ModuleName, const ThreadsafeFS &TFS,
599 CachingProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles) {
600 if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
601 return llvm::Error::success();
602
603 std::string ModuleUnitFileName =
604 MDB.getSourceForModuleName(ModuleName, RequiredSource);
605 /// It is possible that we're meeting third party modules (modules whose
606 /// source are not in the project. e.g, the std module may be a third-party
607 /// module for most project) or something wrong with the implementation of
608 /// ProjectModules.
609 /// FIXME: How should we treat third party modules here? If we want to ignore
610 /// third party modules, we should return true instead of false here.
611 /// Currently we simply bail out.
612 if (ModuleUnitFileName.empty())
613 return llvm::createStringError(
614 llvm::formatv("Don't get the module unit for module {0}", ModuleName));
615
616 /// Try to get prebuilt module files from the compilation database first. This
617 /// helps to avoid building the module files that are already built by the
618 /// compiler.
619 getPrebuiltModuleFile(ModuleName, ModuleUnitFileName, TFS, BuiltModuleFiles);
620
621 // Get Required modules in topological order.
622 auto ReqModuleNames = getAllRequiredModules(RequiredSource, MDB, ModuleName);
623 for (llvm::StringRef ReqModuleName : ReqModuleNames) {
624 if (BuiltModuleFiles.isModuleUnitBuilt(ReqModuleName))
625 continue;
626
627 if (auto Cached = Cache.getModule(ReqModuleName)) {
628 if (IsModuleFileUpToDate(Cached->getModuleFilePath(), BuiltModuleFiles,
629 TFS.view(std::nullopt))) {
630 log("Reusing module {0} from {1}", ReqModuleName,
631 Cached->getModuleFilePath());
632 BuiltModuleFiles.addModuleFile(std::move(Cached));
633 continue;
634 }
635 Cache.remove(ReqModuleName);
636 }
637
638 std::string ReqFileName =
639 MDB.getSourceForModuleName(ReqModuleName, RequiredSource);
640 llvm::Expected<std::shared_ptr<BuiltModuleFile>> MF = buildModuleFile(
641 ReqModuleName, ReqFileName, getCDB(), TFS, BuiltModuleFiles);
642 if (llvm::Error Err = MF.takeError())
643 return Err;
644
645 log("Built module {0} to {1}", ReqModuleName, (*MF)->getModuleFilePath());
646 Cache.add(ReqModuleName, *MF);
647 BuiltModuleFiles.addModuleFile(std::move(*MF));
648 }
649
650 return llvm::Error::success();
651}
652
653std::unique_ptr<PrerequisiteModules>
655 const ThreadsafeFS &TFS) {
656 std::unique_ptr<ProjectModules> MDB = Impl->getCDB().getProjectModules(File);
657 if (!MDB) {
658 elog("Failed to get Project Modules information for {0}", File);
659 return std::make_unique<FailedPrerequisiteModules>();
660 }
661 CachingProjectModules CachedMDB(std::move(MDB),
662 Impl->getProjectModulesCache());
663
664 std::vector<std::string> RequiredModuleNames =
665 CachedMDB.getRequiredModules(File);
666 if (RequiredModuleNames.empty())
667 return std::make_unique<ReusablePrerequisiteModules>();
668
669 auto RequiredModules = std::make_unique<ReusablePrerequisiteModules>();
670 for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {
671 // Return early if there is any error.
672 if (llvm::Error Err = Impl->getOrBuildModuleFile(
673 File, RequiredModuleName, TFS, CachedMDB, *RequiredModules.get())) {
674 elog("Failed to build module {0}; due to {1}", RequiredModuleName,
675 toString(std::move(Err)));
676 return std::make_unique<FailedPrerequisiteModules>();
677 }
678 }
679
680 return std::move(RequiredModules);
681}
682
684 Impl = std::make_unique<ModulesBuilderImpl>(CDB);
685}
686
688
689} // namespace clangd
690} // namespace clang
Provides compilation arguments used for parsing C and C++ files.
const GlobalCompilationDatabase & getCDB() const
ModulesBuilderImpl(const GlobalCompilationDatabase &CDB)
llvm::Error getOrBuildModuleFile(PathRef RequiredSource, StringRef ModuleName, const ThreadsafeFS &TFS, CachingProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles)
std::unique_ptr< PrerequisiteModules > buildPrerequisiteModulesFor(PathRef File, const ThreadsafeFS &TFS)
ModulesBuilder(const GlobalCompilationDatabase &CDB)
Store all the needed module files information to parse a single source file.
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:45
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
Definition Compiler.cpp:95
void vlog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:72
static const char * toString(OffsetEncoding OE)
std::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
Definition Compiler.cpp:130
void log(const char *Fmt, Ts &&... Vals)
Definition Logger.h:67
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition Path.h:29
void elog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:61
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Information required to run clang, e.g. to parse AST or do code completion.
Definition Compiler.h:49
tooling::CompileCommand CompileCommand
Definition Compiler.h:50
const ThreadsafeFS * TFS
Definition Compiler.h:51