diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 64a7a2cfe99d6..97d705161dca3 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -812,8 +812,9 @@ class ModuleDependencyInfo { /// Collect a map from a secondary module name to a list of cross-import /// overlays, when this current module serves as the primary module. llvm::StringMap> - collectCrossImportOverlayNames(ASTContext &ctx, StringRef moduleName, - std::vector &overlayFiles) const; + collectCrossImportOverlayNames( + ASTContext &ctx, StringRef moduleName, + std::vector> &overlayFiles) const; }; using ModuleDependencyVector = llvm::SmallVector, 1>; diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index eb5081033ea02..c26a381b96bf1 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -504,6 +504,14 @@ class SearchPathOptions { /// version inheritance. std::optional PlatformAvailabilityInheritanceMapPath; + /// Cross import module information. Map from module name to the list of cross + /// import overlay files that associate with that module. + using CrossImportMap = llvm::StringMap>; + CrossImportMap CrossImportInfo; + + /// Whether to search for cross import overlay on file system. + bool DisableCrossImportOverlaySearch = false; + /// Debug path mappings to apply to serialized search paths. These are /// specified in LLDB from the target.source-map entries. PathRemapper SearchPathRemapper; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index bdd835be11d26..1ace6f7acfbfe 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -220,6 +220,13 @@ def swift_module_file: Joined<["-"], "swift-module-file=">, MetaVarName<"=">, HelpText<"Specify Swift module input explicitly built from textual interface">; +def swift_module_cross_import: MultiArg<["-"], "swift-module-cross-import", 2>, + MetaVarName<" ">, + HelpText<"Specify the cross import module">; + +def disable_cross_import_overlay_search: Flag<["-"], "disable-cross-import-overlay-search">, + HelpText<"Disable searching for cross import overlay file">; + def explicit_swift_module_map : Separate<["-"], "explicit-swift-module-map-file">, MetaVarName<"">, HelpText<"Specify a JSON file containing information of explicit Swift modules">; diff --git a/lib/AST/ModuleLoader.cpp b/lib/AST/ModuleLoader.cpp index f93cf8a8da843..8d7c2c0da15f3 100644 --- a/lib/AST/ModuleLoader.cpp +++ b/lib/AST/ModuleLoader.cpp @@ -171,6 +171,19 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module, using namespace llvm::sys; using namespace file_types; + // If cross import information is passed on command-line, prefer use that. + auto &crossImports = module->getASTContext().SearchPathOpts.CrossImportInfo; + auto overlays = crossImports.find(module->getNameStr()); + if (overlays != crossImports.end()) { + for (auto entry : overlays->second) { + module->addCrossImportOverlayFile(entry); + if (dependencyTracker) + dependencyTracker->addDependency(entry, module->isSystemModule()); + } + } + if (module->getASTContext().SearchPathOpts.DisableCrossImportOverlaySearch) + return; + if (file->getModuleDefiningPath().empty()) return; findOverlayFilesInternal(module->getASTContext(), @@ -188,7 +201,7 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module, llvm::StringMap> ModuleDependencyInfo::collectCrossImportOverlayNames( ASTContext &ctx, StringRef moduleName, - std::vector &overlayFiles) const { + std::vector> &overlayFiles) const { using namespace llvm::sys; using namespace file_types; std::optional modulePath; @@ -240,7 +253,7 @@ ModuleDependencyInfo::collectCrossImportOverlayNames( ModuleDecl::collectCrossImportOverlay(ctx, file, moduleName, bystandingModule); result[bystandingModule] = std::move(overlayNames); - overlayFiles.push_back(file.str()); + overlayFiles.push_back({moduleName.str(), file.str()}); }); return result; } diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index b75ea0393f19f..657ae695d6ac9 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -789,7 +789,7 @@ void ModuleDependencyScanner::discoverCrossImportOverlayDependencies( llvm::function_ref action) { // Modules explicitly imported. Only these can be secondary module. llvm::SetVector newOverlays; - std::vector overlayFiles; + std::vector> overlayFiles; for (auto dep : allDependencies) { auto moduleName = dep.ModuleName; // Do not look for overlays of main module under scan @@ -876,9 +876,15 @@ void ModuleDependencyScanner::discoverCrossImportOverlayDependencies( mainDep.addModuleDependency(crossImportOverlayModID); }); - llvm::for_each(overlayFiles, [&mainDep](const std::string &file) { - mainDep.addAuxiliaryFile(file); - }); + auto cmdCopy = mainDep.getCommandline(); + cmdCopy.push_back("-disable-cross-import-overlay-search"); + for (auto &entry : overlayFiles) { + mainDep.addAuxiliaryFile(entry.second); + cmdCopy.push_back("-swift-module-cross-import"); + cmdCopy.push_back(entry.first); + cmdCopy.push_back(entry.second); + } + mainDep.updateCommandLine(cmdCopy); cache.updateDependency( {mainModuleName.str(), ModuleDependencyKind::SwiftSource}, mainDep); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f15f0525f3015..558dbd2a0abbf 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2096,6 +2096,12 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args, *forceModuleLoadingMode); } + for (auto *A : Args.filtered(OPT_swift_module_cross_import)) + Opts.CrossImportInfo[A->getValue(0)].push_back(A->getValue(1)); + + Opts.DisableCrossImportOverlaySearch |= + Args.hasArg(OPT_disable_cross_import_overlay_search); + // Opts.RuntimeIncludePath is set by calls to // setRuntimeIncludePath() or setMainExecutablePath(). // Opts.RuntimeImportPath is set by calls to diff --git a/test/CAS/cross_import.swift b/test/CAS/cross_import.swift index 9abba2673f00a..2df2575dc6b49 100644 --- a/test/CAS/cross_import.swift +++ b/test/CAS/cross_import.swift @@ -5,29 +5,38 @@ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ // RUN: -emit-module-interface-path %t/A.swiftinterface -enable-library-evolution -I %t %t/A.swift -// RUN: %target-swift-frontend -emit-module -module-name B -o %t/A.swiftmodule -swift-version 5 \ +// RUN: %target-swift-frontend -emit-module -module-name B -o %t/B.swiftmodule -swift-version 5 \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ // RUN: -emit-module-interface-path %t/B.swiftinterface -enable-library-evolution -I %t %t/B.swift -// RUN: %target-swift-frontend -emit-module -module-name _Cross -o %t/A.swiftmodule -swift-version 5 \ +// RUN: %target-swift-frontend -emit-module -module-name _B_A -o %t/_B_A.swiftmodule -swift-version 5 \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ -// RUN: -emit-module-interface-path %t/_Cross.swiftinterface -enable-library-evolution -I %t %t/cross.swift +// RUN: -emit-module-interface-path %t/_B_A.swiftinterface -enable-library-evolution -I %t %t/b_a.swift -// RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache %t/main.swift \ +// RUN: %target-swift-frontend -emit-module -module-name _C_A -o %t/_C_A.swiftmodule -swift-version 5 \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ -// RUN: -o %t/deps.json -I %t -cache-compile-job -cas-path %t/cas -swift-version 5 -enable-cross-import-overlays -module-load-mode prefer-interface +// RUN: -emit-module-interface-path %t/_C_A.swiftinterface -enable-library-evolution -I %t %t/c_a.swift -// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json A > %t/A.cmd -// RUN: %swift_frontend_plain @%t/A.cmd -// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json B > %t/B.cmd -// RUN: %swift_frontend_plain @%t/B.cmd -// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json _Cross > %t/Cross.cmd -// RUN: %swift_frontend_plain @%t/Cross.cmd +// RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache %t/main.swift -F %t \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -O \ +// RUN: -o %t/deps.json -I %t -cache-compile-job -cas-path %t/cas -swift-version 5 -enable-cross-import-overlays -module-load-mode prefer-serialized -// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json +// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/shim.cmd +// RUN: %swift_frontend_plain @%t/shim.cmd +// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:C > %t/C.cmd +// RUN: %swift_frontend_plain @%t/C.cmd + +// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json %t > %t/map.json // RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid // RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Test > %t/MyApp.cmd +// RUN: %FileCheck %s --input-file=%t/MyApp.cmd --check-prefix CMD +// CMD: -swift-module-cross-import +// CMD-NEXT: B +// CMD-NEXT: A.swiftoverlay +// CMD-NEXT: -swift-module-cross-import +// CMD-NEXT: C +// CMD-NEXT: A.swiftoverlay // RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule \ // RUN: -emit-module-interface-path %t/Test.swiftinterface \ @@ -40,7 +49,8 @@ // RUN: %FileCheck %s --input-file=%t/Test.swiftinterface /// Check to make sure the implicit cross import turned into explicit import in the interface file. -// CHECK: import _Cross +// CHECK: import _B_A +// CHECK: import _C_A //--- A.swift public func a() {} @@ -48,15 +58,36 @@ public func a() {} //--- B.swift public func b() {} -//--- cross.swift -public func cross() {} +//--- b_a.swift +public func b_a() {} + +//--- c_a.swift +public func c_a() {} + +//--- C.framework/Modules/module.modulemap +framework module C { + umbrella header "C.h" + export * +} + +//--- C.framework/Headers/C.h +void c(void); + +//--- C.framework/Modules/C.swiftcrossimport/A.swiftoverlay +%YAML 1.2 +--- +version: 1 +modules: + - name: _C_A //--- main.swift import A import B +import C func test () { - cross() + b_a() + c_a() } //--- B.swiftcrossimport/A.swiftoverlay @@ -64,4 +95,4 @@ func test () { --- version: 1 modules: - - name: _Cross + - name: _B_A diff --git a/test/CrossImport/explicit-overlay-file.swift b/test/CrossImport/explicit-overlay-file.swift new file mode 100644 index 0000000000000..fa3aee4bd23c6 --- /dev/null +++ b/test/CrossImport/explicit-overlay-file.swift @@ -0,0 +1,14 @@ +// This file tests that the -Rcross-import option causes an appropriate remark to be emitted +// RUN: %empty-directory(%t) +// RUN: cp -r %S/Inputs/lib-templates/* %t/ +// RUN: %target-swift-frontend -typecheck %s -enable-cross-import-overlays -Rcross-import -I %t/include -I %t/lib/swift -F %t/Frameworks 2>&1 | %FileCheck %s -check-prefix IMPORT +// RUN: %target-swift-frontend -typecheck %s -disable-cross-import-overlay-search -enable-cross-import-overlays -Rcross-import -I %t/include -I %t/lib/swift -F %t/Frameworks 2>&1 \ +// RUN: | %FileCheck %s -check-prefix NO-IMPORT -allow-empty +// RUN: %target-swift-frontend -typecheck %s -disable-cross-import-overlay-search -enable-cross-import-overlays -Rcross-import -I %t/include -I %t/lib/swift -F %t/Frameworks 2>&1 \ +// RUN: -swift-module-cross-import DeclaringLibrary %t/lib/swift/DeclaringLibrary.swiftcrossimport/BystandingLibrary.swiftoverlay | %FileCheck %s -check-prefix IMPORT + +import DeclaringLibrary +import BystandingLibrary + +// IMPORT: import of 'DeclaringLibrary' and 'BystandingLibrary' triggered a cross-import of '_OverlayLibrary' +// NO-IMPORT-NOT: import of 'DeclaringLibrary' and 'BystandingLibrary' triggered a cross-import of '_OverlayLibrary' diff --git a/test/ScanDependencies/module_deps_cross_import_overlay.swift b/test/ScanDependencies/module_deps_cross_import_overlay.swift index c5a663ca9a551..ef20394517fc0 100644 --- a/test/ScanDependencies/module_deps_cross_import_overlay.swift +++ b/test/ScanDependencies/module_deps_cross_import_overlay.swift @@ -30,5 +30,12 @@ import SubEWrapper // CHECK-NOT: "clang": "X" // CHECK: ], +// CHECK: "swift": { +// CHECK-NEXT: "commandLine": [ +// CHECK-NEXT: "-disable-cross-import-overlay-search", +// CHECK-NEXT: "-swift-module-cross-import", +// CHECK-NEXT: "E", +// CHECK-NEXT: SubE.swiftoverlay + // Ensure a transitive dependency via "_cross_import_E" is recorded in the graph still // CHECK: "clang": "X"