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