Skip to content

Commit 07994da

Browse files
authored
Merge pull request #72743 from artemcm/60EBMChanges
[6.0🍒][Explicit Module Builds] Cherry-pick Explicit Module Loading fixes and improvements
2 parents 0e350d8 + 500c7ac commit 07994da

File tree

14 files changed

+232
-22
lines changed

14 files changed

+232
-22
lines changed

include/swift-c/DependencyScan/DependencyScan.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
/// SWIFTSCAN_VERSION_MINOR should increase when there are API additions.
2626
/// SWIFTSCAN_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
2727
#define SWIFTSCAN_VERSION_MAJOR 0
28-
#define SWIFTSCAN_VERSION_MINOR 7
28+
#define SWIFTSCAN_VERSION_MINOR 8
2929

3030
SWIFTSCAN_BEGIN_DECLS
3131

@@ -206,6 +206,10 @@ SWIFTSCAN_PUBLIC swiftscan_string_ref_t
206206
swiftscan_swift_binary_detail_get_header_dependency(
207207
swiftscan_module_details_t details);
208208

209+
SWIFTSCAN_PUBLIC swiftscan_string_set_t *
210+
swiftscan_swift_binary_detail_get_header_dependency_module_dependencies(
211+
swiftscan_module_details_t details);
212+
209213
SWIFTSCAN_PUBLIC bool
210214
swiftscan_swift_binary_detail_get_is_framework(
211215
swiftscan_module_details_t details);

include/swift/AST/SearchPathOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ class SearchPathOptions {
476476
std::vector<std::string> CandidateCompiledModules;
477477

478478
/// A map of explicit Swift module information.
479-
std::string ExplicitSwiftModuleMap;
479+
std::string ExplicitSwiftModuleMapPath;
480480

481481
/// Module inputs specified with -swift-module-input,
482482
/// <ModuleName, Path to .swiftmodule file>

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,11 @@ struct ExplicitClangModuleInputInfo {
269269
ExplicitClangModuleInputInfo(
270270
std::string moduleMapPath, std::string modulePath,
271271
bool isFramework = false, bool isSystem = false,
272+
bool isBridgingHeaderDependency = true,
272273
std::optional<std::string> moduleCacheKey = std::nullopt)
273274
: moduleMapPath(moduleMapPath), modulePath(modulePath),
274275
isFramework(isFramework), isSystem(isSystem),
276+
isBridgingHeaderDependency(isBridgingHeaderDependency),
275277
moduleCacheKey(moduleCacheKey) {}
276278
// Path of the Clang module map file.
277279
std::string moduleMapPath;
@@ -281,6 +283,8 @@ struct ExplicitClangModuleInputInfo {
281283
bool isFramework = false;
282284
// A flag that indicates whether this module is a system module
283285
bool isSystem = false;
286+
// A flag that indicates whether this is a module dependency of a textual header input
287+
bool isBridgingHeaderDependency = true;
284288
// The cache key for clang module.
285289
std::optional<std::string> moduleCacheKey;
286290
};
@@ -367,7 +371,12 @@ class ExplicitModuleMapParser {
367371
swiftModuleSourceInfoPath, swiftModuleCacheKey, clangModuleCacheKey;
368372
std::optional<std::vector<std::string>> headerDependencyPaths;
369373
std::string clangModuleMapPath = "", clangModulePath = "";
370-
bool isFramework = false, isSystem = false;
374+
bool isFramework = false, isSystem = false,
375+
// The default value is 'true' in case the build system does not yet
376+
// support emitting this field, in which case we must be conservative and
377+
// ensure all dependencies get '-fmodule-map-file', instead of strictly
378+
// module dependencies of textual header inputs.
379+
isBridgingHeaderDependency = true;
371380
for (auto &entry : *mapNode) {
372381
auto key = getScalaNodeText(entry.getKey());
373382
if (key == "prebuiltHeaderDependencyPaths") {
@@ -394,6 +403,8 @@ class ExplicitModuleMapParser {
394403
swiftModuleCacheKey = val.str();
395404
} else if (key == "clangModuleCacheKey") {
396405
clangModuleCacheKey = val.str();
406+
} else if (key == "isBridgingHeaderDependency") {
407+
isBridgingHeaderDependency = parseBoolValue(val);
397408
} else {
398409
// Being forgiving for future fields.
399410
continue;
@@ -423,6 +434,7 @@ class ExplicitModuleMapParser {
423434
clangModulePath,
424435
isFramework,
425436
isSystem,
437+
isBridgingHeaderDependency,
426438
clangModuleCacheKey);
427439
clangModuleMap.try_emplace(moduleName, std::move(entry));
428440
}

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,20 @@ static llvm::Error resolveExplicitModuleInputs(
264264
: binaryDepDetails->moduleCacheKey;
265265
commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" +
266266
path);
267+
// If this binary module was built with a header, the header's module
268+
// dependencies must also specify a .modulemap to the compilation, in
269+
// order to resolve the header's own header include directives.
270+
for (const auto &bridgingHeaderDepName :
271+
binaryDepDetails->headerModuleDependencies) {
272+
auto optionalBridgingHeaderDepModuleInfo = cache.findDependency(
273+
{bridgingHeaderDepName, ModuleDependencyKind::Clang});
274+
assert(optionalDepInfo.has_value());
275+
const auto bridgingHeaderDepModuleDetails =
276+
optionalBridgingHeaderDepModuleInfo.value()->getAsClangModule();
277+
commandLine.push_back(
278+
"-fmodule-map-file=" +
279+
remapPath(bridgingHeaderDepModuleDetails->moduleMapFile));
280+
}
267281
} break;
268282
case swift::ModuleDependencyKind::SwiftPlaceholder: {
269283
auto placeholderDetails = depInfo->getAsPlaceholderDependencyModule();
@@ -278,13 +292,6 @@ static llvm::Error resolveExplicitModuleInputs(
278292
commandLine.push_back("-Xcc");
279293
commandLine.push_back("-fmodule-file=" + depModuleID.ModuleName + "=" +
280294
clangDepDetails->mappedPCMPath);
281-
if (!instance.getInvocation()
282-
.getClangImporterOptions()
283-
.UseClangIncludeTree) {
284-
commandLine.push_back("-Xcc");
285-
commandLine.push_back("-fmodule-map-file=" +
286-
remapPath(clangDepDetails->moduleMapFile));
287-
}
288295
}
289296
if (!clangDepDetails->moduleCacheKey.empty()) {
290297
commandLine.push_back("-Xcc");
@@ -1471,7 +1478,8 @@ static bool diagnoseCycle(const CompilerInstance &instance,
14711478

14721479
auto kindIsSwiftDependency = [&](const ModuleDependencyID &ID) {
14731480
return ID.Kind == swift::ModuleDependencyKind::SwiftInterface ||
1474-
ID.Kind == swift::ModuleDependencyKind::SwiftBinary;
1481+
ID.Kind == swift::ModuleDependencyKind::SwiftBinary ||
1482+
ID.Kind == swift::ModuleDependencyKind::SwiftSource;
14751483
};
14761484

14771485
auto emitModulePath = [&](const std::vector<ModuleDependencyID> path,

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1982,7 +1982,7 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts,
19821982
Args.hasArg(OPT_disable_modules_validate_system_headers);
19831983

19841984
if (const Arg *A = Args.getLastArg(OPT_explicit_swift_module_map))
1985-
Opts.ExplicitSwiftModuleMap = A->getValue();
1985+
Opts.ExplicitSwiftModuleMapPath = A->getValue();
19861986
for (auto A : Args.getAllArgValues(options::OPT_swift_module_file)) {
19871987
if (validateSwiftModuleFileArgumentAndAdd(A, Diags,
19881988
Opts.ExplicitSwiftModuleInputs))

lib/Frontend/Frontend.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -745,18 +745,18 @@ bool CompilerInstance::setUpModuleLoaders() {
745745
bool ExplicitModuleBuild =
746746
Invocation.getFrontendOptions().DisableImplicitModules;
747747
if (ExplicitModuleBuild ||
748-
!Invocation.getSearchPathOptions().ExplicitSwiftModuleMap.empty() ||
748+
!Invocation.getSearchPathOptions().ExplicitSwiftModuleMapPath.empty() ||
749749
!Invocation.getSearchPathOptions().ExplicitSwiftModuleInputs.empty()) {
750750
if (Invocation.getCASOptions().EnableCaching)
751751
ESML = ExplicitCASModuleLoader::create(
752752
*Context, getObjectStore(), getActionCache(), getDependencyTracker(),
753-
MLM, Invocation.getSearchPathOptions().ExplicitSwiftModuleMap,
753+
MLM, Invocation.getSearchPathOptions().ExplicitSwiftModuleMapPath,
754754
Invocation.getSearchPathOptions().ExplicitSwiftModuleInputs,
755755
IgnoreSourceInfoFile);
756756
else
757757
ESML = ExplicitSwiftModuleLoader::create(
758758
*Context, getDependencyTracker(), MLM,
759-
Invocation.getSearchPathOptions().ExplicitSwiftModuleMap,
759+
Invocation.getSearchPathOptions().ExplicitSwiftModuleMapPath,
760760
Invocation.getSearchPathOptions().ExplicitSwiftModuleInputs,
761761
IgnoreSourceInfoFile);
762762
}

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,8 +1847,8 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl(
18471847
}
18481848

18491849
// Pass down -explicit-swift-module-map-file
1850-
StringRef explicitSwiftModuleMap = searchPathOpts.ExplicitSwiftModuleMap;
1851-
genericSubInvocation.getSearchPathOptions().ExplicitSwiftModuleMap =
1850+
StringRef explicitSwiftModuleMap = searchPathOpts.ExplicitSwiftModuleMapPath;
1851+
genericSubInvocation.getSearchPathOptions().ExplicitSwiftModuleMapPath =
18521852
explicitSwiftModuleMap.str();
18531853

18541854
// Pass down VFSOverlay flags (do not need to inherit the options because
@@ -2194,6 +2194,7 @@ struct ExplicitSwiftModuleLoader::Implementation {
21942194
for (auto &entry : ExplicitClangModuleMap) {
21952195
const auto &moduleMapPath = entry.getValue().moduleMapPath;
21962196
if (!moduleMapPath.empty() &&
2197+
entry.getValue().isBridgingHeaderDependency &&
21972198
moduleMapsSeen.find(moduleMapPath) == moduleMapsSeen.end()) {
21982199
moduleMapsSeen.insert(moduleMapPath);
21992200
extraClangArgs.push_back(

lib/FrontendTool/FrontendTool.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,13 @@ static bool buildModuleFromInterface(CompilerInstance &Instance) {
410410
bool IgnoreAdjacentModules = Instance.hasASTContext() &&
411411
Instance.getASTContext().IgnoreAdjacentModules;
412412

413+
// When building explicit module dependencies, they are
414+
// discovered by dependency scanner and the swiftmodule is already rebuilt
415+
// ignoring candidate module. There is no need to serialized dependencies for
416+
// validation purpose because the build system (swift-driver) is then
417+
// responsible for checking whether inputs are up-to-date.
418+
bool ShouldSerializeDeps = !FEOpts.ExplicitInterfaceBuild;
419+
413420
// If an explicit interface build was requested, bypass the creation of a new
414421
// sub-instance from the interface which will build it in a separate thread,
415422
// and isntead directly use the current \c Instance for compilation.
@@ -422,8 +429,7 @@ static bool buildModuleFromInterface(CompilerInstance &Instance) {
422429
return ModuleInterfaceLoader::buildExplicitSwiftModuleFromSwiftInterface(
423430
Instance, Invocation.getClangModuleCachePath(),
424431
FEOpts.BackupModuleInterfaceDir, PrebuiltCachePath, ABIPath, InputPath,
425-
Invocation.getOutputFilename(),
426-
/* shouldSerializeDeps */ true,
432+
Invocation.getOutputFilename(), ShouldSerializeDeps,
427433
Invocation.getSearchPathOptions().CandidateCompiledModules);
428434

429435
return ModuleInterfaceLoader::buildSwiftModuleFromSwiftInterface(
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %empty-directory(%t)
3+
// RUN: %empty-directory(%t/FooInputs)
4+
// RUN: %empty-directory(%t/BridgingHeaderDir)
5+
// RUN: %empty-directory(%t/TestCHeaders)
6+
// RUN: %empty-directory(%t/TestSwiftInterfaces)
7+
// RUN: %empty-directory(%t/FooModuleDir)
8+
// RUN: split-file %s %t
9+
10+
// - Fixup the input module file map
11+
// RUN: sed -e "s|INPUTSDIR|%/t/FooInputs|g" %t/map.json.template > %t/map.json.template1
12+
// RUN: sed -e "s|STDLIBMOD|%/stdlib_module|g" %t/map.json.template1 > %t/map.json.template2
13+
// RUN: sed -e "s|ONONEMOD|%/ononesupport_module|g" %t/map.json.template2 > %t/map.json.template3
14+
// RUN: sed -e "s|SWIFTLIBDIR|%swift-lib-dir|g" %t/map.json.template3 > %t/map.json
15+
16+
// - Set up explicit dependencies for Foo
17+
// RUN: %target-swift-emit-pcm -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/FooInputs/SwiftShims.pcm
18+
// - Build Foo module dependency, explicitly, non-resiliently
19+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/FooModuleDir/Foo.swiftmodule %t/foo.swift -module-name Foo -import-objc-header %t/BridgingHeaderDir/foo.h -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -disable-implicit-swift-modules -explicit-swift-module-map-file %t/map.json -I %S/Inputs/CHeaders
20+
21+
// - Scan main module and ensure that the "FooClient" recipe includes the modulemap for Foo's briding header's module dependencies
22+
// but not other dependencies
23+
// RUN: %target-swift-frontend -scan-dependencies %t/bridging_header_dep_module_map.swift -I %t/FooModuleDir -I %t/TestSwiftInterfaces -I %t/TestCHeaders -I %S/Inputs/CHeaders -o %t/deps.json
24+
// RUN: %validate-json %t/deps.json | %FileCheck %s
25+
26+
// Given the following dependency graph:
27+
//
28+
// main
29+
// |
30+
// FooClient (.swiftinterface)
31+
// | \
32+
// Foo(.swiftmodule) Dart (.pcm)
33+
//
34+
// Given that 'Foo.swiftmodule' is built with a bridging header which imports 'X.h' ('X' clang module)
35+
// We expect that 'Foo' will have a dependency on module 'X', and the scanner will ensure that 'FooClient' is built
36+
// with the modulemap file for 'X' as an explicit input. 'Dart' Clang module however, must not result in an
37+
// explicitly-specified modulemap file because no headers of this module will be ingested into the Swift
38+
// compiler.
39+
40+
// Dependency of the main module
41+
// CHECK: "swift": "FooClient"
42+
43+
// Definition of 'FooClient' in the dependency graph
44+
// CHECK: "swift": "FooClient"
45+
// CHECK: "modulePath": "{{.*}}FooClient-{{.*}}.swiftmodule",
46+
// CHECK: "directDependencies": [
47+
// CHECK-DAG: "swiftPrebuiltExternal": "Foo"
48+
// CHECK-DAG: "swift": "SwiftOnoneSupport"
49+
// CHECK-DAG: "clang": "Dart"
50+
// CHECK: ],
51+
// CHECK: "commandLine": [
52+
// CHECK: "-fmodule-map-file={{.*}}{{/|\\}}CHeaders{{/|\\}}module.modulemap"
53+
// CHECK-NOT: "-fmodule-map-file={{.*}}{{/|\\}}TestCHeaders{{/|\\}}module.modulemap"
54+
// CHECK: ]
55+
56+
// Definition of 'Foo' in the dependency graph
57+
// CHECK: "swiftPrebuiltExternal": "Foo"
58+
// CHECK: "modulePath": "{{.*}}Foo.swiftmodule",
59+
// CHECK-NEXT: "directDependencies": [
60+
// CHECK-DAG: "swift": "Swift"
61+
// CHECK-DAG: "swift": "SwiftOnoneSupport"
62+
// CHECK-DAG: "clang": "X"
63+
// CHECK: ],
64+
// CHECK: "headerDependency": "{{.*}}{{/|\\}}BridgingHeaderDir{{/|\\}}foo.h"
65+
// CHECK: "headerModuleDependencies": [
66+
// CHECK-NEXT: "X"
67+
// CHECK-NEXT: ],
68+
// CHECK: "headerDependenciesSourceFiles": [
69+
// CHECK-NEXT: "{{.*}}{{/|\\}}BridgingHeaderDir{{/|\\}}foo.h"
70+
// CHECK-NEXT: ],
71+
72+
//--- foo.swift
73+
extension Profiler {
74+
public static let count: Int = 42
75+
}
76+
77+
//--- BridgingHeaderDir/foo.h
78+
#include "X.h"
79+
struct Profiler { void* ptr; };
80+
81+
//--- TestCHeaders/Dart.h
82+
struct Dart { void* ptr; };
83+
//--- TestCHeaders/module.modulemap
84+
module Dart {
85+
header "Dart.h"
86+
export *
87+
}
88+
89+
//--- TestSwiftInterfaces/FooClient.swiftinterface
90+
// swift-interface-format-version: 1.0
91+
// swift-module-flags: -module-name FooClient
92+
import Foo
93+
import Dart
94+
95+
//--- map.json.template
96+
[
97+
{
98+
"moduleName": "Swift",
99+
"modulePath": "STDLIBMOD",
100+
"isFramework": false
101+
},
102+
{
103+
"moduleName": "SwiftOnoneSupport",
104+
"modulePath": "ONONEMOD",
105+
"isFramework": false
106+
},
107+
{
108+
"moduleName": "SwiftShims",
109+
"isFramework": false,
110+
"clangModuleMapPath": "SWIFTLIBDIR/swift/shims/module.modulemap",
111+
"clangModulePath": "INPUTSDIR/SwiftShims.pcm"
112+
}]
113+
114+
//--- bridging_header_dep_module_map.swift
115+
import FooClient
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %empty-directory(%t)
3+
// RUN: %empty-directory(%t/TestInputs)
4+
// RUN: split-file %s %t
5+
6+
// - Fixup the input module file map
7+
// RUN: sed -e "s|INPUTSDIR|%/t/TestInputs|g" %t/map.json.template > %t/map.json.template1
8+
// RUN: sed -e "s|STDLIBMOD|%/stdlib_module|g" %t/map.json.template1 > %t/map.json.template2
9+
// RUN: sed -e "s|ONONEMOD|%/ononesupport_module|g" %t/map.json.template2 > %t/map.json.template3
10+
// RUN: sed -e "s|CHEADERSDIR|%/S/Inputs/CHeaders|g" %t/map.json.template3 > %t/map.json.template4
11+
// RUN: sed -e "s|SWIFTLIBDIR|%swift-lib-dir|g" %t/map.json.template4 > %t/map.json
12+
13+
// - Pre-compile explicit module dependency inputs
14+
// RUN: %target-swift-emit-pcm -module-name A -o %t/TestInputs/A.pcm %S/Inputs/CHeaders/module.modulemap
15+
// RUN: %target-swift-emit-pcm -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/TestInputs/SwiftShims.pcm
16+
17+
// RUN: %target-swift-frontend -c -disable-implicit-swift-modules -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -explicit-swift-module-map-file %t/map.json -primary-file %t/bridging_header_modulemap_only.swift -o %t/bridging_header_modulemap_only.o -dump-clang-diagnostics 2>&1 | %FileCheck %s --check-prefix=CHECK-CLANG-COMMAND
18+
19+
//--- map.json.template
20+
[
21+
{
22+
"moduleName": "Swift",
23+
"modulePath": "STDLIBMOD",
24+
"isFramework": false
25+
},
26+
{
27+
"moduleName": "SwiftOnoneSupport",
28+
"modulePath": "ONONEMOD",
29+
"isFramework": false
30+
},
31+
{
32+
"moduleName": "SwiftShims",
33+
"isFramework": false,
34+
"isBridgingHeaderDependency": false,
35+
"clangModuleMapPath": "SWIFTLIBDIR/swift/shims/module.modulemap",
36+
"clangModulePath": "INPUTSDIR/SwiftShims.pcm"
37+
},
38+
{
39+
"moduleName": "A",
40+
"isFramework": false,
41+
"isBridgingHeaderDependency": true,
42+
"clangModulePath": "INPUTSDIR/A.pcm",
43+
"clangModuleMapPath": "CHEADERSDIR/module.modulemap"
44+
}
45+
]
46+
47+
//--- bridging_header_modulemap_only.swift
48+
import A
49+
50+
// CHECK-CLANG-COMMAND: -fmodule-map-file={{.*}}{{/|\\}}CHeaders{{/|\\}}module.modulemap
51+
// CHECK-CLANG-COMMAND-NOT: -fmodule-map-file={{.*}}{{/|\\}}swift{{/|\\}}shims{{/|\\}}module.modulemap

test/ScanDependencies/explicit-swift-dependencies.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,5 @@ import F
5151
// CHECK-NEXT: "{{.*}}{{/|\\}}F-{{.*}}.swiftmodule"
5252
// CHECK-DAG: "-swift-module-file=Swift={{.*}}{{/|\\}}Swift-{{.*}}.swiftmodule"
5353
// CHECK-DAG: "-swift-module-file=SwiftOnoneSupport={{.*}}{{/|\\}}SwiftOnoneSupport-{{.*}}.swiftmodule"
54-
// CHECK-DAG: "-fmodule-file=F={{.*}}{{/|\\}}F-{{.*}}.pcm",
55-
// CHECK-DAG: "-fmodule-file=SwiftShims={{.*}}{{/|\\}}SwiftShims-{{.*}}.pcm",
54+
// CHECK-DAG: "-fmodule-file=F={{.*}}{{/|\\}}F-{{.*}}.pcm"
55+
// CHECK-DAG: "-fmodule-file=SwiftShims={{.*}}{{/|\\}}SwiftShims-{{.*}}.pcm"

0 commit comments

Comments
 (0)