diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 7098efc770068..2ca3fd50f2fd2 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -708,7 +708,7 @@ class ModuleDependencyInfo { bool isStaticLibrary() const { if (auto *detail = getAsSwiftInterfaceModule()) return detail->isStatic; - else if (auto *detail = getAsSwiftBinaryModule()) + if (auto *detail = getAsSwiftBinaryModule()) return detail->isStatic; return false; } @@ -716,9 +716,9 @@ class ModuleDependencyInfo { const ArrayRef getHeaderInputSourceFiles() const { if (auto *detail = getAsSwiftInterfaceModule()) return detail->textualModuleDetails.bridgingSourceFiles; - else if (auto *detail = getAsSwiftSourceModule()) + if (auto *detail = getAsSwiftSourceModule()) return detail->textualModuleDetails.bridgingSourceFiles; - else if (auto *detail = getAsSwiftBinaryModule()) + if (auto *detail = getAsSwiftBinaryModule()) return detail->headerSourceFiles; return {}; } @@ -726,9 +726,9 @@ class ModuleDependencyInfo { const ArrayRef getHeaderDependencies() const { if (auto *detail = getAsSwiftInterfaceModule()) return detail->textualModuleDetails.bridgingModuleDependencies; - else if (auto *detail = getAsSwiftSourceModule()) + if (auto *detail = getAsSwiftSourceModule()) return detail->textualModuleDetails.bridgingModuleDependencies; - else if (auto *detail = getAsSwiftBinaryModule()) + if (auto *detail = getAsSwiftBinaryModule()) return detail->headerModuleDependencies; return {}; } @@ -736,9 +736,9 @@ class ModuleDependencyInfo { std::vector getCommandline() const { if (auto *detail = getAsClangModule()) return detail->buildCommandLine; - else if (auto *detail = getAsSwiftInterfaceModule()) + if (auto *detail = getAsSwiftInterfaceModule()) return detail->textualModuleDetails.buildCommandLine; - else if (auto *detail = getAsSwiftSourceModule()) + if (auto *detail = getAsSwiftSourceModule()) return detail->textualModuleDetails.buildCommandLine; return {}; } @@ -747,10 +747,10 @@ class ModuleDependencyInfo { if (isSwiftInterfaceModule()) return cast(storage.get()) ->updateCommandLine(newCommandLine); - else if (isSwiftSourceModule()) + if (isSwiftSourceModule()) return cast(storage.get()) ->updateCommandLine(newCommandLine); - else if (isClangModule()) + if (isClangModule()) return cast(storage.get()) ->updateCommandLine(newCommandLine); llvm_unreachable("Unexpected type"); diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index be2b0146e0caf..5d43d084bf476 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -178,76 +178,243 @@ static void removeMacroSearchPaths(std::vector &cmd) { } } -static llvm::Expected -updateModuleCacheKey(ModuleDependencyInfo &depInfo, - ModuleDependenciesCache &cache, - llvm::cas::ObjectStore &CAS) { - auto commandLine = depInfo.getCommandline(); - std::vector Args; - if (commandLine.size() > 1) - for (auto &c : ArrayRef(commandLine).drop_front(1)) - Args.push_back(c.c_str()); - - auto base = createCompileJobBaseCacheKey(CAS, Args); - if (!base) - return base.takeError(); - - std::string InputPath; - if (auto *dep = depInfo.getAsClangModule()) - InputPath = dep->moduleMapFile; - else if (auto *dep = depInfo.getAsSwiftInterfaceModule()) - InputPath = dep->swiftInterfaceFile; - else - llvm_unreachable("Unhandled dependency kind"); +class ExplicitModuleDependencyResolver { +public: + ExplicitModuleDependencyResolver(ModuleDependencyID moduleID, + ModuleDependenciesCache &cache, + CompilerInstance &instance) + : moduleID(moduleID), cache(cache), instance(instance), + resolvingDepInfo(cache.findKnownDependency(moduleID)) { + tracker = cache.getScanService().createSwiftDependencyTracker(); + // Copy commandline. + commandline = resolvingDepInfo.getCommandline(); + } - if (cache.getScanService().hasPathMapping()) - InputPath = cache.getScanService().remapPath(InputPath); + llvm::Error + resolve(const std::set &dependencies, + std::optional> bridgingHeaderDeps) { + // No need to resolve dependency for placeholder. + if (moduleID.Kind == ModuleDependencyKind::SwiftPlaceholder) + return llvm::Error::success(); - // Module compilation commands always have only one input and the input - // index is always 0. - auto key = createCompileJobCacheKeyForOutput(CAS, *base, /*InputIndex=*/0); - if (!key) - return key.takeError(); + // If the dependency is already finalized, nothing needs to be done. + if (resolvingDepInfo.isFinalized()) + return llvm::Error::success(); - depInfo.updateModuleCacheKey(CAS.getID(*key).toString()); - return *key; -} + if (auto ID = resolvingDepInfo.getClangIncludeTree()) + includeTrees.push_back(*ID); + + for (const auto &depModuleID : dependencies) { + const auto &depInfo = cache.findKnownDependency(depModuleID); + switch (depModuleID.Kind) { + case swift::ModuleDependencyKind::SwiftInterface: { + auto interfaceDepDetails = depInfo.getAsSwiftInterfaceModule(); + assert(interfaceDepDetails && "Expected Swift Interface dependency."); + if (auto err = handleSwiftInterfaceModuleDependency( + depModuleID, *interfaceDepDetails)) + return err; + } break; + case swift::ModuleDependencyKind::SwiftBinary: { + auto binaryDepDetails = depInfo.getAsSwiftBinaryModule(); + assert(binaryDepDetails && "Expected Swift Binary Module dependency."); + if (auto err = handleSwiftBinaryModuleDependency(depModuleID, + *binaryDepDetails)) + return err; + } break; + case swift::ModuleDependencyKind::SwiftPlaceholder: { + auto placeholderDetails = depInfo.getAsPlaceholderDependencyModule(); + assert(placeholderDetails && "Expected Swift Placeholder dependency."); + if (auto err = handleSwiftPlaceholderModuleDependency( + depModuleID, *placeholderDetails)) + return err; + } break; + case swift::ModuleDependencyKind::Clang: { + auto clangDepDetails = depInfo.getAsClangModule(); + assert(clangDepDetails && "Expected Clang Module dependency."); + if (auto err = + handleClangModuleDependency(depModuleID, *clangDepDetails)) + return err; + } break; + case swift::ModuleDependencyKind::SwiftSource: { + auto sourceDepDetails = depInfo.getAsSwiftSourceModule(); + assert(sourceDepDetails && "Expected Swift Source Module dependency."); + if (auto err = handleSwiftSourceModuleDependency(depModuleID, + *sourceDepDetails)) + return err; + } break; + default: + llvm_unreachable("Unhandled dependency kind."); + } + } -static llvm::Error resolveExplicitModuleInputs( - ModuleDependencyID moduleID, - const std::set &dependencies, - ModuleDependenciesCache &cache, CompilerInstance &instance, - std::optional> bridgingHeaderDeps) { - // Only need to resolve dependency for following dependencies. - if (moduleID.Kind == ModuleDependencyKind::SwiftPlaceholder) + // Update bridging header build command if there is a bridging header + // dependency. + if (auto E = addBridgingHeaderDeps(resolvingDepInfo)) + return E; + if (bridgingHeaderDeps) { + bridgingHeaderBuildCmd = + resolvingDepInfo.getBridgingHeaderCommandline(); + for (auto bridgingDep : *bridgingHeaderDeps) { + auto &dep = cache.findKnownDependency(bridgingDep); + auto *clangDep = dep.getAsClangModule(); + assert(clangDep && "wrong module dependency kind"); + if (!clangDep->moduleCacheKey.empty()) { + bridgingHeaderBuildCmd.push_back("-Xcc"); + bridgingHeaderBuildCmd.push_back("-fmodule-file-cache-key"); + bridgingHeaderBuildCmd.push_back("-Xcc"); + bridgingHeaderBuildCmd.push_back(clangDep->mappedPCMPath); + bridgingHeaderBuildCmd.push_back("-Xcc"); + bridgingHeaderBuildCmd.push_back(clangDep->moduleCacheKey); + } + } + } + + pruneUnusedVFSOverlay(); + + // Update the dependency in the cache with the modified command-line. + if (resolvingDepInfo.isSwiftInterfaceModule() || + resolvingDepInfo.isClangModule()) { + if (cache.getScanService().hasPathMapping()) + commandline = + remapPathsFromCommandLine(commandline, [&](StringRef path) { + return cache.getScanService().remapPath(path); + }); + } + + auto dependencyInfoCopy = resolvingDepInfo; + if (auto err = finalize(dependencyInfoCopy)) + return err; + + dependencyInfoCopy.setIsFinalized(true); + cache.updateDependency(moduleID, dependencyInfoCopy); return llvm::Error::success(); + } + +private: + // Finalize the resolving dependency info. + llvm::Error finalize(ModuleDependencyInfo &depInfo) { + if (resolvingDepInfo.isSwiftPlaceholderModule()) + return llvm::Error::success(); + + // Add macros. + for (auto ¯o : macros) + depInfo.addMacroDependency( + macro.first(), macro.second.LibraryPath, macro.second.ExecutablePath); + + // Update CAS dependencies. + if (auto err = collectCASDependencies(depInfo)) + return err; + + if (!bridgingHeaderBuildCmd.empty()) + depInfo.updateBridgingHeaderCommandLine( + bridgingHeaderBuildCmd); + if (!resolvingDepInfo.isSwiftBinaryModule()) { + depInfo.updateCommandLine(commandline); + if (auto err = updateModuleCacheKey(depInfo)) + return err; + } - auto &resolvingDepInfo = cache.findKnownDependency(moduleID); - // If the dependency is already finalized, nothing needs to be done. - if (resolvingDepInfo.isFinalized()) return llvm::Error::success(); + } - auto &service = cache.getScanService(); - auto remapPath = [&](StringRef path) { return service.remapPath(path); }; - std::vector rootIDs; - std::vector includeTrees; - if (auto ID = resolvingDepInfo.getClangIncludeTree()) - includeTrees.push_back(*ID); + llvm::Error handleSwiftInterfaceModuleDependency( + ModuleDependencyID depModuleID, + const SwiftInterfaceModuleDependenciesStorage &interfaceDepDetails) { + auto &path = interfaceDepDetails.moduleCacheKey.empty() + ? interfaceDepDetails.moduleOutputPath + : interfaceDepDetails.moduleCacheKey; + commandline.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" + + path); + addMacroDependencies(depModuleID, interfaceDepDetails); + return llvm::Error::success(); + } + + llvm::Error handleSwiftBinaryModuleDependency( + ModuleDependencyID depModuleID, + const SwiftBinaryModuleDependencyStorage &binaryDepDetails) { + auto &path = binaryDepDetails.moduleCacheKey.empty() + ? binaryDepDetails.compiledModulePath + : binaryDepDetails.moduleCacheKey; + commandline.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" + + path); + // If this binary module was built with a header, the header's module + // dependencies must also specify a .modulemap to the compilation, in + // order to resolve the header's own header include directives. + for (const auto &bridgingHeaderDepName : + binaryDepDetails.headerModuleDependencies) { + auto optionalBridgingHeaderDepModuleInfo = cache.findKnownDependency( + {bridgingHeaderDepName, ModuleDependencyKind::Clang}); + const auto bridgingHeaderDepModuleDetails = + optionalBridgingHeaderDepModuleInfo.getAsClangModule(); + commandline.push_back("-Xcc"); + commandline.push_back("-fmodule-map-file=" + + cache.getScanService().remapPath( + bridgingHeaderDepModuleDetails->moduleMapFile)); + } + addMacroDependencies(depModuleID, binaryDepDetails); + return llvm::Error::success(); + } + + llvm::Error handleSwiftPlaceholderModuleDependency( + ModuleDependencyID depModuleID, + const SwiftPlaceholderModuleDependencyStorage &placeholderDetails) { + commandline.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" + + placeholderDetails.compiledModulePath); + return llvm::Error::success(); + } + + llvm::Error handleClangModuleDependency( + ModuleDependencyID depModuleID, + const ClangModuleDependencyStorage &clangDepDetails) { + if (!resolvingDepInfo.isClangModule()) { + commandline.push_back("-Xcc"); + commandline.push_back("-fmodule-file=" + depModuleID.ModuleName + "=" + + clangDepDetails.mappedPCMPath); + } + if (!clangDepDetails.moduleCacheKey.empty()) { + commandline.push_back("-Xcc"); + commandline.push_back("-fmodule-file-cache-key"); + commandline.push_back("-Xcc"); + commandline.push_back(clangDepDetails.mappedPCMPath); + commandline.push_back("-Xcc"); + commandline.push_back(clangDepDetails.moduleCacheKey); + } + + // Collect CAS deppendencies from clang modules. + if (!clangDepDetails.CASFileSystemRootID.empty()) + rootIDs.push_back(clangDepDetails.CASFileSystemRootID); + if (!clangDepDetails.CASClangIncludeTreeRootID.empty()) + includeTrees.push_back(clangDepDetails.CASClangIncludeTreeRootID); + + collectUsedVFSOverlay(clangDepDetails); - auto tracker = cache.getScanService().createSwiftDependencyTracker(); - auto addBridgingHeaderDeps = - [&](const ModuleDependencyInfo &depInfo) -> llvm::Error { + return llvm::Error::success(); + } + + llvm::Error handleSwiftSourceModuleDependency( + ModuleDependencyID depModuleID, + const SwiftSourceModuleDependenciesStorage &sourceDepDetails) { + addMacroDependencies(depModuleID, sourceDepDetails); + return addBridgingHeaderDeps(sourceDepDetails); + } + + llvm::Error addBridgingHeaderDeps(const ModuleDependencyInfo &depInfo) { auto sourceDepDetails = depInfo.getAsSwiftSourceModule(); if (!sourceDepDetails) return llvm::Error::success(); - if (sourceDepDetails->textualModuleDetails - .CASBridgingHeaderIncludeTreeRootID.empty()) { - if (!sourceDepDetails->textualModuleDetails.bridgingSourceFiles.empty()) { + return addBridgingHeaderDeps(*sourceDepDetails); + } + + llvm::Error addBridgingHeaderDeps( + const SwiftSourceModuleDependenciesStorage &sourceDepDetails) { + if (sourceDepDetails.textualModuleDetails.CASBridgingHeaderIncludeTreeRootID + .empty()) { + if (!sourceDepDetails.textualModuleDetails.bridgingSourceFiles.empty()) { if (tracker) { tracker->startTracking(); for (auto &file : - sourceDepDetails->textualModuleDetails.bridgingSourceFiles) + sourceDepDetails.textualModuleDetails.bridgingSourceFiles) tracker->trackFile(file); auto bridgeRoot = tracker->createTreeFromDependencies(); if (!bridgeRoot) @@ -256,133 +423,84 @@ static llvm::Error resolveExplicitModuleInputs( } } } else - includeTrees.push_back(sourceDepDetails->textualModuleDetails + includeTrees.push_back(sourceDepDetails.textualModuleDetails .CASBridgingHeaderIncludeTreeRootID); return llvm::Error::success(); }; - if (auto E = addBridgingHeaderDeps(resolvingDepInfo)) - return E; - std::vector commandLine = resolvingDepInfo.getCommandline(); - auto dependencyInfoCopy = resolvingDepInfo; - auto &directDeps = resolvingDepInfo.getDirectModuleDependencies(); - - // Helper to the macro dependencies from direct module dependencies. - auto addMacroDependencies = [&](ModuleDependencyID moduleID, - const ModuleDependencyInfo &dep) { + void addMacroDependencies(ModuleDependencyID moduleID, + const ModuleDependencyInfoStorageBase &dep) { + auto &directDeps = resolvingDepInfo.getDirectModuleDependencies(); if (llvm::find(directDeps, moduleID) == directDeps.end()) return; - for (auto &entry: dep.getMacroDependencies()) - dependencyInfoCopy.addMacroDependency( - entry.first, entry.second.LibraryPath, entry.second.ExecutablePath); + for (auto &entry : dep.macroDependencies) + macros.insert({entry.first, + {entry.second.LibraryPath, entry.second.ExecutablePath}}); + } + + static bool isVFSOverlayFlag(StringRef arg) { + return arg == "-ivfsoverlay" || arg == "-vfsoverlay"; }; + static bool isXCCArg(StringRef arg) { return arg == "-Xcc"; }; + + void + collectUsedVFSOverlay(const ClangModuleDependencyStorage &clangDepDetails) { + // true if the previous argument was the dash-option of an option pair + bool getNext = false; + for (const auto &A : clangDepDetails.buildCommandLine) { + StringRef arg(A); + if (isXCCArg(arg)) + continue; + if (getNext) { + getNext = false; + usedVFSOverlayPaths.insert(arg); + } else if (isVFSOverlayFlag(arg)) + getNext = true; + } + } - for (const auto &depModuleID : dependencies) { - const auto &depInfo = cache.findKnownDependency(depModuleID); - switch (depModuleID.Kind) { - case swift::ModuleDependencyKind::SwiftInterface: { - auto interfaceDepDetails = depInfo.getAsSwiftInterfaceModule(); - assert(interfaceDepDetails && "Expected Swift Interface dependency."); - auto &path = interfaceDepDetails->moduleCacheKey.empty() - ? interfaceDepDetails->moduleOutputPath - : interfaceDepDetails->moduleCacheKey; - commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" + - path); - addMacroDependencies(depModuleID, depInfo); - } break; - case swift::ModuleDependencyKind::SwiftBinary: { - auto binaryDepDetails = depInfo.getAsSwiftBinaryModule(); - assert(binaryDepDetails && "Expected Swift Binary Module dependency."); - auto &path = binaryDepDetails->moduleCacheKey.empty() - ? binaryDepDetails->compiledModulePath - : binaryDepDetails->moduleCacheKey; - commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" + - path); - // If this binary module was built with a header, the header's module - // dependencies must also specify a .modulemap to the compilation, in - // order to resolve the header's own header include directives. - for (const auto &bridgingHeaderDepName : - binaryDepDetails->headerModuleDependencies) { - auto optionalBridgingHeaderDepModuleInfo = cache.findKnownDependency( - {bridgingHeaderDepName, ModuleDependencyKind::Clang}); - const auto bridgingHeaderDepModuleDetails = - optionalBridgingHeaderDepModuleInfo.getAsClangModule(); - commandLine.push_back("-Xcc"); - commandLine.push_back( - "-fmodule-map-file=" + - remapPath(bridgingHeaderDepModuleDetails->moduleMapFile)); - } - addMacroDependencies(depModuleID, depInfo); - } break; - case swift::ModuleDependencyKind::SwiftPlaceholder: { - auto placeholderDetails = depInfo.getAsPlaceholderDependencyModule(); - assert(placeholderDetails && "Expected Swift Placeholder dependency."); - commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" + - placeholderDetails->compiledModulePath); - } break; - case swift::ModuleDependencyKind::Clang: { - auto clangDepDetails = depInfo.getAsClangModule(); - assert(clangDepDetails && "Expected Clang Module dependency."); - if (!resolvingDepInfo.isClangModule()) { - commandLine.push_back("-Xcc"); - commandLine.push_back("-fmodule-file=" + depModuleID.ModuleName + "=" + - clangDepDetails->mappedPCMPath); + void pruneUnusedVFSOverlay() { + std::vector resolvedCommandLine; + size_t skip = 0; + for (auto it = commandline.begin(), end = commandline.end(); + it != end; it++) { + if (skip) { + skip--; + continue; } - if (!clangDepDetails->moduleCacheKey.empty()) { - commandLine.push_back("-Xcc"); - commandLine.push_back("-fmodule-file-cache-key"); - commandLine.push_back("-Xcc"); - commandLine.push_back(clangDepDetails->mappedPCMPath); - commandLine.push_back("-Xcc"); - commandLine.push_back(clangDepDetails->moduleCacheKey); + // If this VFS overlay was not used across any of the dependencies, skip + // it. + if ((it + 1) != end && isXCCArg(*it) && isVFSOverlayFlag(*(it + 1))) { + assert(it + 2 != end); // Extra -Xcc + assert(it + 3 != end); // Actual VFS overlay path argument + if (!usedVFSOverlayPaths.contains(*(it + 3))) { + skip = 3; + continue; + } } - - // Only need to merge the CASFS from clang importer. - if (auto ID = depInfo.getCASFSRootID()) - rootIDs.push_back(*ID); - if (auto ID = depInfo.getClangIncludeTree()) - includeTrees.push_back(*ID); - } break; - case swift::ModuleDependencyKind::SwiftSource: { - if (auto E = addBridgingHeaderDeps(depInfo)) - return E; - break; + resolvedCommandLine.push_back(*it); } - default: - llvm_unreachable("Unhandled dependency kind."); - } - } - - // Update the dependency in the cache with the modified command-line. - if (resolvingDepInfo.isSwiftInterfaceModule() || - resolvingDepInfo.isClangModule()) { - if (service.hasPathMapping()) - commandLine = remapPathsFromCommandLine(commandLine, remapPath); - dependencyInfoCopy.updateCommandLine(commandLine); + commandline = std::move(resolvedCommandLine); } - // Handle CAS options. - if (instance.getInvocation().getCASOptions().EnableCaching) { - // Merge CASFS from clang dependency. - auto &CASFS = cache.getScanService().getSharedCachingFS(); - auto &CAS = CASFS.getCAS(); + llvm::Error collectCASDependencies(ModuleDependencyInfo &dependencyInfoCopy) { + if (!instance.getInvocation().getCASOptions().EnableCaching) + return llvm::Error::success(); - assert(tracker && "no caching tracker is available"); - // Compute the CASFS root ID for the resolving dependency. + // Collect CAS info from current resolving module. if (auto *sourceDep = resolvingDepInfo.getAsSwiftSourceModule()) { tracker->startTracking(); tracker->addCommonSearchPathDeps(instance.getInvocation()); llvm::for_each( sourceDep->sourceFiles, - [&tracker](const std::string &file) { tracker->trackFile(file); }); + [this](const std::string &file) { tracker->trackFile(file); }); llvm::for_each( sourceDep->auxiliaryFiles, - [&tracker](const std::string &file) { tracker->trackFile(file); }); - llvm::for_each(sourceDep->macroDependencies, - [&tracker](const auto &entry) { - tracker->trackFile(entry.second.LibraryPath); - }); + [this](const std::string &file) { tracker->trackFile(file); }); + llvm::for_each(sourceDep->macroDependencies, [this](const auto &entry) { + tracker->trackFile(entry.second.LibraryPath); + }); auto root = tracker->createTreeFromDependencies(); if (!root) return root.takeError(); @@ -396,9 +514,9 @@ static llvm::Error resolveExplicitModuleInputs( tracker->trackFile(textualDep->swiftInterfaceFile); llvm::for_each( textualDep->auxiliaryFiles, - [&tracker](const std::string &file) { tracker->trackFile(file); }); + [this](const std::string &file) { tracker->trackFile(file); }); llvm::for_each(textualDep->macroDependencies, - [&tracker](const auto &entry) { + [this](const auto &entry) { tracker->trackFile(entry.second.LibraryPath); }); auto root = tracker->createTreeFromDependencies(); @@ -412,174 +530,102 @@ static llvm::Error resolveExplicitModuleInputs( // Update build command line. if (resolvingDepInfo.isSwiftInterfaceModule() || resolvingDepInfo.isSwiftSourceModule()) { - std::vector newCommandLine = - dependencyInfoCopy.getCommandline(); - // If there are no external macro dependencies, drop all plugin search // paths. - if (dependencyInfoCopy.getMacroDependencies().empty()) - removeMacroSearchPaths(newCommandLine); + if (resolvingDepInfo.getMacroDependencies().empty() && macros.empty()) + removeMacroSearchPaths(commandline); // Update with casfs option. for (auto rootID : rootIDs) { - newCommandLine.push_back("-cas-fs"); - newCommandLine.push_back(rootID); + commandline.push_back("-cas-fs"); + commandline.push_back(rootID); } for (auto tree : includeTrees) { - newCommandLine.push_back("-clang-include-tree-root"); - newCommandLine.push_back(tree); + commandline.push_back("-clang-include-tree-root"); + commandline.push_back(tree); } - - dependencyInfoCopy.updateCommandLine(newCommandLine); - } - - if (bridgingHeaderDeps) { - std::vector newCommandLine = - dependencyInfoCopy.getBridgingHeaderCommandline(); - for (auto bridgingDep : *bridgingHeaderDeps) { - auto &dep = cache.findKnownDependency(bridgingDep); - auto *clangDep = dep.getAsClangModule(); - assert(clangDep && "wrong module dependency kind"); - if (!clangDep->moduleCacheKey.empty()) { - newCommandLine.push_back("-Xcc"); - newCommandLine.push_back("-fmodule-file-cache-key"); - newCommandLine.push_back("-Xcc"); - newCommandLine.push_back(clangDep->mappedPCMPath); - newCommandLine.push_back("-Xcc"); - newCommandLine.push_back(clangDep->moduleCacheKey); - } - } - dependencyInfoCopy.updateBridgingHeaderCommandLine(newCommandLine); } // Compute and update module cache key. - auto setupBinaryCacheKey = [&](StringRef path) -> llvm::Error { - // For binary module, we need to make sure the lookup key is setup here in - // action cache. We just use the CASID of the binary module itself as key. - auto Ref = CASFS.getObjectRefForFileContent(path); - if (!Ref) - return llvm::errorCodeToError(Ref.getError()); - assert(*Ref && "Binary module should be loaded into CASFS already"); - dependencyInfoCopy.updateModuleCacheKey(CAS.getID(**Ref).toString()); - - swift::cas::CompileJobCacheResult::Builder Builder; - Builder.addOutput(file_types::ID::TY_SwiftModuleFile, **Ref); - auto Result = Builder.build(CAS); - if (!Result) - return Result.takeError(); - if (auto E = instance.getActionCache().put(CAS.getID(**Ref), - CAS.getID(*Result))) - return E; - return llvm::Error::success(); - }; - - if (resolvingDepInfo.isClangModule() || - resolvingDepInfo.isSwiftInterfaceModule()) { - auto Key = updateModuleCacheKey(dependencyInfoCopy, cache, CAS); - if (!Key) - return Key.takeError(); - } else if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) { - if (auto E = setupBinaryCacheKey(binaryDep->compiledModulePath)) + if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) { + if (auto E = setupBinaryCacheKey(binaryDep->compiledModulePath, + dependencyInfoCopy)) return E; } + return llvm::Error::success(); } - dependencyInfoCopy.setIsFinalized(true); - cache.updateDependency(moduleID, dependencyInfoCopy); + llvm::Error updateModuleCacheKey(ModuleDependencyInfo &depInfo) { + if (!instance.getInvocation().getCASOptions().EnableCaching) + return llvm::Error::success(); - return llvm::Error::success(); -} + auto &CAS = cache.getScanService().getSharedCachingFS().getCAS(); + auto commandLine = depInfo.getCommandline(); + std::vector Args; + if (commandLine.size() > 1) + for (auto &c : ArrayRef(commandLine).drop_front(1)) + Args.push_back(c.c_str()); -static llvm::Error -pruneUnusedVFSOverlays(ModuleDependencyID moduleID, - const std::set &dependencies, - ModuleDependenciesCache &cache, - CompilerInstance &instance) { - // Pruning of unused VFS overlay options for Clang dependencies - // is performed by the Clang dependency scanner. - if (moduleID.Kind == ModuleDependencyKind::Clang) - return llvm::Error::success(); + auto base = createCompileJobBaseCacheKey(CAS, Args); + if (!base) + return base.takeError(); - auto isVFSOverlayFlag = [](StringRef arg) { - return arg == "-ivfsoverlay" || arg == "-vfsoverlay"; - }; - auto isXCCArg = [](StringRef arg) { - return arg == "-Xcc"; - }; + // Module compilation commands always have only one input and the input + // index is always 0. + auto key = createCompileJobCacheKeyForOutput(CAS, *base, /*InputIndex=*/0); + if (!key) + return key.takeError(); - auto &resolvingDepInfo = cache.findKnownDependency(moduleID); - // If this Swift dependency contains any VFS overlay paths, - // then attempt to prune the ones not used by any of the Clang dependencies. - if (!llvm::any_of(resolvingDepInfo.getCommandline(), - [&isVFSOverlayFlag](const std::string &arg) { - return isVFSOverlayFlag(arg); - })) + depInfo.updateModuleCacheKey(CAS.getID(*key).toString()); return llvm::Error::success(); - - // 1. For each Clang dependency, gather its ivfsoverlay path arguments - // to keep track of which overlays are actually used and were not - // pruned by the Clang dependency scanner. - llvm::StringSet<> usedVFSOverlayPaths; - for (const auto &depModuleID : dependencies) { - const auto &depInfo = cache.findKnownDependency(depModuleID); - if (auto clangDepDetails = depInfo.getAsClangModule()) { - const auto &depCommandLine = clangDepDetails->buildCommandLine; - // true if the previous argument was the dash-option of an option pair - bool getNext = false; - for (const auto &A : depCommandLine) { - StringRef arg(A); - if (isXCCArg(arg)) - continue; - if (getNext) { - getNext = false; - usedVFSOverlayPaths.insert(arg); - } else if (isVFSOverlayFlag(arg)) - getNext = true; - } - } } - // 2. Each -Xcc VFS overlay path on the resolving command-line which is not used by - // any of the Clang dependencies can be removed from the command-line. - const std::vector ¤tCommandLine = - resolvingDepInfo.getCommandline(); - std::vector resolvedCommandLine; - size_t skip = 0; - for (auto it = currentCommandLine.begin(), end = currentCommandLine.end(); - it != end; it++) { - if (skip) { - skip--; - continue; - } - // If this VFS overlay was not used across any of the dependencies, skip it. - if ((it+1) != end && isXCCArg(*it) && isVFSOverlayFlag(*(it + 1))) { - assert(it + 2 != end); // Extra -Xcc - assert(it + 3 != end); // Actual VFS overlay path argument - if (!usedVFSOverlayPaths.contains(*(it + 3))) { - skip = 3; - continue; - } - } - resolvedCommandLine.push_back(*it); + llvm::Error setupBinaryCacheKey(StringRef path, + ModuleDependencyInfo &depInfo) { + auto &CASFS = cache.getScanService().getSharedCachingFS(); + auto &CAS = CASFS.getCAS(); + // For binary module, we need to make sure the lookup key is setup here in + // action cache. We just use the CASID of the binary module itself as key. + auto Ref = CASFS.getObjectRefForFileContent(path); + if (!Ref) + return llvm::errorCodeToError(Ref.getError()); + assert(*Ref && "Binary module should be loaded into CASFS already"); + depInfo.updateModuleCacheKey(CAS.getID(**Ref).toString()); + + swift::cas::CompileJobCacheResult::Builder Builder; + Builder.addOutput(file_types::ID::TY_SwiftModuleFile, **Ref); + auto Result = Builder.build(CAS); + if (!Result) + return Result.takeError(); + if (auto E = + instance.getActionCache().put(CAS.getID(**Ref), CAS.getID(*Result))) + return E; + return llvm::Error::success(); } - // 3. Update the dependency in the cache if the command-line has been modified. - if (currentCommandLine.size() != resolvedCommandLine.size()) { - auto dependencyInfoCopy = resolvingDepInfo; - dependencyInfoCopy.updateCommandLine(resolvedCommandLine); - - // Update the CAS cache key for the new command-line - if (instance.getInvocation().getCASOptions().EnableCaching) { - auto &CAS = cache.getScanService().getSharedCachingFS().getCAS(); - auto Key = updateModuleCacheKey(dependencyInfoCopy, cache, CAS); - if (!Key) - return Key.takeError(); - } - cache.updateDependency(moduleID, dependencyInfoCopy); - } +private: + ModuleDependencyID moduleID; + ModuleDependenciesCache &cache; + CompilerInstance &instance; + const ModuleDependencyInfo &resolvingDepInfo; - return llvm::Error::success(); + std::optional tracker; + std::vector rootIDs; + std::vector includeTrees; + std::vector commandline; + std::vector bridgingHeaderBuildCmd; + llvm::StringMap macros; + llvm::StringSet<> usedVFSOverlayPaths; +}; + +static llvm::Error resolveExplicitModuleInputs( + ModuleDependencyID moduleID, + const std::set &dependencies, + ModuleDependenciesCache &cache, CompilerInstance &instance, + std::optional> bridgingHeaderDeps) { + ExplicitModuleDependencyResolver resolver(moduleID, cache, instance); + return resolver.resolve(dependencies, bridgingHeaderDeps); } static bool writePrescanJSONToOutput(DiagnosticEngine &diags, @@ -1406,11 +1452,6 @@ static void resolveDependencyCommandLineArguments( instance, bridgingHeaderDeps)) instance.getDiags().diagnose(SourceLoc(), diag::error_cas, toString(std::move(E))); - - if (auto E = - pruneUnusedVFSOverlays(modID, dependencyClosure, cache, instance)) - instance.getDiags().diagnose(SourceLoc(), diag::error_cas, - toString(std::move(E))); } }