Skip to content

Commit 6b62817

Browse files
committed
Add feature for partially explicit modules
As of Swift 5.6 and this PR swiftlang/swift#39887 the new json format used for entirely explicit module builds can be used without entirely disabling implicit modules. This provides an alternative to VFS overlays for discovering dependencies without `-I` search paths. This is theoretically about the same but I expect this file format to have better support in general than VFS overlays for things like the new incremental compilation support, which currently doesn't support VFS overlays, and this shouldn't have any downsides vs VFS files. This format does support some more keys than just the 2 we pass, as far as I can tell they are unused today, so I'm opting not to pass them. We may have to revisit this in the future.
1 parent f05b2bd commit 6b62817

File tree

4 files changed

+96
-3
lines changed

4 files changed

+96
-3
lines changed

swift/internal/compiling.bzl

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ load(
5353
"SWIFT_FEATURE_OPT",
5454
"SWIFT_FEATURE_OPT_USES_OSIZE",
5555
"SWIFT_FEATURE_OPT_USES_WMO",
56+
"SWIFT_FEATURE_PARTIALLY_EXPLICIT_MODULES",
5657
"SWIFT_FEATURE_REWRITE_GENERATED_HEADER",
5758
"SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION",
5859
"SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION",
@@ -90,7 +91,7 @@ load(
9091
"get_providers",
9192
"struct_fields",
9293
)
93-
load(":vfsoverlay.bzl", "write_vfsoverlay")
94+
load(":vfsoverlay.bzl", "write_explicit_module_map", "write_vfsoverlay")
9495

9596
# VFS root where all .swiftmodule files will be placed when
9697
# SWIFT_FEATURE_VFSOVERLAY is enabled.
@@ -725,7 +726,10 @@ def compile_action_configs(
725726
swift_action_names.DUMP_AST,
726727
],
727728
configurators = [_dependencies_swiftmodules_configurator],
728-
not_features = [SWIFT_FEATURE_VFSOVERLAY],
729+
not_features = [
730+
[SWIFT_FEATURE_VFSOVERLAY],
731+
[SWIFT_FEATURE_PARTIALLY_EXPLICIT_MODULES],
732+
],
729733
),
730734
swift_toolchain_config.action_config(
731735
actions = [
@@ -738,6 +742,17 @@ def compile_action_configs(
738742
],
739743
features = [SWIFT_FEATURE_VFSOVERLAY],
740744
),
745+
swift_toolchain_config.action_config(
746+
actions = [
747+
swift_action_names.COMPILE,
748+
swift_action_names.DERIVE_FILES,
749+
swift_action_names.DUMP_AST,
750+
],
751+
configurators = [
752+
_explicit_module_map_configurator,
753+
],
754+
features = [SWIFT_FEATURE_PARTIALLY_EXPLICIT_MODULES],
755+
),
741756
])
742757

743758
#### Search paths for framework dependencies
@@ -1425,6 +1440,17 @@ def _dependencies_swiftmodules_vfsoverlay_configurator(prerequisites, args):
14251440
inputs = swiftmodules + [prerequisites.vfsoverlay_file],
14261441
)
14271442

1443+
def _explicit_module_map_configurator(prerequisites, args):
1444+
"""Configures a explicit swiftmodule map file for compilation"""
1445+
swiftmodules = prerequisites.transitive_swiftmodules
1446+
1447+
args.add("-Xfrontend", "-explicit-swift-module-map-file")
1448+
args.add("-Xfrontend", prerequisites.explicit_module_file.path)
1449+
1450+
return swift_toolchain_config.config_result(
1451+
inputs = swiftmodules + [prerequisites.explicit_module_file],
1452+
)
1453+
14281454
def _module_name_configurator(prerequisites, args):
14291455
"""Adds the module name flag to the command line."""
14301456
args.add("-module-name", prerequisites.module_name)
@@ -1815,11 +1841,31 @@ def compile(
18151841
else:
18161842
vfsoverlay_file = None
18171843

1844+
if is_feature_enabled(
1845+
feature_configuration = feature_configuration,
1846+
feature_name = SWIFT_FEATURE_PARTIALLY_EXPLICIT_MODULES,
1847+
):
1848+
explicit_module_file = derived_files.explicit_module_map(
1849+
actions = actions,
1850+
target_name = target_name,
1851+
)
1852+
write_explicit_module_map(
1853+
actions = actions,
1854+
swiftmodules = transitive_swiftmodules,
1855+
output_file = explicit_module_file,
1856+
)
1857+
else:
1858+
explicit_module_file = None
1859+
1860+
if vfsoverlay_file and explicit_module_file:
1861+
fail("VFS overlays cannot be used with explicit modules")
1862+
18181863
prerequisites = struct(
18191864
additional_inputs = additional_inputs,
18201865
bin_dir = feature_configuration._bin_dir,
18211866
cc_compilation_context = merged_providers.cc_info.compilation_context,
18221867
defines = sets.to_list(defines_set),
1868+
explicit_module_file = explicit_module_file,
18231869
genfiles_dir = feature_configuration._genfiles_dir,
18241870
is_swift = True,
18251871
module_name = module_name,

swift/internal/derived_files.bzl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,23 @@ def _vfsoverlay(actions, target_name):
294294
"""
295295
return actions.declare_file("{}.vfsoverlay.yaml".format(target_name))
296296

297+
def _explicit_module_map(actions, target_name):
298+
"""Declares a file for the explicit module map confoiguration for a
299+
compilation action.
300+
301+
The explicit module map file is JSON-formatted file that allows us to place
302+
the `.swiftmodule` files for all dependencies into a single file used for
303+
lookup instead of discovering them through search paths.
304+
305+
Args:
306+
actions: The context's actions object.
307+
target_name: The name of the target being built.
308+
309+
Returns:
310+
The declared `File`.
311+
"""
312+
return actions.declare_file("{}.explicitmodulemap.json".format(target_name))
313+
297314
def _whole_module_object_file(actions, target_name):
298315
"""Declares a file for object files created with whole module optimization.
299316
@@ -326,6 +343,7 @@ derived_files = struct(
326343
ast = _ast,
327344
autolink_flags = _autolink_flags,
328345
executable = _executable,
346+
explicit_module_map = _explicit_module_map,
329347
indexstore_directory = _indexstore_directory,
330348
intermediate_bc_file = _intermediate_bc_file,
331349
intermediate_object_file = _intermediate_object_file,
@@ -334,8 +352,8 @@ derived_files = struct(
334352
precompiled_module = _precompiled_module,
335353
reexport_modules_src = _reexport_modules_src,
336354
static_archive = _static_archive,
337-
swiftc_output_file_map = _swiftc_output_file_map,
338355
swiftc_derived_output_file_map = _swiftc_derived_output_file_map,
356+
swiftc_output_file_map = _swiftc_output_file_map,
339357
swiftdoc = _swiftdoc,
340358
swiftinterface = _swiftinterface,
341359
swiftmodule = _swiftmodule,

swift/internal/feature_names.bzl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ SWIFT_FEATURE_USE_RESPONSE_FILES = "swift.use_response_files"
202202
# when access to those paths involves traversing a networked file system.
203203
SWIFT_FEATURE_VFSOVERLAY = "swift.vfsoverlay"
204204

205+
# If enabled, Swift compilation actions will use a explicit module map file for
206+
# discovering dependencies. This is faster than using search paths when you
207+
# have many dependencies. This doesn't apply to system dependencies.
208+
SWIFT_FEATURE_PARTIALLY_EXPLICIT_MODULES = "swift.partially_explicit_modules"
209+
205210
# If enabled, builds using the "dbg" compilation mode will explicitly disable
206211
# swiftc from producing swiftmodules containing embedded file paths, which are
207212
# inherently non-portable across machines.

swift/internal/vfsoverlay.bzl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,27 @@ def write_vfsoverlay(
6262
content = vfsoverlay_yaml,
6363
output = vfsoverlay_file,
6464
)
65+
66+
def write_explicit_module_map(
67+
actions,
68+
swiftmodules,
69+
output_file):
70+
"""Generates a explicit module map and writes it to a file.
71+
72+
Args:
73+
actions: The object used to register actions.
74+
swiftmodules: The `list` of transitive `.swiftmodule` dependencies.
75+
output_file: A `File` to write the output to.
76+
"""
77+
virtual_swiftmodules = [
78+
{
79+
"moduleName": swiftmodule.basename.rsplit(".", 1)[0],
80+
"modulePath": swiftmodule.path,
81+
}
82+
for swiftmodule in swiftmodules
83+
]
84+
85+
actions.write(
86+
content = json.encode(virtual_swiftmodules),
87+
output = output_file,
88+
)

0 commit comments

Comments
 (0)