Skip to content

Commit cf8187a

Browse files
[ScanDependency] Pass crossimport overlay file to swift-frontend
Teach dependency scanner to pass cross import overlay file to swift-frontend for main module compilation. This allows swift-frontend not to repeat the file system search for overlay files when loading modules. This also fixes the issue when caching is enabled, the cross import doesn't work when the first module is a clang module because the module built with caching using clang include tree does not preserve DefinitionLoc which is used to inferred the modulemap location for cross import overlay search. rdar://127844120
1 parent 35cda47 commit cf8187a

File tree

9 files changed

+118
-25
lines changed

9 files changed

+118
-25
lines changed

include/swift/AST/ModuleDependencies.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -812,8 +812,9 @@ class ModuleDependencyInfo {
812812
/// Collect a map from a secondary module name to a list of cross-import
813813
/// overlays, when this current module serves as the primary module.
814814
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>>
815-
collectCrossImportOverlayNames(ASTContext &ctx, StringRef moduleName,
816-
std::vector<std::string> &overlayFiles) const;
815+
collectCrossImportOverlayNames(
816+
ASTContext &ctx, StringRef moduleName,
817+
std::vector<std::pair<std::string, std::string>> &overlayFiles) const;
817818
};
818819

819820
using ModuleDependencyVector = llvm::SmallVector<std::pair<ModuleDependencyID, ModuleDependencyInfo>, 1>;

include/swift/AST/SearchPathOptions.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,14 @@ class SearchPathOptions {
504504
/// version inheritance.
505505
std::optional<std::string> PlatformAvailabilityInheritanceMapPath;
506506

507+
/// Cross import module information. Map from module name to the list of cross
508+
/// import overlay files that associate with that module.
509+
using CrossImportMap = llvm::StringMap<std::vector<std::string>>;
510+
CrossImportMap CrossImportInfo;
511+
512+
/// Whether to search for cross import overlay on file system.
513+
bool DisableCrossImportOverlaySearch = false;
514+
507515
/// Debug path mappings to apply to serialized search paths. These are
508516
/// specified in LLDB from the target.source-map entries.
509517
PathRemapper SearchPathRemapper;

include/swift/Option/FrontendOptions.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ def swift_module_file: Joined<["-"], "swift-module-file=">,
220220
MetaVarName<"<name>=<path>">,
221221
HelpText<"Specify Swift module input explicitly built from textual interface">;
222222

223+
def swift_module_cross_import: MultiArg<["-"], "swift-module-cross-import", 2>,
224+
MetaVarName<"<moduleName> <crossImport.swiftoverlay>">,
225+
HelpText<"Specify the cross import module">;
226+
227+
def disable_cross_import_overlay_search: Flag<["-"], "disable-cross-import-overlay-search">,
228+
HelpText<"Disable searching for cross import overlay file">;
229+
223230
def explicit_swift_module_map
224231
: Separate<["-"], "explicit-swift-module-map-file">, MetaVarName<"<path>">,
225232
HelpText<"Specify a JSON file containing information of explicit Swift modules">;

lib/AST/ModuleLoader.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,19 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
171171
using namespace llvm::sys;
172172
using namespace file_types;
173173

174+
// If cross import information is passed on command-line, prefer use that.
175+
auto &crossImports = module->getASTContext().SearchPathOpts.CrossImportInfo;
176+
auto overlays = crossImports.find(module->getNameStr());
177+
if (overlays != crossImports.end()) {
178+
for (auto entry : overlays->second) {
179+
module->addCrossImportOverlayFile(entry);
180+
if (dependencyTracker)
181+
dependencyTracker->addDependency(entry, module->isSystemModule());
182+
}
183+
}
184+
if (module->getASTContext().SearchPathOpts.DisableCrossImportOverlaySearch)
185+
return;
186+
174187
if (file->getModuleDefiningPath().empty())
175188
return;
176189
findOverlayFilesInternal(module->getASTContext(),
@@ -188,7 +201,7 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
188201
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>>
189202
ModuleDependencyInfo::collectCrossImportOverlayNames(
190203
ASTContext &ctx, StringRef moduleName,
191-
std::vector<std::string> &overlayFiles) const {
204+
std::vector<std::pair<std::string, std::string>> &overlayFiles) const {
192205
using namespace llvm::sys;
193206
using namespace file_types;
194207
std::optional<std::string> modulePath;
@@ -240,7 +253,7 @@ ModuleDependencyInfo::collectCrossImportOverlayNames(
240253
ModuleDecl::collectCrossImportOverlay(ctx, file, moduleName,
241254
bystandingModule);
242255
result[bystandingModule] = std::move(overlayNames);
243-
overlayFiles.push_back(file.str());
256+
overlayFiles.push_back({moduleName.str(), file.str()});
244257
});
245258
return result;
246259
}

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ void ModuleDependencyScanner::discoverCrossImportOverlayDependencies(
800800
llvm::function_ref<void(ModuleDependencyID)> action) {
801801
// Modules explicitly imported. Only these can be secondary module.
802802
llvm::SetVector<Identifier> newOverlays;
803-
std::vector<std::string> overlayFiles;
803+
std::vector<std::pair<std::string, std::string>> overlayFiles;
804804
for (auto dep : allDependencies) {
805805
auto moduleName = dep.ModuleName;
806806
// Do not look for overlays of main module under scan
@@ -887,9 +887,15 @@ void ModuleDependencyScanner::discoverCrossImportOverlayDependencies(
887887
mainDep.addModuleDependency(crossImportOverlayModID);
888888
});
889889

890-
llvm::for_each(overlayFiles, [&mainDep](const std::string &file) {
891-
mainDep.addAuxiliaryFile(file);
892-
});
890+
auto cmdCopy = mainDep.getCommandline();
891+
cmdCopy.push_back("-disable-cross-import-overlay-search");
892+
for (auto &entry : overlayFiles) {
893+
mainDep.addAuxiliaryFile(entry.second);
894+
cmdCopy.push_back("-swift-module-cross-import");
895+
cmdCopy.push_back(entry.first);
896+
cmdCopy.push_back(entry.second);
897+
}
898+
mainDep.updateCommandLine(cmdCopy);
893899

894900
cache.updateDependency(
895901
{mainModuleName.str(), ModuleDependencyKind::SwiftSource}, mainDep);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,12 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args,
20682068
*forceModuleLoadingMode);
20692069
}
20702070

2071+
for (auto *A : Args.filtered(OPT_swift_module_cross_import))
2072+
Opts.CrossImportInfo[A->getValue(0)].push_back(A->getValue(1));
2073+
2074+
Opts.DisableCrossImportOverlaySearch |=
2075+
Args.hasArg(OPT_disable_cross_import_overlay_search);
2076+
20712077
// Opts.RuntimeIncludePath is set by calls to
20722078
// setRuntimeIncludePath() or setMainExecutablePath().
20732079
// Opts.RuntimeImportPath is set by calls to

test/CAS/cross_import.swift

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,38 @@
55
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
66
// RUN: -emit-module-interface-path %t/A.swiftinterface -enable-library-evolution -I %t %t/A.swift
77

8-
// RUN: %target-swift-frontend -emit-module -module-name B -o %t/A.swiftmodule -swift-version 5 \
8+
// RUN: %target-swift-frontend -emit-module -module-name B -o %t/B.swiftmodule -swift-version 5 \
99
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
1010
// RUN: -emit-module-interface-path %t/B.swiftinterface -enable-library-evolution -I %t %t/B.swift
1111

12-
// RUN: %target-swift-frontend -emit-module -module-name _Cross -o %t/A.swiftmodule -swift-version 5 \
12+
// RUN: %target-swift-frontend -emit-module -module-name _B_A -o %t/_B_A.swiftmodule -swift-version 5 \
1313
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
14-
// RUN: -emit-module-interface-path %t/_Cross.swiftinterface -enable-library-evolution -I %t %t/cross.swift
14+
// RUN: -emit-module-interface-path %t/_B_A.swiftinterface -enable-library-evolution -I %t %t/b_a.swift
1515

16-
// RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache %t/main.swift \
16+
// RUN: %target-swift-frontend -emit-module -module-name _C_A -o %t/_C_A.swiftmodule -swift-version 5 \
1717
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
18-
// 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
18+
// RUN: -emit-module-interface-path %t/_C_A.swiftinterface -enable-library-evolution -I %t %t/c_a.swift
1919

20-
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json A > %t/A.cmd
21-
// RUN: %swift_frontend_plain @%t/A.cmd
22-
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json B > %t/B.cmd
23-
// RUN: %swift_frontend_plain @%t/B.cmd
24-
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json _Cross > %t/Cross.cmd
25-
// RUN: %swift_frontend_plain @%t/Cross.cmd
20+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache %t/main.swift -F %t \
21+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -O \
22+
// 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
2623

27-
// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json
24+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/shim.cmd
25+
// RUN: %swift_frontend_plain @%t/shim.cmd
26+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:C > %t/C.cmd
27+
// RUN: %swift_frontend_plain @%t/C.cmd
28+
29+
// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json %t > %t/map.json
2830
// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid
2931

3032
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Test > %t/MyApp.cmd
33+
// RUN: %FileCheck %s --input-file=%t/MyApp.cmd --check-prefix CMD
34+
// CMD: -swift-module-cross-import
35+
// CMD-NEXT: B
36+
// CMD-NEXT: A.swiftoverlay
37+
// CMD-NEXT: -swift-module-cross-import
38+
// CMD-NEXT: C
39+
// CMD-NEXT: A.swiftoverlay
3140

3241
// RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule \
3342
// RUN: -emit-module-interface-path %t/Test.swiftinterface \
@@ -40,28 +49,50 @@
4049
// RUN: %FileCheck %s --input-file=%t/Test.swiftinterface
4150

4251
/// Check to make sure the implicit cross import turned into explicit import in the interface file.
43-
// CHECK: import _Cross
52+
// CHECK: import _B_A
53+
// CHECK: import _C_A
4454

4555
//--- A.swift
4656
public func a() {}
4757

4858
//--- B.swift
4959
public func b() {}
5060

51-
//--- cross.swift
52-
public func cross() {}
61+
//--- b_a.swift
62+
public func b_a() {}
63+
64+
//--- c_a.swift
65+
public func c_a() {}
66+
67+
//--- C.framework/Modules/module.modulemap
68+
framework module C {
69+
umbrella header "C.h"
70+
export *
71+
}
72+
73+
//--- C.framework/Headers/C.h
74+
void c(void);
75+
76+
//--- C.framework/Modules/C.swiftcrossimport/A.swiftoverlay
77+
%YAML 1.2
78+
---
79+
version: 1
80+
modules:
81+
- name: _C_A
5382

5483
//--- main.swift
5584
import A
5685
import B
86+
import C
5787

5888
func test () {
59-
cross()
89+
b_a()
90+
c_a()
6091
}
6192

6293
//--- B.swiftcrossimport/A.swiftoverlay
6394
%YAML 1.2
6495
---
6596
version: 1
6697
modules:
67-
- name: _Cross
98+
- name: _B_A
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// This file tests that the -Rcross-import option causes an appropriate remark to be emitted
2+
// RUN: %empty-directory(%t)
3+
// RUN: cp -r %S/Inputs/lib-templates/* %t/
4+
// 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
5+
// 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 \
6+
// RUN: | %FileCheck %s -check-prefix NO-IMPORT -allow-empty
7+
// 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 \
8+
// RUN: -swift-module-cross-import DeclaringLibrary %t/lib/swift/DeclaringLibrary.swiftcrossimport/BystandingLibrary.swiftoverlay | %FileCheck %s -check-prefix IMPORT
9+
10+
import DeclaringLibrary
11+
import BystandingLibrary
12+
13+
// IMPORT: import of 'DeclaringLibrary' and 'BystandingLibrary' triggered a cross-import of '_OverlayLibrary'
14+
// NO-IMPORT-NOT: import of 'DeclaringLibrary' and 'BystandingLibrary' triggered a cross-import of '_OverlayLibrary'

test/ScanDependencies/module_deps_cross_import_overlay.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,12 @@ import SubEWrapper
3030
// CHECK-NOT: "clang": "X"
3131
// CHECK: ],
3232

33+
// CHECK: "swift": {
34+
// CHECK-NEXT: "commandLine": [
35+
// CHECK-NEXT: "-disable-cross-import-overlay-search",
36+
// CHECK-NEXT: "-swift-module-cross-import",
37+
// CHECK-NEXT: "E",
38+
// CHECK-NEXT: SubE.swiftoverlay
39+
3340
// Ensure a transitive dependency via "_cross_import_E" is recorded in the graph still
3441
// CHECK: "clang": "X"

0 commit comments

Comments
 (0)