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