From 90a1bb812bea606b36f9612c96bc013a1cd041d5 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 9 Jun 2023 08:39:28 -0700 Subject: [PATCH 1/3] [Dependency Scanning] Do not treat modules as their own dependencies --- lib/DependencyScan/ScanDependencies.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index a3a09efb75b30..b1246ae133573 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -254,6 +254,10 @@ computeTransitiveClosureOfExplicitDependencies( llvm::set_union(modReachableSet, succReachableSet); } } + // For ease of use down-the-line, remove the node's self from its set of reachable nodes + for (const auto &modID : topologicallySortedModuleList) + result[modID].erase(modID); + return result; } From b974d97879760611e376f284b8f510bd0a18a29d Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Fri, 9 Jun 2023 13:50:07 -0700 Subject: [PATCH 2/3] [Dependency Scanning] Record header dependencies of Binary Swift module dependencies These are meant to capture paths to the PCH files that a given module was built with. --- include/swift/AST/ModuleDependencies.h | 37 +++++++++----- .../SerializedModuleDependencyCacheFormat.h | 1 + .../Serialization/SerializedModuleLoader.h | 23 +++++---- .../ModuleDependencyCacheSerialization.cpp | 23 ++++++--- lib/Serialization/ModuleDependencyScanner.cpp | 15 +++--- lib/Serialization/SerializedModuleLoader.cpp | 49 +++++++++++++------ 6 files changed, 97 insertions(+), 51 deletions(-) diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 98dbc1de8fda6..dde8b9ef26984 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -106,10 +106,15 @@ class ModuleDependencyInfoStorageBase { const ModuleDependencyKind dependencyKind; ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind, - StringRef moduleCacheKey = "", - bool resolved = false) + StringRef moduleCacheKey = "") : dependencyKind(dependencyKind), moduleCacheKey(moduleCacheKey.str()), - resolved(resolved) {} + resolved(false) { } + + ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind, + const std::vector &moduleImports, + StringRef moduleCacheKey = "") + : dependencyKind(dependencyKind), moduleImports(moduleImports), + moduleCacheKey(moduleCacheKey.str()), resolved(false) {} virtual ModuleDependencyInfoStorageBase *clone() const = 0; @@ -282,12 +287,15 @@ class SwiftBinaryModuleDependencyStorage : public ModuleDependencyInfoStorageBas SwiftBinaryModuleDependencyStorage(const std::string &compiledModulePath, const std::string &moduleDocPath, const std::string &sourceInfoPath, + const std::vector &moduleImports, + const std::vector &headerImports, const bool isFramework, const std::string &moduleCacheKey) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary, - moduleCacheKey), + moduleImports, moduleCacheKey), compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), - sourceInfoPath(sourceInfoPath), isFramework(isFramework) {} + sourceInfoPath(sourceInfoPath), preCompiledBridgingHeaderPaths(headerImports), + isFramework(isFramework) {} ModuleDependencyInfoStorageBase *clone() const override { return new SwiftBinaryModuleDependencyStorage(*this); @@ -302,6 +310,9 @@ class SwiftBinaryModuleDependencyStorage : public ModuleDependencyInfoStorageBas /// The path to the .swiftSourceInfo file. const std::string sourceInfoPath; + /// The paths of all the .pch dependencies of this module. + const std::vector preCompiledBridgingHeaderPaths; + /// A flag that indicates this dependency is a framework const bool isFramework; @@ -447,15 +458,17 @@ class ModuleDependencyInfo { } /// Describe the module dependencies for a serialized or parsed Swift module. - static ModuleDependencyInfo - forSwiftBinaryModule(const std::string &compiledModulePath, - const std::string &moduleDocPath, - const std::string &sourceInfoPath, bool isFramework, - const std::string &moduleCacheKey) { + static ModuleDependencyInfo forSwiftBinaryModule( + const std::string &compiledModulePath, + const std::string &moduleDocPath, + const std::string &sourceInfoPath, + const std::vector &moduleImports, + const std::vector &headerImports, + bool isFramework, const std::string &moduleCacheKey) { return ModuleDependencyInfo( std::make_unique( - compiledModulePath, moduleDocPath, sourceInfoPath, isFramework, - moduleCacheKey)); + compiledModulePath, moduleDocPath, sourceInfoPath, + moduleImports, headerImports, isFramework, moduleCacheKey)); } /// Describe the main Swift module. diff --git a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h index 3e9f4eeb4ca15..b702b07d79739 100644 --- a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h +++ b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h @@ -165,6 +165,7 @@ using SwiftBinaryModuleDetailsLayout = FileIDField, // compiledModulePath FileIDField, // moduleDocPath FileIDField, // moduleSourceInfoPath + ImportArrayIDField, // headerImports IsFrameworkField, // isFramework IdentifierIDField // moduleCacheKey >; diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index b13b2fb177798..085deabdda8c4 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -150,15 +150,20 @@ class SerializedModuleLoaderBase : public ModuleLoader { /// Scan the given serialized module file to determine dependencies. llvm::ErrorOr scanModuleFile(Twine modulePath, bool isFramework); - static llvm::ErrorOr> - getModuleImportsOfModule(Twine modulePath, - ModuleLoadingBehavior transitiveBehavior, - bool isFramework, - bool isRequiredOSSAModules, - StringRef SDKName, - StringRef packageName, - llvm::vfs::FileSystem *fileSystem, - PathObfuscator &recoverer); + struct BinaryModuleImports { + llvm::StringSet<> moduleImports; + llvm::StringSet<> headerImports; + }; + + static llvm::ErrorOr + getImportsOfModule(Twine modulePath, + ModuleLoadingBehavior transitiveBehavior, + bool isFramework, + bool isRequiredOSSAModules, + StringRef SDKName, + StringRef packageName, + llvm::vfs::FileSystem *fileSystem, + PathObfuscator &recoverer); /// Load the module file into a buffer and also collect its module name. static std::unique_ptr diff --git a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp index 184f356ef78c4..e8c786323e5c7 100644 --- a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp +++ b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp @@ -462,10 +462,11 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi "Unexpected SWIFT_BINARY_MODULE_DETAILS_NODE record"); cache.configureForContextHash(getContextHash()); unsigned compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID, - isFramework, moduleCacheKeyID; + headerImportsArrayID, isFramework, moduleCacheKeyID; SwiftBinaryModuleDetailsLayout::readRecord( Scratch, compiledModulePathID, moduleDocPathID, - moduleSourceInfoPathID, isFramework, moduleCacheKeyID); + moduleSourceInfoPathID, headerImportsArrayID, isFramework, + moduleCacheKeyID); auto compiledModulePath = getIdentifier(compiledModulePathID); if (!compiledModulePath) @@ -477,16 +478,18 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi if (!moduleSourceInfoPath) llvm::report_fatal_error("Bad module source info path"); auto moduleCacheKey = getIdentifier(moduleCacheKeyID); - if (!moduleCacheKeyID) + if (!moduleCacheKey) llvm::report_fatal_error("Bad moduleCacheKey"); + auto headerImports = getStringArray(headerImportsArrayID); + if (!headerImports) + llvm::report_fatal_error("Bad binary direct dependencies: no header imports"); + // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftBinaryModule( - *compiledModulePath, *moduleDocPath, *moduleSourceInfoPath, - isFramework, *moduleCacheKey); - // Add dependencies of this module - for (const auto &moduleName : *currentModuleImports) - moduleDep.addModuleImport(moduleName); + *compiledModulePath, *moduleDocPath, *moduleSourceInfoPath, + *currentModuleImports, *headerImports, isFramework, + *moduleCacheKey); cache.recordDependency(currentModuleName, std::move(moduleDep), getContextHash()); @@ -704,6 +707,7 @@ bool swift::dependencies::module_dependency_cache_serialization:: enum ModuleIdentifierArrayKind : uint8_t { Empty = 0, DependencyImports, + DependencyHeaders, QualifiedModuleDependencyIDs, CompiledModuleCandidates, BuildCommandLine, @@ -975,6 +979,7 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(ModuleDependencyID modul getIdentifier(swiftBinDeps->compiledModulePath), getIdentifier(swiftBinDeps->moduleDocPath), getIdentifier(swiftBinDeps->sourceInfoPath), + getArrayID(moduleID, ModuleIdentifierArrayKind::DependencyHeaders), swiftBinDeps->isFramework, getIdentifier(swiftBinDeps->moduleCacheKey)); @@ -1152,6 +1157,8 @@ void ModuleDependenciesCacheSerializer::collectStringsAndArrays( addIdentifier(swiftBinDeps->moduleDocPath); addIdentifier(swiftBinDeps->sourceInfoPath); addIdentifier(swiftBinDeps->moduleCacheKey); + addStringArray(moduleID, ModuleIdentifierArrayKind::DependencyHeaders, + swiftBinDeps->preCompiledBridgingHeaderPaths); break; } case swift::ModuleDependencyKind::SwiftPlaceholder: { diff --git a/lib/Serialization/ModuleDependencyScanner.cpp b/lib/Serialization/ModuleDependencyScanner.cpp index ecac3a5160d83..335cfd1e185b4 100644 --- a/lib/Serialization/ModuleDependencyScanner.cpp +++ b/lib/Serialization/ModuleDependencyScanner.cpp @@ -208,38 +208,41 @@ ErrorOr ModuleDependencyScanner::scanInterfaceFile( }); if (adjacentBinaryModule != compiledCandidates.end()) { // Required modules. - auto adjacentBinaryModuleRequiredImports = getModuleImportsOfModule( + auto adjacentBinaryModuleRequiredImports = getImportsOfModule( *adjacentBinaryModule, ModuleLoadingBehavior::Required, isFramework, isRequiredOSSAModules(), Ctx.LangOpts.SDKName, Ctx.LangOpts.PackageName, Ctx.SourceMgr.getFileSystem().get(), Ctx.SearchPathOpts.DeserializedPathRecoverer); if (!adjacentBinaryModuleRequiredImports) return adjacentBinaryModuleRequiredImports.getError(); - + auto adjacentBinaryModuleRequiredModuleImports = + (*adjacentBinaryModuleRequiredImports).moduleImports; #ifndef NDEBUG // Verify that the set of required modules read out from the binary // module is a super-set of module imports identified in the // textual interface. for (const auto &requiredImport : Result->getModuleImports()) { - assert(adjacentBinaryModuleRequiredImports->contains(requiredImport) && + assert(adjacentBinaryModuleRequiredModuleImports.contains(requiredImport) && "Expected adjacent binary module's import set to contain all " "textual interface imports."); } #endif - for (const auto &requiredImport : *adjacentBinaryModuleRequiredImports) + for (const auto &requiredImport : adjacentBinaryModuleRequiredModuleImports) Result->addModuleImport(requiredImport.getKey(), &alreadyAddedModules); // Optional modules. Will be looked-up on a best-effort basis - auto adjacentBinaryModuleOptionalImports = getModuleImportsOfModule( + auto adjacentBinaryModuleOptionalImports = getImportsOfModule( *adjacentBinaryModule, ModuleLoadingBehavior::Optional, isFramework, isRequiredOSSAModules(), Ctx.LangOpts.SDKName, Ctx.LangOpts.PackageName, Ctx.SourceMgr.getFileSystem().get(), Ctx.SearchPathOpts.DeserializedPathRecoverer); if (!adjacentBinaryModuleOptionalImports) return adjacentBinaryModuleOptionalImports.getError(); - for (const auto &optionalImport : *adjacentBinaryModuleOptionalImports) + auto adjacentBinaryModuleOptionalModuleImports = + (*adjacentBinaryModuleOptionalImports).moduleImports; + for (const auto &optionalImport : adjacentBinaryModuleOptionalModuleImports) Result->addOptionalModuleImport(optionalImport.getKey(), &alreadyAddedModules); } diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 8a55635f35f69..56327b501b71a 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -392,8 +392,8 @@ std::error_code SerializedModuleLoaderBase::openModuleFile( return std::error_code(); } -llvm::ErrorOr> -SerializedModuleLoaderBase::getModuleImportsOfModule( +llvm::ErrorOr +SerializedModuleLoaderBase::getImportsOfModule( Twine modulePath, ModuleLoadingBehavior transitiveBehavior, bool isFramework, bool isRequiredOSSAModules, StringRef SDKName, StringRef packageName, llvm::vfs::FileSystem *fileSystem, @@ -403,6 +403,7 @@ SerializedModuleLoaderBase::getModuleImportsOfModule( return moduleBuf.getError(); llvm::StringSet<> importedModuleNames; + llvm::StringSet<> importedHeaders; // Load the module file without validation. std::shared_ptr loadedModuleFile; serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load( @@ -410,9 +411,10 @@ SerializedModuleLoaderBase::getModuleImportsOfModule( isRequiredOSSAModules, SDKName, recoverer, loadedModuleFile); for (const auto &dependency : loadedModuleFile->getDependencies()) { - // FIXME: Record header dependency? - if (dependency.isHeader()) + if (dependency.isHeader()) { + importedHeaders.insert(dependency.RawPath); continue; + } ModuleLoadingBehavior dependencyTransitiveBehavior = loadedModuleFile->getTransitiveLoadingBehavior( @@ -433,17 +435,13 @@ SerializedModuleLoaderBase::getModuleImportsOfModule( importedModuleNames.insert(moduleName); } - return importedModuleNames; + return SerializedModuleLoaderBase::BinaryModuleImports{importedModuleNames, importedHeaders}; } llvm::ErrorOr SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework) { const std::string moduleDocPath; const std::string sourceInfoPath; - // Map the set of dependencies over to the "module dependencies". - auto dependencies = ModuleDependencyInfo::forSwiftBinaryModule( - modulePath.str(), moduleDocPath, sourceInfoPath, isFramework, - /*module-cache-key*/ ""); // Some transitive dependencies of binary modules are not required to be // imported during normal builds. // TODO: This is worth revisiting for debugger purposes where @@ -452,18 +450,37 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework) { // optional. ModuleLoadingBehavior transitiveLoadingBehavior = ModuleLoadingBehavior::Required; - auto importedModuleNames = getModuleImportsOfModule( + auto binaryModuleImports = getImportsOfModule( modulePath, transitiveLoadingBehavior, isFramework, isRequiredOSSAModules(), Ctx.LangOpts.SDKName, Ctx.LangOpts.PackageName, Ctx.SourceMgr.getFileSystem().get(), Ctx.SearchPathOpts.DeserializedPathRecoverer); - if (!importedModuleNames) - return importedModuleNames.getError(); + if (!binaryModuleImports) + return binaryModuleImports.getError(); + + auto importedModuleSet = binaryModuleImports.get().moduleImports; + std::vector importedModuleNames; + importedModuleNames.reserve(importedModuleSet.size()); + llvm::transform(importedModuleSet.keys(), + std::back_inserter(importedModuleNames), + [](llvm::StringRef N) { + return N.str(); + }); + + auto importedHeaderSet = binaryModuleImports.get().headerImports; + std::vector importedHeaders; + importedHeaders.reserve(importedHeaderSet.size()); + llvm::transform(importedHeaderSet.keys(), + std::back_inserter(importedHeaders), + [](llvm::StringRef N) { + return N.str(); + }); - llvm::StringSet<> addedModuleNames; - for (const auto &importedModuleName : *importedModuleNames) - dependencies.addModuleImport(importedModuleName.getKey(), - &addedModuleNames); + // Map the set of dependencies over to the "module dependencies". + auto dependencies = ModuleDependencyInfo::forSwiftBinaryModule( + modulePath.str(), moduleDocPath, sourceInfoPath, + importedModuleNames, importedHeaders, isFramework, + /*module-cache-key*/ ""); return std::move(dependencies); } From 92d9e61d1aaf532176db7aa0493513213a779d11 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Mon, 12 Jun 2023 10:35:00 -0400 Subject: [PATCH 3/3] [Dependency Scanning] Emit header dependencies of binary Swift module dependencies in output and provide libSwiftScan API to query it --- .../swift-c/DependencyScan/DependencyScan.h | 4 ++ .../swift/DependencyScan/DependencyScanImpl.h | 4 ++ .../swift/Frontend/ModuleInterfaceLoader.h | 56 +++++++++------ lib/DependencyScan/ScanDependencies.cpp | 14 ++++ lib/Frontend/ModuleInterfaceLoader.cpp | 4 +- .../Inputs/Swift/FooClient.swiftinterface | 5 ++ .../header_deps_of_binary.swift | 70 +++++++++++++++++++ tools/libSwiftScan/libSwiftScan.cpp | 6 ++ tools/libSwiftScan/libSwiftScan.exports | 1 + 9 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 test/ScanDependencies/Inputs/Swift/FooClient.swiftinterface create mode 100644 test/ScanDependencies/header_deps_of_binary.swift diff --git a/include/swift-c/DependencyScan/DependencyScan.h b/include/swift-c/DependencyScan/DependencyScan.h index 998c8309bf352..07d6b2217e841 100644 --- a/include/swift-c/DependencyScan/DependencyScan.h +++ b/include/swift-c/DependencyScan/DependencyScan.h @@ -180,6 +180,10 @@ SWIFTSCAN_PUBLIC swiftscan_string_ref_t swiftscan_swift_binary_detail_get_module_source_info_path( swiftscan_module_details_t details); +SWIFTSCAN_PUBLIC swiftscan_string_set_t * +swiftscan_swift_binary_detail_get_header_dependencies( + swiftscan_module_details_t details); + SWIFTSCAN_PUBLIC bool swiftscan_swift_binary_detail_get_is_framework( swiftscan_module_details_t details); diff --git a/include/swift/DependencyScan/DependencyScanImpl.h b/include/swift/DependencyScan/DependencyScanImpl.h index 92b3d45851a8a..a0ac5751d298f 100644 --- a/include/swift/DependencyScan/DependencyScanImpl.h +++ b/include/swift/DependencyScan/DependencyScanImpl.h @@ -121,6 +121,10 @@ typedef struct { /// The path to the .swiftSourceInfo file. swiftscan_string_ref_t module_source_info_path; + /// (Clang) header dependencies of this binary module. + /// Typically pre-compiled bridging header. + swiftscan_string_set_t *header_dependencies; + /// A flag to indicate whether or not this module is a framework. bool is_framework; diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 3c0d148ba62e0..4d61b939be13e 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -241,12 +241,14 @@ struct ExplicitSwiftModuleInputInfo { ExplicitSwiftModuleInputInfo(std::string modulePath, llvm::Optional moduleDocPath, llvm::Optional moduleSourceInfoPath, + llvm::Optional> headerDependencyPaths, bool isFramework = false, bool isSystem = false, llvm::Optional moduleCacheKey = None) : modulePath(modulePath), moduleDocPath(moduleDocPath), moduleSourceInfoPath(moduleSourceInfoPath), + headerDependencyPaths(headerDependencyPaths), isFramework(isFramework), isSystem(isSystem), moduleCacheKey(moduleCacheKey) {} @@ -256,6 +258,8 @@ struct ExplicitSwiftModuleInputInfo { llvm::Optional moduleDocPath; // Path of the .swiftsourceinfo file. llvm::Optional moduleSourceInfoPath; + // Paths of the precompiled header dependencies of this module. + llvm::Optional> headerDependencyPaths; // A flag that indicates whether this module is a framework bool isFramework = false; // A flag that indicates whether this module is a system module @@ -369,34 +373,39 @@ class ExplicitModuleMapParser { llvm::Optional swiftModulePath, swiftModuleDocPath, swiftModuleSourceInfoPath, swiftModuleCacheKey, clangModuleCacheKey; + llvm::Optional> headerDependencyPaths; std::string clangModuleMapPath = "", clangModulePath = ""; bool isFramework = false, isSystem = false; for (auto &entry : *mapNode) { auto key = getScalaNodeText(entry.getKey()); - auto val = getScalaNodeText(entry.getValue()); - if (key == "moduleName") { - moduleName = val; - } else if (key == "modulePath") { - swiftModulePath = val.str(); - } else if (key == "docPath") { - swiftModuleDocPath = val.str(); - } else if (key == "sourceInfoPath") { - swiftModuleSourceInfoPath = val.str(); - } else if (key == "isFramework") { - isFramework = parseBoolValue(val); - } else if (key == "isSystem") { - isSystem = parseBoolValue(val); - } else if (key == "clangModuleMapPath") { - clangModuleMapPath = val.str(); - } else if (key == "clangModulePath") { - clangModulePath = val.str(); - } else if (key == "moduleCacheKey") { - swiftModuleCacheKey = val.str(); - } else if (key == "clangModuleCacheKey") { - clangModuleCacheKey = val.str(); - } else { - // Being forgiving for future fields. + if (key == "prebuiltHeaderDependencyPaths") { continue; + } else { + auto val = getScalaNodeText(entry.getValue()); + if (key == "moduleName") { + moduleName = val; + } else if (key == "modulePath") { + swiftModulePath = val.str(); + } else if (key == "docPath") { + swiftModuleDocPath = val.str(); + } else if (key == "sourceInfoPath") { + swiftModuleSourceInfoPath = val.str(); + } else if (key == "isFramework") { + isFramework = parseBoolValue(val); + } else if (key == "isSystem") { + isSystem = parseBoolValue(val); + } else if (key == "clangModuleMapPath") { + clangModuleMapPath = val.str(); + } else if (key == "clangModulePath") { + clangModulePath = val.str(); + } else if (key == "moduleCacheKey") { + swiftModuleCacheKey = val.str(); + } else if (key == "clangModuleCacheKey") { + clangModuleCacheKey = val.str(); + } else { + // Being forgiving for future fields. + continue; + } } } if (moduleName.empty()) @@ -409,6 +418,7 @@ class ExplicitModuleMapParser { ExplicitSwiftModuleInputInfo entry(swiftModulePath.value(), swiftModuleDocPath, swiftModuleSourceInfoPath, + headerDependencyPaths, isFramework, isSystem, swiftModuleCacheKey); diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index b1246ae133573..396a965d1e4d1 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -334,6 +334,12 @@ static llvm::Error resolveExplicitModuleInputs( : binaryDepDetails->moduleCacheKey; commandLine.push_back("-swift-module-file=" + depModuleID.first + "=" + path); + for (const auto &headerDep : binaryDepDetails->preCompiledBridgingHeaderPaths) { + commandLine.push_back("-Xcc"); + commandLine.push_back("-include-pch"); + commandLine.push_back("-Xcc"); + commandLine.push_back(headerDep); + } } break; case swift::ModuleDependencyKind::SwiftPlaceholder: { auto placeholderDetails = depInfo->getAsPlaceholderDependencyModule(); @@ -1167,6 +1173,13 @@ static void writeJSON(llvm::raw_ostream &out, swiftBinaryDeps->module_cache_key, 5, /*trailingComma=*/true); } + + // Module Header Dependencies + if (swiftBinaryDeps->header_dependencies->count != 0) + writeJSONSingleField(out, "headerDependencies", + swiftBinaryDeps->header_dependencies, 5, + /*trailingComma=*/true); + writeJSONSingleField(out, "isFramework", swiftBinaryDeps->is_framework, 5, /*trailingComma=*/false); } else { @@ -1403,6 +1416,7 @@ generateFullDependencyGraph(CompilerInstance &instance, create_clone(swiftBinaryDeps->compiledModulePath.c_str()), create_clone(swiftBinaryDeps->moduleDocPath.c_str()), create_clone(swiftBinaryDeps->sourceInfoPath.c_str()), + create_set(swiftBinaryDeps->preCompiledBridgingHeaderPaths), swiftBinaryDeps->isFramework, create_clone(swiftBinaryDeps->moduleCacheKey.c_str())}; } else { diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index af9a42220d986..b12ac463d0efe 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -2004,7 +2004,7 @@ struct ExplicitSwiftModuleLoader::Implementation { const std::vector> &commandLineExplicitInputs) { for (const auto &moduleInput : commandLineExplicitInputs) { - ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}); + ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}, {}); ExplicitModuleMap.try_emplace(moduleInput.first, std::move(entry)); } } @@ -2270,7 +2270,7 @@ struct ExplicitCASModuleLoader::Implementation { const std::vector> &commandLineExplicitInputs) { for (const auto &moduleInput : commandLineExplicitInputs) { - ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}); + ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}, {}); ExplicitModuleMap.try_emplace(moduleInput.first, std::move(entry)); } } diff --git a/test/ScanDependencies/Inputs/Swift/FooClient.swiftinterface b/test/ScanDependencies/Inputs/Swift/FooClient.swiftinterface new file mode 100644 index 0000000000000..dbf1aa40270ea --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/FooClient.swiftinterface @@ -0,0 +1,5 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name FooClient +import Swift +import Foo +public func overlayFuncA() { } diff --git a/test/ScanDependencies/header_deps_of_binary.swift b/test/ScanDependencies/header_deps_of_binary.swift new file mode 100644 index 0000000000000..421840c21cce9 --- /dev/null +++ b/test/ScanDependencies/header_deps_of_binary.swift @@ -0,0 +1,70 @@ +// REQUIRES: objc_interop, OS=macosx +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/clang-module-cache) +// RUN: %empty-directory(%t/PCH) +// RUN: %empty-directory(%t/SwiftModules) + +// - Set up Foo Swift dependency +// RUN: echo "extension Profiler {" >> %t/foo.swift +// RUN: echo " public static let count: Int = 42" >> %t/foo.swift +// RUN: echo "}" >> %t/foo.swift + +// - Set up Foo bridging header +// RUN: echo "struct Profiler { void* ptr; };" >> %t/foo.h + +// - Compile bridging header +// RUN: %target-swift-frontend -enable-objc-interop -emit-pch %t/foo.h -o %t/PCH/foo.pch -disable-implicit-swift-modules + +// - Set up explicit dependencies for Foo +// RUN: %target-swift-emit-pcm -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/SwiftShims.pcm +// RUN: %target-swift-emit-pcm -module-name _SwiftConcurrencyShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/_SwiftConcurrencyShims.pcm +// RUN: echo "[{" > %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"Swift\"," >> %t/foo_inputs_map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false" >> %t/foo_inputs_map.json +// RUN: echo "}," >> %t/foo_inputs_map.json +// RUN: echo "{" >> %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %t/foo_inputs_map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false" >> %t/foo_inputs_map.json +// RUN: echo "}," >> %t/foo_inputs_map.json +// RUN: echo "{" >> %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %t/foo_inputs_map.json +// RUN: echo "\"modulePath\": \"%/string_processing_module\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false" >> %t/foo_inputs_map.json +// RUN: echo "}," >> %t/foo_inputs_map.json +// RUN: echo "{" >> %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"SwiftShims\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false," >> %t/foo_inputs_map.json +// RUN: echo "\"clangModuleMapPath\": \"%swift-lib-dir/swift/shims/module.modulemap\"," >> %t/foo_inputs_map.json +// RUN: echo "\"clangModulePath\": \"%t/inputs/SwiftShims.pcm\"" >> %t/foo_inputs_map.json +// RUN: echo "}," >> %t/foo_inputs_map.json +// RUN: echo "{" >> %t/foo_inputs_map.json +// RUN: echo "\"moduleName\": \"_SwiftConcurrencyShims\"," >> %t/foo_inputs_map.json +// RUN: echo "\"isFramework\": false," >> %t/foo_inputs_map.json +// RUN: echo "\"clangModuleMapPath\": \"%swift-lib-dir/swift/shims/module.modulemap\"," >> %t/foo_inputs_map.json +// RUN: echo "\"clangModulePath\": \"%t/inputs/_SwiftConcurrencyShims.pcm\"" >> %t/foo_inputs_map.json +// RUN: echo "}]" >> %t/foo_inputs_map.json + +// - Build Foo module dependency, explicitly +// RUN: %target-swift-frontend -emit-module -emit-module-path %t/SwiftModules/Foo.swiftmodule %t/foo.swift -module-name Foo -import-objc-header %t/PCH/foo.pch -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -disable-implicit-swift-modules -explicit-swift-module-map-file %t/foo_inputs_map.json + +// - Scan main module +// RUN: %target-swift-frontend -scan-dependencies %s -I %t/SwiftModules -I %S/Inputs/Swift -o %t/deps.json +// RUN: %FileCheck %s --input-file %t/deps.json + +// CHECK: "swift": "FooClient" +// CHECK: "swift": "FooClient" +// CHECK: "swiftPrebuiltExternal": "Foo" +// CHECK: "commandLine": [ +// CHECK: "-include-pch", +// CHECK-NEXT: "-Xcc", +// CHECK-NEXT: "{{.*}}{{/|\\}}PCH{{/|\\}}foo.pch" + + +// CHECK: "swiftPrebuiltExternal": "Foo" +// CHECK: "headerDependencies": [ +// CHECK: "{{.*}}{{/|\\}}PCH{{/|\\}}foo.pch" +// CHECK: ], + +import FooClient diff --git a/tools/libSwiftScan/libSwiftScan.cpp b/tools/libSwiftScan/libSwiftScan.cpp index 8e2e69e6c6820..1091ca4888d1e 100644 --- a/tools/libSwiftScan/libSwiftScan.cpp +++ b/tools/libSwiftScan/libSwiftScan.cpp @@ -344,6 +344,12 @@ swiftscan_swift_binary_detail_get_module_source_info_path( return details->swift_binary_details.module_source_info_path; } +swiftscan_string_set_t * +swiftscan_swift_binary_detail_get_header_dependencies( + swiftscan_module_details_t details) { + return details->swift_binary_details.header_dependencies; +} + bool swiftscan_swift_binary_detail_get_is_framework( swiftscan_module_details_t details) { return details->swift_binary_details.is_framework; diff --git a/tools/libSwiftScan/libSwiftScan.exports b/tools/libSwiftScan/libSwiftScan.exports index ff1d5337276fe..9e30dbb0aaa7a 100644 --- a/tools/libSwiftScan/libSwiftScan.exports +++ b/tools/libSwiftScan/libSwiftScan.exports @@ -22,6 +22,7 @@ swiftscan_swift_textual_detail_get_module_cache_key swiftscan_swift_binary_detail_get_compiled_module_path swiftscan_swift_binary_detail_get_module_doc_path swiftscan_swift_binary_detail_get_module_source_info_path +swiftscan_swift_binary_detail_get_header_dependencies swiftscan_swift_binary_detail_get_is_framework swiftscan_swift_binary_detail_get_module_cache_key swiftscan_swift_placeholder_detail_get_compiled_module_path