[clang-tools-extra] [clangd] [Modules] Support Reusable Modules Builder (PR #106683)

kadir çetinkaya via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 8 05:46:21 PST 2024


================
@@ -316,36 +309,221 @@ llvm::Error buildModuleFile(llvm::StringRef ModuleName,
   if (Clang->getDiagnostics().hasErrorOccurred())
     return llvm::createStringError("Compilation failed");
 
-  BuiltModuleFiles.addModuleFile(ModuleName, Inputs.CompileCommand.Output);
-  return llvm::Error::success();
+  return ModuleFile{ModuleName, Inputs.CompileCommand.Output, BuiltModuleFiles};
+}
+
+bool ReusablePrerequisiteModules::canReuse(
+    const CompilerInvocation &CI,
+    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) const {
+  if (RequiredModules.empty())
+    return true;
+
+  SmallVector<StringRef> BMIPaths;
+  for (auto &MF : RequiredModules)
+    BMIPaths.push_back(MF->getModuleFilePath());
+  return IsModuleFilesUpToDate(BMIPaths, *this, VFS);
+}
+
+class ModuleFileCache {
+public:
+  ModuleFileCache(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
+
+  llvm::Error
+  getOrBuildModuleFile(StringRef ModuleName, const ThreadsafeFS &TFS,
+                       ProjectModules &MDB,
+                       ReusablePrerequisiteModules &RequiredModules);
+  const GlobalCompilationDatabase &getCDB() const { return CDB; }
+
+  std::shared_ptr<const ModuleFile>
+  getValidModuleFile(StringRef ModuleName, ProjectModules &MDB,
+                     const ThreadsafeFS &TFS,
+                     PrerequisiteModules &BuiltModuleFiles);
+
+  void add(StringRef ModuleName, std::shared_ptr<const ModuleFile> ModuleFile) {
+    std::lock_guard<std::mutex> Lock(ModuleFilesMutex);
+
+    ModuleFiles.insert_or_assign(ModuleName, ModuleFile);
+  }
+
+private:
+  const GlobalCompilationDatabase &CDB;
+
+  llvm::StringMap<std::weak_ptr<const ModuleFile>> ModuleFiles;
+  // Mutex to guard accesses to ModuleFiles.
+  std::mutex ModuleFilesMutex;
+};
+
+/// Collect the directly and indirectly required module names for \param
+/// ModuleName. The \param ModuleName is guaranteed to be the first element in
+/// \param ModuleNames.
+llvm::SmallVector<StringRef> getAllRequiredModules(ProjectModules &MDB,
+                                                   StringRef ModuleName) {
+  llvm::SmallVector<StringRef> ModuleNames;
+
+  std::queue<StringRef> Worklist;
+  llvm::StringSet<> ModuleNamesSet;
+  Worklist.push(ModuleName);
+
+  while (!Worklist.empty()) {
+    StringRef CurrentModule = Worklist.front();
+    Worklist.pop();
+
+    if (!ModuleNamesSet.insert(CurrentModule).second)
+      continue;
+
+    ModuleNames.push_back(CurrentModule);
+
+    for (StringRef RequiredModuleName :
+         MDB.getRequiredModules(MDB.getSourceForModuleName(CurrentModule)))
+      if (!ModuleNamesSet.contains(RequiredModuleName))
+        Worklist.push(RequiredModuleName);
+  }
+
+  return ModuleNames;
+}
+
+std::shared_ptr<const ModuleFile>
+ModuleFileCache::getValidModuleFile(StringRef ModuleName, ProjectModules &MDB,
+                                    const ThreadsafeFS &TFS,
+                                    PrerequisiteModules &BuiltModuleFiles) {
+  {
+    std::lock_guard<std::mutex> Lock(ModuleFilesMutex);
+
+    auto Iter = ModuleFiles.find(ModuleName);
+    if (Iter == ModuleFiles.end())
+      return nullptr;
+
+    if (Iter->second.expired()) {
+      ModuleFiles.erase(Iter);
+      return nullptr;
+    }
----------------
kadircet wrote:

no point in performing this check now.

it can expire until we perform the loop below and we're already bailing out if this is the case.

so either drop this check, or put a copy into `RequiredModuleFiles` after lookup (and change `getAllRequiredModules` to not return the root module)

https://github.com/llvm/llvm-project/pull/106683


More information about the cfe-commits mailing list