clang-tools 23.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 "SourceCode.h"
12#include "support/Logger.h"
13#include "clang/Frontend/FrontendAction.h"
14#include "clang/Frontend/FrontendActions.h"
15#include "clang/Serialization/ASTReader.h"
16#include "clang/Serialization/ModuleCache.h"
17#include "llvm/ADT/ScopeExit.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/StringSet.h"
20#include "llvm/Support/CommandLine.h"
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/LockFileManager.h"
23#include "llvm/Support/Path.h"
24#include "llvm/Support/Process.h"
25
26#include <chrono>
27#include <ctime>
28
29namespace clang {
30namespace clangd {
31
32namespace {
33
34llvm::cl::opt<bool> DebugModulesBuilder(
35 "debug-modules-builder",
36 llvm::cl::desc("Don't remove clangd's built module files for debugging. "
37 "Remember to remove them later after debugging."),
38 llvm::cl::init(false));
39
40llvm::cl::opt<unsigned> VersionedModuleFileGCThresholdSeconds(
41 "modules-builder-versioned-gc-threshold-seconds",
42 llvm::cl::desc("Delete versioned copy-on-read module files whose last "
43 "access time is older than this many seconds."),
44 llvm::cl::init(3 * 24 * 60 * 60));
45
46//===----------------------------------------------------------------------===//
47// Persistent Module Cache Layout.
48//
49// clangd publishes prerequisite BMIs into a stable on-disk cache so later
50// builders can reuse them across sessions. Cache entries are grouped by a
51// readable module-unit source directory name plus a hash of the normalized
52// source path, and are further separated by a hash of the full compile
53// command, which keeps incompatible BMI variants apart.
54//
55// module-unit source
56// |
57// v
58// cache root
59// |
60// +-- <module-unit-source-name>-<source-hash>
61// |
62// +-- <command-hash>
63// |
64// +-- <primary-module>[-<partition>].pcm
65//===----------------------------------------------------------------------===//
66
67std::string hashStringForCache(llvm::StringRef Content) {
68 return llvm::toHex(digest(Content));
69}
70
71std::string normalizePathForCache(PathRef Path) {
72 llvm::SmallString<256> Normalized(Path);
73 llvm::sys::path::remove_dots(Normalized, /*remove_dot_dot=*/true);
74 return maybeCaseFoldPath(Normalized);
75}
76
77/// Returns the root directory used for persistent module cache storage.
78/// Prefer a project-local cache so different clangd sessions working on the
79/// same source tree can reuse BMIs. Fall back to the user cache directory, and
80/// finally to a non-ephemeral temp directory when no better cache root exists.
81llvm::SmallString<256>
82getModuleCacheRoot(PathRef ModuleUnitFileName,
83 const GlobalCompilationDatabase &CDB) {
84 llvm::SmallString<256> Result;
85 if (auto PI = CDB.getProjectInfo(ModuleUnitFileName);
86 PI && !PI->SourceRoot.empty()) {
87 Result = PI->SourceRoot;
88 llvm::sys::path::append(Result, ".cache", "clangd", "modules");
89 return Result;
90 }
91
92 if (llvm::sys::path::cache_directory(Result)) {
93 llvm::sys::path::append(Result, "clangd", "modules");
94 return Result;
95 }
96
97 llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Result);
98 llvm::sys::path::append(Result, "clangd", "modules");
99 return Result;
100}
101
102/// Returns the directory holding source-scoped lock files for the persistent
103/// module cache. Placing locks beside the cache ensures all builders sharing
104/// the cache also synchronize through the same lock namespace.
105llvm::SmallString<256>
106getModuleCacheLocksDirectory(PathRef ModuleUnitFileName,
107 const GlobalCompilationDatabase &CDB) {
108 llvm::SmallString<256> Result = getModuleCacheRoot(ModuleUnitFileName, CDB);
109 llvm::sys::path::append(Result, ".locks");
110 return Result;
111}
112
113std::string getModuleUnitSourcePathHash(PathRef ModuleUnitFileName) {
114 return hashStringForCache(normalizePathForCache(ModuleUnitFileName));
115}
116
117std::string getModuleUnitSourceDirectoryName(PathRef ModuleUnitFileName) {
118 std::string Result = llvm::sys::path::filename(ModuleUnitFileName).str();
119 Result.push_back('-');
120 Result.append(getModuleUnitSourcePathHash(ModuleUnitFileName));
121 return Result;
122}
123
124std::string getCompileCommandStringHash(const tooling::CompileCommand &Cmd) {
125 std::string SerializedCommand;
126 SerializedCommand.reserve(Cmd.Directory.size() + Cmd.Filename.size() +
127 Cmd.CommandLine.size() * 16);
128 // The module-unit source path is already encoded in the parent cache
129 // directory. Output is rewritten while staging the BMI, so hash only the
130 // semantic compile command to keep the cache key stable across rebuilds.
131 SerializedCommand.append(Cmd.Directory);
132 SerializedCommand.push_back('\0');
133 for (const auto &Arg : Cmd.CommandLine) {
134 SerializedCommand.append(Arg);
135 SerializedCommand.push_back('\0');
136 }
137 return hashStringForCache(SerializedCommand);
138}
139
140/// Returns the directory for a persistent BMI built from a specific module
141/// unit source and compile command. The directory name keeps a readable source
142/// basename alongside the source-hash, and the command-hash keeps incompatible
143/// command lines apart.
144llvm::SmallString<256>
145getModuleFilesDirectory(PathRef ModuleUnitFileName,
146 const tooling::CompileCommand &Cmd,
147 const GlobalCompilationDatabase &CDB) {
148 llvm::SmallString<256> Result = getModuleCacheRoot(ModuleUnitFileName, CDB);
149 llvm::sys::path::append(Result,
150 getModuleUnitSourceDirectoryName(ModuleUnitFileName),
151 getCompileCommandStringHash(Cmd));
152 return Result;
153}
154
155/// Returns the lock file path guarding publication of BMIs for a module unit
156/// source. Builders targeting the same source-hash serialize through this path.
157llvm::SmallString<256>
158getModuleSourceHashLockPath(PathRef ModuleUnitFileName,
159 const GlobalCompilationDatabase &CDB) {
160 llvm::SmallString<256> Result =
161 getModuleCacheLocksDirectory(ModuleUnitFileName, CDB);
162 llvm::sys::path::append(Result,
163 getModuleUnitSourcePathHash(ModuleUnitFileName));
164 return Result;
165}
166
167/// Returns a unique temporary path used to stage a BMI before atomically
168/// publishing it to the stable cache path.
169llvm::SmallString<256> getTemporaryModuleFilePath(PathRef ModuleFilePath) {
170 llvm::SmallString<256> ResultPattern(ModuleFilePath);
171 ResultPattern.append(".tmp-%%-%%-%%-%%-%%-%%");
172 llvm::SmallString<256> Result;
173 llvm::sys::fs::createUniquePath(ResultPattern, Result,
174 /*MakeAbsolute=*/false);
175 return Result;
176}
177
178std::string getModuleFileVersionTimestamp() {
179 const auto Now = std::chrono::system_clock::now();
180 const auto Micros = std::chrono::duration_cast<std::chrono::microseconds>(
181 Now.time_since_epoch()) %
182 std::chrono::seconds(1);
183 const std::time_t CalendarTime = std::chrono::system_clock::to_time_t(Now);
184 std::tm LocalTime;
185#ifdef _WIN32
186 localtime_s(&LocalTime, &CalendarTime);
187#else
188 localtime_r(&CalendarTime, &LocalTime);
189#endif
190
191 return llvm::formatv("{0:04}{1:02}{2:02}-{3:02}{4:02}{5:02}-{6:06}",
192 LocalTime.tm_year + 1900, LocalTime.tm_mon + 1,
193 LocalTime.tm_mday, LocalTime.tm_hour, LocalTime.tm_min,
194 LocalTime.tm_sec, Micros.count())
195 .str();
196}
197
198llvm::SmallString<256>
199getCopyOnReadModuleFilePath(PathRef PublishedModuleFile) {
200 llvm::SmallString<256> Result(PublishedModuleFile);
201 llvm::sys::path::remove_filename(Result);
202 llvm::sys::path::append(
203 Result,
204 llvm::formatv("{0}-{1}{2}", llvm::sys::path::stem(PublishedModuleFile),
205 getModuleFileVersionTimestamp(),
206 llvm::sys::path::extension(PublishedModuleFile))
207 .str());
208 return Result;
209}
210
211/// Ensures the lock anchor file exists before LockFileManager tries to acquire
212/// ownership, creating parent directories as needed.
213llvm::Error ensureLockAnchorFileExists(PathRef LockPath) {
214 llvm::SmallString<256> LockParent(LockPath);
215 llvm::sys::path::remove_filename(LockParent);
216 if (std::error_code EC = llvm::sys::fs::create_directories(LockParent))
217 return llvm::createStringError(llvm::formatv(
218 "Failed to create lock directory {0}: {1}", LockParent, EC.message()));
219
220 int FD = -1;
221 if (std::error_code EC = llvm::sys::fs::openFileForWrite(
222 LockPath, FD, llvm::sys::fs::CD_OpenAlways))
223 return llvm::createStringError(llvm::formatv(
224 "Failed to open lock file anchor {0}: {1}", LockPath, EC.message()));
225 llvm::sys::Process::SafelyCloseFileDescriptor(FD);
226 return llvm::Error::success();
227}
228
229//===----------------------------------------------------------------------===//
230// Persistent Module Cache Locking.
231//
232// Builders targeting the same module-unit source share a source-hash lock.
233// This serializes in-place replacement of stale cache entries and final publish
234// of the stable BMI path, while still allowing unrelated module sources to be
235// built concurrently.
236//
237// builder A builder B
238// | |
239// +---- lock(source) ----->|
240// | |
241// | build/publish BMI | wait
242// | |
243// +---- unlock ----------->|
244// | reuse or rebuild
245//===----------------------------------------------------------------------===//
246
247/// Serializes publication and in-place replacement of persistent BMIs for a
248/// single module-unit source across multiple builders.
249class ScopedModuleSourceLock {
250public:
251 static llvm::Expected<ScopedModuleSourceLock>
252 acquire(PathRef ModuleUnitFileName, const GlobalCompilationDatabase &CDB) {
253 constexpr auto LockWaitInterval = std::chrono::seconds(10);
254 llvm::SmallString<256> LockPath =
255 getModuleSourceHashLockPath(ModuleUnitFileName, CDB);
256 if (llvm::Error Err = ensureLockAnchorFileExists(LockPath))
257 return std::move(Err);
258
259 auto Waited = std::chrono::seconds::zero();
260
261 while (true) {
262 auto Lock = std::make_unique<llvm::LockFileManager>(LockPath);
263 auto TryLock = Lock->tryLock();
264 if (!TryLock)
265 return TryLock.takeError();
266 if (*TryLock)
267 return ScopedModuleSourceLock(std::move(Lock));
268
269 switch (Lock->waitForUnlockFor(LockWaitInterval)) {
270 case llvm::WaitForUnlockResult::Success:
271 case llvm::WaitForUnlockResult::OwnerDied:
272 continue;
273 case llvm::WaitForUnlockResult::Timeout:
274 Waited += LockWaitInterval;
275 log("Still waiting for module lock {0} after {1}s", LockPath,
276 Waited.count());
277 continue;
278 }
279 llvm_unreachable("Unhandled lock wait result");
280 }
281 }
282
283private:
284 explicit ScopedModuleSourceLock(std::unique_ptr<llvm::LockFileManager> Lock)
285 : Lock(std::move(Lock)) {}
286
287 std::unique_ptr<llvm::LockFileManager> Lock;
288};
289
290// Get the stable published module file path under \param ModuleFilesPrefix.
291std::string getModuleFilePath(llvm::StringRef ModuleName,
292 PathRef ModuleFilesPrefix) {
293 llvm::SmallString<256> ModuleFilePath(ModuleFilesPrefix);
294 auto [PrimaryModuleName, PartitionName] = ModuleName.split(':');
295 llvm::sys::path::append(ModuleFilePath, PrimaryModuleName);
296 if (!PartitionName.empty()) {
297 ModuleFilePath.append("-");
298 ModuleFilePath.append(PartitionName);
299 }
300
301 ModuleFilePath.append(".pcm");
302 return std::string(ModuleFilePath);
303}
304
305std::string getPublishedModuleFilePath(llvm::StringRef ModuleName,
306 PathRef ModuleFilesPrefix) {
307 return getModuleFilePath(ModuleName, ModuleFilesPrefix);
308}
309
310// FailedPrerequisiteModules - stands for the PrerequisiteModules which has
311// errors happened during the building process.
312class FailedPrerequisiteModules : public PrerequisiteModules {
313public:
314 ~FailedPrerequisiteModules() override = default;
315
316 // We shouldn't adjust the compilation commands based on
317 // FailedPrerequisiteModules.
318 void adjustHeaderSearchOptions(HeaderSearchOptions &Options) const override {}
319
320 // FailedPrerequisiteModules can never be reused.
321 bool
322 canReuse(const CompilerInvocation &CI,
323 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) const override {
324 return false;
325 }
326
327 llvm::StringSet<> getRequiredModuleNames() const override { return {}; }
328};
329
330/// Represents a reference to a module file (*.pcm).
331class ModuleFile {
332protected:
333 ModuleFile(StringRef ModuleName, PathRef ModuleFilePath)
334 : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.str()) {}
335
336public:
337 ModuleFile() = delete;
338
339 ModuleFile(const ModuleFile &) = delete;
340 ModuleFile operator=(const ModuleFile &) = delete;
341
342 // The move constructor is needed for llvm::SmallVector.
343 ModuleFile(ModuleFile &&Other)
344 : ModuleName(std::move(Other.ModuleName)),
345 ModuleFilePath(std::move(Other.ModuleFilePath)) {
346 Other.ModuleName.clear();
347 Other.ModuleFilePath.clear();
348 }
349
350 ModuleFile &operator=(ModuleFile &&Other) {
351 if (this == &Other)
352 return *this;
353
354 this->~ModuleFile();
355 new (this) ModuleFile(std::move(Other));
356 return *this;
357 }
358 virtual ~ModuleFile() = default;
359
360 StringRef getModuleName() const { return ModuleName; }
361
362 StringRef getModuleFilePath() const { return ModuleFilePath; }
363
364protected:
365 std::string ModuleName;
366 std::string ModuleFilePath;
367};
368
369/// Represents a prebuilt module file which is not owned by us.
370class PrebuiltModuleFile : public ModuleFile {
371private:
372 // private class to make sure the class can only be constructed by member
373 // functions.
374 struct CtorTag {};
375
376public:
377 PrebuiltModuleFile(StringRef ModuleName, PathRef ModuleFilePath, CtorTag)
378 : ModuleFile(ModuleName, ModuleFilePath) {}
379
380 static std::shared_ptr<PrebuiltModuleFile> make(StringRef ModuleName,
381 PathRef ModuleFilePath) {
382 return std::make_shared<PrebuiltModuleFile>(ModuleName, ModuleFilePath,
383 CtorTag{});
384 }
385};
386
387//===----------------------------------------------------------------------===//
388// Module File Ownership and Reuse.
389//
390// PrebuiltModuleFile refers to BMIs supplied directly by the compile command.
391// BuiltModuleFile refers to BMIs produced by clangd and published into the
392// persistent cache. Object lifetime does not control filesystem lifetime for
393// BuiltModuleFile; cache files remain on disk for reuse across builders. The
394// versioned copies handed to clang for actual reads are owned by
395// CopyOnReadModuleFile and are deleted when the last reader releases them.
396//
397// Copy-on-read keeps the published BMI path stable for future builders while
398// avoiding in-place replacement races for active readers. clangd never hands
399// the stable cache entry directly to parsing code. Instead, once a published
400// BMI is known to be up to date, clangd copies it to a versioned sibling path
401// and gives that copy to readers. Rebuilding only mutates the stable cache
402// entry; existing readers keep their own immutable copy until the last
403// shared_ptr reference drops and the copy-on-read file is deleted.
404//
405// compile command ---------> PrebuiltModuleFile
406//
407// clangd build -> publish -> BuiltModuleFile ------------> stable cache path
408// (M.pcm)
409// |
410// +-> copy for read -> CopyOnReadModuleFile
411// (M-<timestamp>.pcm)
412// -> handed to clang readers
413// -> removed on last release
414//
415// later builder -----------> reuse stable cache path ----> copy for read
416//===----------------------------------------------------------------------===//
417
418/// Represents a module file built and published by clangd into its persistent
419/// cache.
420class BuiltModuleFile final : public ModuleFile {
421private:
422 // private class to make sure the class can only be constructed by member
423 // functions.
424 struct CtorTag {};
425
426public:
427 BuiltModuleFile(StringRef ModuleName, PathRef ModuleFilePath, CtorTag)
428 : ModuleFile(ModuleName, ModuleFilePath) {}
429
430 static std::shared_ptr<BuiltModuleFile> make(StringRef ModuleName,
431 PathRef ModuleFilePath) {
432 return std::make_shared<BuiltModuleFile>(ModuleName, ModuleFilePath,
433 CtorTag{});
434 }
435};
436
437/// Represents a versioned copy of a published BMI handed to clangd readers.
438/// The copy is removed when the last reader releases it.
439class CopyOnReadModuleFile final : public ModuleFile {
440private:
441 struct CtorTag {};
442
443public:
444 CopyOnReadModuleFile(StringRef ModuleName, PathRef ModuleFilePath, CtorTag)
445 : ModuleFile(ModuleName, ModuleFilePath) {}
446
447 ~CopyOnReadModuleFile() override {
448 if (!ModuleFilePath.empty() && !DebugModulesBuilder)
449 if (std::error_code EC = llvm::sys::fs::remove(ModuleFilePath))
450 vlog("Failed to remove copy-on-read module file {0}: {1}",
451 ModuleFilePath, EC.message());
452 }
453
454 static std::shared_ptr<CopyOnReadModuleFile> make(StringRef ModuleName,
455 PathRef ModuleFilePath) {
456 return std::make_shared<CopyOnReadModuleFile>(ModuleName, ModuleFilePath,
457 CtorTag{});
458 }
459};
460
461// ReusablePrerequisiteModules - stands for PrerequisiteModules for which all
462// the required modules are built successfully. All the module files
463// are owned by the modules builder.
464class ReusablePrerequisiteModules : public PrerequisiteModules {
465public:
466 ReusablePrerequisiteModules() = default;
467
468 ReusablePrerequisiteModules(const ReusablePrerequisiteModules &Other) =
469 default;
470 ReusablePrerequisiteModules &
471 operator=(const ReusablePrerequisiteModules &) = default;
472 ReusablePrerequisiteModules(ReusablePrerequisiteModules &&) = delete;
473 ReusablePrerequisiteModules
474 operator=(ReusablePrerequisiteModules &&) = delete;
475
476 ~ReusablePrerequisiteModules() override = default;
477
478 void adjustHeaderSearchOptions(HeaderSearchOptions &Options) const override {
479 // Appending all built module files.
480 for (const auto &RequiredModule : RequiredModules)
481 Options.PrebuiltModuleFiles.insert_or_assign(
482 RequiredModule->getModuleName().str(),
483 RequiredModule->getModuleFilePath().str());
484 }
485
486 std::string getAsString() const {
487 std::string Result;
488 llvm::raw_string_ostream OS(Result);
489 for (const auto &MF : RequiredModules) {
490 OS << "-fmodule-file=" << MF->getModuleName() << "="
491 << MF->getModuleFilePath() << " ";
492 }
493 return Result;
494 }
495
496 bool canReuse(const CompilerInvocation &CI,
497 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) const override;
498
499 bool isModuleUnitBuilt(llvm::StringRef ModuleName) const {
500 return BuiltModuleNames.contains(ModuleName);
501 }
502
503 void addModuleFile(std::shared_ptr<const ModuleFile> MF) {
504 BuiltModuleNames.insert(MF->getModuleName());
505 RequiredModules.emplace_back(std::move(MF));
506 }
507
508 void setDirectModuleNames(std::vector<std::string> Names) {
509 DirectModuleNames.insert_range(Names);
510 }
511
512 llvm::StringSet<> getRequiredModuleNames() const override {
513 return DirectModuleNames;
514 }
515
516private:
517 llvm::SmallVector<std::shared_ptr<const ModuleFile>, 8> RequiredModules;
518 // A helper class to speedup the query if a module is built.
519 llvm::StringSet<> BuiltModuleNames;
520 // The directly required module names as scanned from the source file.
521 llvm::StringSet<> DirectModuleNames;
522};
523
524bool IsModuleFileUpToDate(PathRef ModuleFilePath,
525 const PrerequisiteModules &RequisiteModules,
526 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
527 HeaderSearchOptions HSOpts;
528 RequisiteModules.adjustHeaderSearchOptions(HSOpts);
529 HSOpts.ForceCheckCXX20ModulesInputFiles = true;
530 HSOpts.ValidateASTInputFilesContent = true;
531
532 clang::clangd::IgnoreDiagnostics IgnoreDiags;
533 DiagnosticOptions DiagOpts;
534 IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
535 CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags,
536 /*ShouldOwnClient=*/false);
537
538 LangOptions LangOpts;
539 LangOpts.SkipODRCheckInGMF = true;
540
541 FileManager FileMgr(FileSystemOptions(), VFS);
542
543 SourceManager SourceMgr(*Diags, FileMgr);
544
545 HeaderSearch HeaderInfo(HSOpts, SourceMgr, *Diags, LangOpts,
546 /*Target=*/nullptr);
547
548 PreprocessorOptions PPOpts;
549 TrivialModuleLoader ModuleLoader;
550 Preprocessor PP(PPOpts, *Diags, LangOpts, SourceMgr, HeaderInfo,
551 ModuleLoader);
552
553 std::shared_ptr<ModuleCache> ModCache = createCrossProcessModuleCache();
554 PCHContainerOperations PCHOperations;
555 CodeGenOptions CodeGenOpts;
556 ASTReader Reader(
557 PP, *ModCache, /*ASTContext=*/nullptr, PCHOperations.getRawReader(),
558 CodeGenOpts, {},
559 /*isysroot=*/"",
560 /*DisableValidationKind=*/DisableValidationForModuleKind::None,
561 /*AllowASTWithCompilerErrors=*/false,
562 /*AllowConfigurationMismatch=*/false,
563 /*ValidateSystemInputs=*/false,
564 /*ForceValidateUserInputs=*/true,
565 /*ValidateASTInputFilesContent=*/true);
566
567 // We don't need any listener here. By default it will use a validator
568 // listener.
569 Reader.setListener(nullptr);
570
571 // Use ARR_OutOfDate so that ReadAST returns OutOfDate instead of Failure
572 // when input files are modified. This allows us to detect staleness
573 // without treating it as a hard error.
574 // ReadAST will validate all input files internally and return OutOfDate
575 // if any file is modified.
576 return Reader.ReadAST(ModuleFileName::makeExplicit(ModuleFilePath),
577 serialization::MK_MainFile, SourceLocation(),
578 ASTReader::ARR_OutOfDate) == ASTReader::Success;
579}
580
581bool IsModuleFilesUpToDate(
582 llvm::SmallVector<PathRef> ModuleFilePaths,
583 const PrerequisiteModules &RequisiteModules,
584 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
585 return llvm::all_of(
586 ModuleFilePaths, [&RequisiteModules, VFS](auto ModuleFilePath) {
587 return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules, VFS);
588 });
589}
590
591/// Builds a BMI into a temporary file and publishes it to `ModuleFilePath`.
592/// If another builder wins the publish race first, reports that through
593/// `PublishedExistingModuleFile` so the caller can validate and reuse it.
594llvm::Expected<std::shared_ptr<BuiltModuleFile>>
595buildModuleFile(llvm::StringRef ModuleName, PathRef ModuleUnitFileName,
596 tooling::CompileCommand Cmd, PathRef ModuleFilePath,
597 const ThreadsafeFS &TFS,
598 const ReusablePrerequisiteModules &BuiltModuleFiles,
599 bool &PublishedExistingModuleFile) {
600 PublishedExistingModuleFile = false;
601 llvm::SmallString<256> ModuleFilesPrefix(ModuleFilePath);
602 llvm::sys::path::remove_filename(ModuleFilesPrefix);
603 if (std::error_code EC = llvm::sys::fs::create_directories(ModuleFilesPrefix))
604 return llvm::createStringError(
605 llvm::formatv("Failed to create module cache directory {0}: {1}",
606 ModuleFilesPrefix, EC.message()));
607
608 llvm::SmallString<256> TemporaryModuleFilePath =
609 getTemporaryModuleFilePath(ModuleFilePath);
610 auto RemoveTemporaryModuleFile = llvm::scope_exit([&] {
611 if (!TemporaryModuleFilePath.empty() && !DebugModulesBuilder)
612 llvm::sys::fs::remove(TemporaryModuleFilePath);
613 });
614 (void)RemoveTemporaryModuleFile;
615
616 Cmd.Output = TemporaryModuleFilePath.str().str();
617
618 ParseInputs Inputs;
619 Inputs.TFS = &TFS;
620 Inputs.CompileCommand = std::move(Cmd);
621
622 IgnoreDiagnostics IgnoreDiags;
623 auto CI = buildCompilerInvocation(Inputs, IgnoreDiags);
624 if (!CI)
625 return llvm::createStringError("Failed to build compiler invocation");
626
627 auto FS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
628 auto Buf = FS->getBufferForFile(Inputs.CompileCommand.Filename);
629 if (!Buf)
630 return llvm::createStringError("Failed to create buffer");
631
632 // In clang's driver, we will suppress the check for ODR violation in GMF.
633 // See the implementation of RenderModulesOptions in Clang.cpp.
634 CI->getLangOpts().SkipODRCheckInGMF = true;
635
636 // Hash the contents of input files and store the hash value to the BMI files.
637 // So that we can check if the files are still valid when we want to reuse the
638 // BMI files.
639 CI->getHeaderSearchOpts().ValidateASTInputFilesContent = true;
640
641 BuiltModuleFiles.adjustHeaderSearchOptions(CI->getHeaderSearchOpts());
642
643 CI->getFrontendOpts().OutputFile = Inputs.CompileCommand.Output;
644 auto Clang =
645 prepareCompilerInstance(std::move(CI), /*Preamble=*/nullptr,
646 std::move(*Buf), std::move(FS), IgnoreDiags);
647 if (!Clang)
648 return llvm::createStringError("Failed to prepare compiler instance");
649
650 GenerateReducedModuleInterfaceAction Action;
651 Clang->ExecuteAction(Action);
652
653 if (Clang->getDiagnostics().hasErrorOccurred()) {
654 std::string Cmds;
655 for (const auto &Arg : Inputs.CompileCommand.CommandLine) {
656 if (!Cmds.empty())
657 Cmds += " ";
658 Cmds += Arg;
659 }
660
661 clangd::vlog("Failed to compile {0} with command: {1}", ModuleUnitFileName,
662 Cmds);
663
664 std::string BuiltModuleFilesStr = BuiltModuleFiles.getAsString();
665 if (!BuiltModuleFilesStr.empty())
666 clangd::vlog("The actual used module files built by clangd is {0}",
667 BuiltModuleFilesStr);
668
669 return llvm::createStringError(
670 llvm::formatv("Failed to compile {0}. Use '--log=verbose' to view "
671 "detailed failure reasons. It is helpful to use "
672 "'--debug-modules-builder' flag to keep the clangd's "
673 "built module files to reproduce the failure for "
674 "debugging. Remember to remove them after debugging.",
675 ModuleUnitFileName));
676 }
677
678 if (std::error_code EC =
679 llvm::sys::fs::rename(TemporaryModuleFilePath, ModuleFilePath)) {
680 if (!llvm::sys::fs::exists(ModuleFilePath))
681 return llvm::createStringError(
682 llvm::formatv("Failed to publish module file {0}: {1}",
683 ModuleFilePath, EC.message()));
684 // Another builder already published the stable cache entry. Drop our
685 // staged BMI and let the caller revalidate the published path.
686 PublishedExistingModuleFile = true;
687 } else {
688 // Rename consumed the staging file into the stable cache path. Clear it so
689 // the scope-exit cleanup does not try to remove the published BMI.
690 TemporaryModuleFilePath.clear();
691 }
692
693 return BuiltModuleFile::make(ModuleName, ModuleFilePath);
694}
695
696llvm::Expected<std::shared_ptr<CopyOnReadModuleFile>>
697copyModuleFileForRead(llvm::StringRef ModuleName,
698 PathRef PublishedModuleFilePath) {
699 llvm::SmallString<256> VersionedModuleFilePath =
700 getCopyOnReadModuleFilePath(PublishedModuleFilePath);
701 if (std::error_code EC = llvm::sys::fs::copy_file(PublishedModuleFilePath,
702 VersionedModuleFilePath))
703 return llvm::createStringError(llvm::formatv(
704 "Failed to copy module file {0} to {1}: {2}", PublishedModuleFilePath,
705 VersionedModuleFilePath, EC.message()));
706 return CopyOnReadModuleFile::make(ModuleName, VersionedModuleFilePath);
707}
708
709bool ReusablePrerequisiteModules::canReuse(
710 const CompilerInvocation &CI,
711 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) const {
712 if (RequiredModules.empty())
713 return true;
714
715 llvm::SmallVector<llvm::StringRef> BMIPaths;
716 for (auto &MF : RequiredModules)
717 BMIPaths.push_back(MF->getModuleFilePath());
718 return IsModuleFilesUpToDate(BMIPaths, *this, VFS);
719}
720
721//===----------------------------------------------------------------------===//
722// In-Memory Module File Cache.
723//
724// This cache deduplicates BMIs within a single builder instance. Its key
725// mirrors the persistent cache layout: module name, module-unit source, and
726// compile command hash. That prevents a builder from reusing a BMI built under
727// a different command line.
728//
729// (module name,
730// module-unit source,
731// command hash)
732// |
733// v
734// ModuleFileCache
735// |
736// +-- hit -> reuse in current builder
737// |
738// +-- miss -> probe persistent cache / rebuild
739//===----------------------------------------------------------------------===//
740
741/// In-memory cache for module files built by clangd. Entries are keyed by
742/// module name, module-unit source, and compile-command hash so persistent BMI
743/// variants do not collide.
744class ModuleFileCache {
745public:
746 ModuleFileCache(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
747 const GlobalCompilationDatabase &getCDB() const { return CDB; }
748
749 std::shared_ptr<const ModuleFile> getModule(StringRef ModuleName,
750 PathRef ModuleUnitSource,
751 llvm::StringRef CommandHash);
752
753 void add(StringRef ModuleName, PathRef ModuleUnitSource,
754 llvm::StringRef CommandHash,
755 std::shared_ptr<const ModuleFile> ModuleFile) {
756 std::lock_guard<std::mutex> Lock(ModuleFilesMutex);
757 ModuleFiles[cacheKey(ModuleName, ModuleUnitSource, CommandHash)] =
758 ModuleFile;
759 }
760
761 void remove(StringRef ModuleName, PathRef ModuleUnitSource,
762 llvm::StringRef CommandHash);
763
764private:
765 static std::string cacheKey(StringRef ModuleName, PathRef ModuleUnitSource,
766 llvm::StringRef CommandHash) {
767 std::string Key;
768 Key.reserve(ModuleName.size() + ModuleUnitSource.size() +
769 CommandHash.size() + 2);
770 Key.append(ModuleName);
771 Key.push_back('\0');
772 Key.append(maybeCaseFoldPath(ModuleUnitSource));
773 Key.push_back('\0');
774 Key.append(CommandHash);
775 return Key;
776 }
777
778 const GlobalCompilationDatabase &CDB;
779
780 llvm::StringMap<std::weak_ptr<const ModuleFile>> ModuleFiles;
781 std::mutex ModuleFilesMutex;
782};
783
784std::shared_ptr<const ModuleFile>
785ModuleFileCache::getModule(StringRef ModuleName, PathRef ModuleUnitSource,
786 llvm::StringRef CommandHash) {
787 std::lock_guard<std::mutex> Lock(ModuleFilesMutex);
788
789 auto Iter =
790 ModuleFiles.find(cacheKey(ModuleName, ModuleUnitSource, CommandHash));
791 if (Iter == ModuleFiles.end())
792 return nullptr;
793
794 if (auto Res = Iter->second.lock())
795 return Res;
796
797 ModuleFiles.erase(Iter);
798 return nullptr;
799}
800
801void ModuleFileCache::remove(StringRef ModuleName, PathRef ModuleUnitSource,
802 llvm::StringRef CommandHash) {
803 std::lock_guard<std::mutex> Lock(ModuleFilesMutex);
804 ModuleFiles.erase(cacheKey(ModuleName, ModuleUnitSource, CommandHash));
805}
806
807class ModuleNameToSourceCache {
808public:
809 std::string getUniqueSourceForModuleName(llvm::StringRef ModuleName) {
810 std::lock_guard<std::mutex> Lock(CacheMutex);
811 auto Iter = ModuleNameToUniqueSourceCache.find(ModuleName);
812 if (Iter != ModuleNameToUniqueSourceCache.end())
813 return Iter->second;
814 return "";
815 }
816
817 void addUniqueEntry(llvm::StringRef ModuleName, PathRef Source) {
818 std::lock_guard<std::mutex> Lock(CacheMutex);
819 ModuleNameToUniqueSourceCache[ModuleName] = Source.str();
820 }
821
822 void eraseUniqueEntry(llvm::StringRef ModuleName) {
823 std::lock_guard<std::mutex> Lock(CacheMutex);
824 ModuleNameToUniqueSourceCache.erase(ModuleName);
825 }
826
827 std::string getMultipleSourceForModuleName(llvm::StringRef ModuleName,
828 PathRef RequiredSrcFile) {
829 std::lock_guard<std::mutex> Lock(CacheMutex);
830 auto Outer = ModuleNameToMultipleSourceCache.find(ModuleName);
831 if (Outer == ModuleNameToMultipleSourceCache.end())
832 return "";
833 auto Inner = Outer->second.find(maybeCaseFoldPath(RequiredSrcFile));
834 if (Inner == Outer->second.end())
835 return "";
836 return Inner->second;
837 }
838
839 void addMultipleEntry(llvm::StringRef ModuleName, PathRef RequiredSrcFile,
840 PathRef Source) {
841 std::lock_guard<std::mutex> Lock(CacheMutex);
842 ModuleNameToMultipleSourceCache[ModuleName]
843 [maybeCaseFoldPath(RequiredSrcFile)] =
844 Source.str();
845 }
846
847 void eraseMultipleEntry(llvm::StringRef ModuleName, PathRef RequiredSrcFile) {
848 std::lock_guard<std::mutex> Lock(CacheMutex);
849 auto Outer = ModuleNameToMultipleSourceCache.find(ModuleName);
850 if (Outer == ModuleNameToMultipleSourceCache.end())
851 return;
852 Outer->second.erase(maybeCaseFoldPath(RequiredSrcFile));
853 if (Outer->second.empty())
854 ModuleNameToMultipleSourceCache.erase(Outer);
855 }
856
857private:
858 std::mutex CacheMutex;
859 llvm::StringMap<std::string> ModuleNameToUniqueSourceCache;
860
861 // Map from module name to a map from required source to module unit source
862 // which declares the corresponding module name.
863 // This looks inefficiency. We can only assume there won't too many duplicated
864 // module names with different module units in a project.
865 llvm::StringMap<llvm::StringMap<std::string>> ModuleNameToMultipleSourceCache;
866};
867
868class CachingProjectModules : public ProjectModules {
869public:
870 CachingProjectModules(std::unique_ptr<ProjectModules> MDB,
871 ModuleNameToSourceCache &Cache)
872 : MDB(std::move(MDB)), Cache(Cache) {
873 assert(this->MDB && "CachingProjectModules should only be created with a "
874 "valid underlying ProjectModules");
875 }
876
877 std::vector<std::string> getRequiredModules(PathRef File) override {
878 return MDB->getRequiredModules(File);
879 }
880
881 std::string getModuleNameForSource(PathRef File) override {
882 return MDB->getModuleNameForSource(File);
883 }
884
885 ModuleNameState getModuleNameState(llvm::StringRef ModuleName) override {
886 return MDB->getModuleNameState(ModuleName);
887 }
888
889 std::string getSourceForModuleName(llvm::StringRef ModuleName,
890 PathRef RequiredSrcFile) override {
891 auto ModuleState = MDB->getModuleNameState(ModuleName);
892
893 if (ModuleState == ModuleNameState::Multiple) {
894 std::string CachedResult =
895 Cache.getMultipleSourceForModuleName(ModuleName, RequiredSrcFile);
896
897 // Verify Cached Result by seeing if the source declaring the same module
898 // as we query.
899 if (!CachedResult.empty()) {
900 std::string ModuleNameOfCachedSource =
901 MDB->getModuleNameForSource(CachedResult);
902 if (ModuleNameOfCachedSource == ModuleName)
903 return CachedResult;
904
905 // Cached Result is invalid. Clear it.
906 Cache.eraseMultipleEntry(ModuleName, RequiredSrcFile);
907 }
908
909 auto Result = MDB->getSourceForModuleName(ModuleName, RequiredSrcFile);
910 if (!Result.empty())
911 Cache.addMultipleEntry(ModuleName, RequiredSrcFile, Result);
912 return Result;
913 }
914
915 // For unknown module name state, assume it is unique. This may give user
916 // higher usability.
917 assert(ModuleState == ModuleNameState::Unique ||
918 ModuleState == ModuleNameState::Unknown);
919 std::string CachedResult = Cache.getUniqueSourceForModuleName(ModuleName);
920
921 // Verify Cached Result by seeing if the source declaring the same module
922 // as we query.
923 if (!CachedResult.empty()) {
924 std::string ModuleNameOfCachedSource =
925 MDB->getModuleNameForSource(CachedResult);
926 if (ModuleNameOfCachedSource == ModuleName)
927 return CachedResult;
928
929 // Cached Result is invalid. Clear it.
930 Cache.eraseUniqueEntry(ModuleName);
931 }
932
933 auto Result = MDB->getSourceForModuleName(ModuleName, RequiredSrcFile);
934 if (!Result.empty())
935 Cache.addUniqueEntry(ModuleName, Result);
936
937 return Result;
938 }
939
940private:
941 std::unique_ptr<ProjectModules> MDB;
942 ModuleNameToSourceCache &Cache;
943};
944
945/// Collect the directly and indirectly required module names for \param
946/// ModuleName in topological order. The \param ModuleName is guaranteed to
947/// be the last element in \param ModuleNames.
948llvm::SmallVector<std::string> getAllRequiredModules(PathRef RequiredSource,
949 CachingProjectModules &MDB,
950 StringRef ModuleName) {
951 llvm::SmallVector<std::string> ModuleNames;
952 llvm::StringSet<> ModuleNamesSet;
953
954 auto VisitDeps = [&](StringRef ModuleName, auto Visitor) -> void {
955 ModuleNamesSet.insert(ModuleName);
956
957 for (StringRef RequiredModuleName : MDB.getRequiredModules(
958 MDB.getSourceForModuleName(ModuleName, RequiredSource)))
959 if (ModuleNamesSet.insert(RequiredModuleName).second)
960 Visitor(RequiredModuleName, Visitor);
961
962 ModuleNames.push_back(ModuleName.str());
963 };
964 VisitDeps(ModuleName, VisitDeps);
965
966 return ModuleNames;
967}
968
969/// Collects cache roots to scan during constructor-time GC.
970/// Scans one cache root and returns all `.pcm` files under it.
971std::vector<std::string> collectModuleFiles(PathRef CacheRoot) {
972 std::vector<std::string> Result;
973 std::error_code EC;
974 for (llvm::sys::fs::recursive_directory_iterator It(CacheRoot, EC), End;
975 It != End && !EC; It.increment(EC)) {
976 if (llvm::sys::path::extension(It->path()) != ".pcm")
977 continue;
978 Result.push_back(It->path());
979 }
980 if (EC)
981 log("Failed to scan module cache directory {0}: {1}", CacheRoot,
982 EC.message());
983 return Result;
984}
985
986/// Performs one GC pass over a persistent module cache root.
987void garbageCollectModuleCache(PathRef CacheRoot) {
988 for (const auto &ModuleFilePath : collectModuleFiles(CacheRoot)) {
989 llvm::sys::fs::file_status Status;
990 if (std::error_code EC = llvm::sys::fs::status(ModuleFilePath, Status)) {
991 log("Failed to stat cached module file {0} for GC: {1}", ModuleFilePath,
992 EC.message());
993 continue;
994 }
995
996 llvm::sys::TimePoint<> LastAccess = Status.getLastAccessedTime();
997 llvm::sys::TimePoint<> Now = std::chrono::system_clock::now();
998 if (LastAccess > Now)
999 continue;
1000 auto Age =
1001 std::chrono::duration_cast<std::chrono::seconds>(Now - LastAccess);
1002 auto Threshold =
1003 std::chrono::seconds(VersionedModuleFileGCThresholdSeconds);
1004 if (Age <= Threshold)
1005 continue;
1006
1007 if (!llvm::sys::fs::exists(ModuleFilePath))
1008 continue;
1009
1010 constexpr llvm::StringLiteral Reason = "file older than GC threshold";
1011 if (std::error_code EC = llvm::sys::fs::remove(ModuleFilePath)) {
1012 log("Failed to remove cached module file {0} ({1}): {2}", ModuleFilePath,
1013 Reason, EC.message());
1014 continue;
1015 }
1016 log("Removed cached module file {0} ({1})", ModuleFilePath, Reason);
1017 }
1018}
1019
1020} // namespace
1021
1023public:
1025
1026 ModuleNameToSourceCache &getProjectModulesCache() {
1027 return ProjectModulesCache;
1028 }
1029 const GlobalCompilationDatabase &getCDB() const { return Cache.getCDB(); }
1030
1031 llvm::Error
1032 getOrBuildModuleFile(PathRef RequiredSource, StringRef ModuleName,
1033 const ThreadsafeFS &TFS, CachingProjectModules &MDB,
1034 ReusablePrerequisiteModules &BuiltModuleFiles);
1035
1036private:
1037 /// Try to get prebuilt module files from the compilation database.
1038 void getPrebuiltModuleFile(StringRef ModuleName, PathRef ModuleUnitFileName,
1039 const ThreadsafeFS &TFS,
1040 ReusablePrerequisiteModules &BuiltModuleFiles);
1041
1042 /// Runs GC once for the cache root owning a project root.
1043 void garbageCollectModuleCacheForProjectRoot(PathRef ProjectRoot);
1044
1045 ModuleFileCache Cache;
1046 ModuleNameToSourceCache ProjectModulesCache;
1047 std::mutex GarbageCollectedProjectRootsMutex;
1048 llvm::StringSet<> GarbageCollectedProjectRoots;
1049};
1050
1051void ModulesBuilder::ModulesBuilderImpl::
1052 garbageCollectModuleCacheForProjectRoot(PathRef ProjectRoot) {
1053 if (ProjectRoot.empty())
1054 return;
1055 std::string NormalizedProjectRoot = normalizePathForCache(ProjectRoot);
1056 {
1057 // If the project root lives in GarbageCollectedProjectRoots, it implies
1058 // we've already started GC on the cache root.
1059 std::lock_guard<std::mutex> Lock(GarbageCollectedProjectRootsMutex);
1060 if (!GarbageCollectedProjectRoots.insert(NormalizedProjectRoot).second)
1061 return;
1062 }
1063
1064 llvm::SmallString<256> CacheRoot(ProjectRoot);
1065 llvm::sys::path::append(CacheRoot, ".cache", "clangd", "modules");
1066 log("Running GC pass for clangd built module files under {0} with age "
1067 "threshold {1} seconds (adjust with --modules-builder-versioned-gc-"
1068 "threshold-seconds)",
1069 CacheRoot, VersionedModuleFileGCThresholdSeconds);
1070 garbageCollectModuleCache(CacheRoot);
1071 log("Done running GC pass for clangd built module files under {0}",
1072 CacheRoot);
1073}
1074
1075void ModulesBuilder::ModulesBuilderImpl::getPrebuiltModuleFile(
1076 StringRef ModuleName, PathRef ModuleUnitFileName, const ThreadsafeFS &TFS,
1077 ReusablePrerequisiteModules &BuiltModuleFiles) {
1078 auto Cmd = getCDB().getCompileCommand(ModuleUnitFileName);
1079 if (!Cmd)
1080 return;
1081
1082 ParseInputs Inputs;
1083 Inputs.TFS = &TFS;
1084 Inputs.CompileCommand = std::move(*Cmd);
1085
1086 IgnoreDiagnostics IgnoreDiags;
1087 auto CI = buildCompilerInvocation(Inputs, IgnoreDiags);
1088 if (!CI)
1089 return;
1090
1091 // We don't need to check if the module files are in ModuleCache or adding
1092 // them to the module cache. As even if the module files are in the module
1093 // cache, we still need to validate them. And it looks not helpful to add them
1094 // to the module cache, since we may always try to get the prebuilt module
1095 // files before building the module files by ourselves.
1096 for (auto &[ModuleName, ModuleFilePath] :
1097 CI->getHeaderSearchOpts().PrebuiltModuleFiles) {
1098 if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
1099 continue;
1100
1101 // Convert relative path to absolute path based on the compilation directory
1102 llvm::SmallString<256> AbsoluteModuleFilePath;
1103 if (llvm::sys::path::is_relative(ModuleFilePath)) {
1104 AbsoluteModuleFilePath = Inputs.CompileCommand.Directory;
1105 llvm::sys::path::append(AbsoluteModuleFilePath, ModuleFilePath);
1106 } else
1107 AbsoluteModuleFilePath = ModuleFilePath;
1108
1109 if (IsModuleFileUpToDate(AbsoluteModuleFilePath, BuiltModuleFiles,
1110 TFS.view(std::nullopt))) {
1111 log("Reusing prebuilt module file {0} of module {1} for {2}",
1112 AbsoluteModuleFilePath, ModuleName, ModuleUnitFileName);
1113 BuiltModuleFiles.addModuleFile(
1114 PrebuiltModuleFile::make(ModuleName, AbsoluteModuleFilePath));
1115 }
1116 }
1117}
1118
1120 PathRef RequiredSource, StringRef ModuleName, const ThreadsafeFS &TFS,
1121 CachingProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles) {
1122 if (BuiltModuleFiles.isModuleUnitBuilt(ModuleName))
1123 return llvm::Error::success();
1124
1125 std::string ModuleUnitFileName =
1126 MDB.getSourceForModuleName(ModuleName, RequiredSource);
1127 /// It is possible that we're meeting third party modules (modules whose
1128 /// source are not in the project. e.g, the std module may be a third-party
1129 /// module for most project) or something wrong with the implementation of
1130 /// ProjectModules.
1131 /// FIXME: How should we treat third party modules here? If we want to ignore
1132 /// third party modules, we should return true instead of false here.
1133 /// Currently we simply bail out.
1134 if (ModuleUnitFileName.empty())
1135 return llvm::createStringError(
1136 llvm::formatv("Don't get the module unit for module {0}", ModuleName));
1137
1138 /// Try to get prebuilt module files from the compilation database first. This
1139 /// helps to avoid building the module files that are already built by the
1140 /// compiler.
1141 getPrebuiltModuleFile(ModuleName, ModuleUnitFileName, TFS, BuiltModuleFiles);
1142
1143 // Get Required modules in topological order.
1144 auto ReqModuleNames = getAllRequiredModules(RequiredSource, MDB, ModuleName);
1145 for (llvm::StringRef ReqModuleName : ReqModuleNames) {
1146 if (BuiltModuleFiles.isModuleUnitBuilt(ReqModuleName))
1147 continue;
1148
1149 std::string ReqFileName =
1150 MDB.getSourceForModuleName(ReqModuleName, RequiredSource);
1151 auto Cmd = getCDB().getCompileCommand(ReqFileName);
1152 if (!Cmd)
1153 return llvm::createStringError(
1154 llvm::formatv("No compile command for {0}", ReqFileName));
1155 if (auto PI = getCDB().getProjectInfo(ReqFileName);
1156 PI && !PI->SourceRoot.empty())
1157 garbageCollectModuleCacheForProjectRoot(PI->SourceRoot);
1158
1159 const std::string CommandHash = getCompileCommandStringHash(*Cmd);
1160 const std::string PublishedModuleFilePath = getPublishedModuleFilePath(
1161 ReqModuleName, getModuleFilesDirectory(ReqFileName, *Cmd, getCDB()));
1162
1163 // Keep the source-scoped lock while probing and validating cached BMIs so
1164 // stale-file replacement and final publication stay serialized.
1165 auto SourceLock = ScopedModuleSourceLock::acquire(ReqFileName, getCDB());
1166 if (!SourceLock)
1167 return SourceLock.takeError();
1168
1169 std::shared_ptr<const ModuleFile> Cached =
1170 Cache.getModule(ReqModuleName, ReqFileName, CommandHash);
1171
1172 if (Cached) {
1173 if (IsModuleFileUpToDate(Cached->getModuleFilePath(), BuiltModuleFiles,
1174 TFS.view(std::nullopt))) {
1175 log("Reusing module {0} from {1}", ReqModuleName,
1176 Cached->getModuleFilePath());
1177 BuiltModuleFiles.addModuleFile(std::move(Cached));
1178 continue;
1179 }
1180 Cache.remove(ReqModuleName, ReqFileName, CommandHash);
1181 }
1182
1183 if (llvm::sys::fs::exists(PublishedModuleFilePath)) {
1184 if (IsModuleFileUpToDate(PublishedModuleFilePath, BuiltModuleFiles,
1185 TFS.view(std::nullopt))) {
1186 log("Reusing persistent module {0} from {1}", ReqModuleName,
1187 PublishedModuleFilePath);
1188 auto Materialized =
1189 copyModuleFileForRead(ReqModuleName, PublishedModuleFilePath);
1190 if (llvm::Error Err = Materialized.takeError())
1191 return Err;
1192 Cache.add(ReqModuleName, ReqFileName, CommandHash, *Materialized);
1193 BuiltModuleFiles.addModuleFile(std::move(*Materialized));
1194 continue;
1195 }
1196
1197 // The persistent module file is stale. Remove it and build a new one.
1198 std::error_code EC = llvm::sys::fs::remove(PublishedModuleFilePath);
1199 if (EC)
1200 return llvm::createStringError(
1201 llvm::formatv("Failed to remove stale module file {0}: {1}",
1202 PublishedModuleFilePath, EC.message()));
1203 }
1204
1205 bool PublishedExistingModuleFile = false;
1206 llvm::Expected<std::shared_ptr<BuiltModuleFile>> MF = buildModuleFile(
1207 ReqModuleName, ReqFileName, std::move(*Cmd), PublishedModuleFilePath,
1208 TFS, BuiltModuleFiles, PublishedExistingModuleFile);
1209 if (llvm::Error Err = MF.takeError())
1210 return Err;
1211
1212 if (PublishedExistingModuleFile &&
1213 !IsModuleFileUpToDate(PublishedModuleFilePath, BuiltModuleFiles,
1214 TFS.view(std::nullopt))) {
1215 return llvm::createStringError(
1216 llvm::formatv("Published module file {0} is stale after lock wait",
1217 PublishedModuleFilePath));
1218 }
1219
1220 auto Materialized =
1221 copyModuleFileForRead(ReqModuleName, PublishedModuleFilePath);
1222 if (llvm::Error Err = Materialized.takeError())
1223 return Err;
1224
1225 log("Built module {0} to {1}", ReqModuleName,
1226 (*Materialized)->getModuleFilePath());
1227 Cache.add(ReqModuleName, ReqFileName, CommandHash, *Materialized);
1228 BuiltModuleFiles.addModuleFile(std::move(*Materialized));
1229 }
1230
1231 return llvm::Error::success();
1232}
1233
1235 std::unique_ptr<ProjectModules> MDB = Impl->getCDB().getProjectModules(File);
1236 if (!MDB)
1237 return false;
1238
1239 CachingProjectModules CachedMDB(std::move(MDB),
1240 Impl->getProjectModulesCache());
1241 return !CachedMDB.getRequiredModules(File).empty();
1242}
1243
1245 std::unique_ptr<ProjectModules> MDB = Impl->getCDB().getProjectModules(File);
1246 if (!MDB)
1247 return {};
1248
1249 CachingProjectModules CachedMDB(std::move(MDB),
1250 Impl->getProjectModulesCache());
1251 return CachedMDB.getRequiredModules(File);
1252}
1253
1254std::unique_ptr<PrerequisiteModules>
1256 const ThreadsafeFS &TFS) {
1257 std::unique_ptr<ProjectModules> MDB = Impl->getCDB().getProjectModules(File);
1258 if (!MDB) {
1259 elog("Failed to get Project Modules information for {0}", File);
1260 return std::make_unique<FailedPrerequisiteModules>();
1261 }
1262 CachingProjectModules CachedMDB(std::move(MDB),
1263 Impl->getProjectModulesCache());
1264
1265 std::vector<std::string> RequiredModuleNames =
1266 CachedMDB.getRequiredModules(File);
1267 if (RequiredModuleNames.empty())
1268 return std::make_unique<ReusablePrerequisiteModules>();
1269
1270 auto RequiredModules = std::make_unique<ReusablePrerequisiteModules>();
1271 RequiredModules->setDirectModuleNames(RequiredModuleNames);
1272 for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {
1273 // Return early if there is any error.
1274 if (llvm::Error Err = Impl->getOrBuildModuleFile(
1275 File, RequiredModuleName, TFS, CachedMDB, *RequiredModules.get())) {
1276 elog("Failed to build module {0}; due to {1}", RequiredModuleName,
1277 toString(std::move(Err)));
1278 return std::make_unique<FailedPrerequisiteModules>();
1279 }
1280 }
1281
1282 return std::move(RequiredModules);
1283}
1284
1286 Impl = std::make_unique<ModulesBuilderImpl>(CDB);
1287}
1288
1290
1291} // namespace clangd
1292} // 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)
bool hasRequiredModules(PathRef File)
std::unique_ptr< PrerequisiteModules > buildPrerequisiteModulesFor(PathRef File, const ThreadsafeFS &TFS)
std::vector< std::string > getRequiredModuleNames(PathRef File)
Returns the list of directly required module names.
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:44
std::string maybeCaseFoldPath(PathRef Path)
Definition Path.cpp:18
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:96
FileDigest digest(llvm::StringRef Content)
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:131
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
std::string Path
A typedef to represent a file path.
Definition Path.h:26
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:51
const ThreadsafeFS * TFS
Definition Compiler.h:53