Skip to content

Commit b66294e

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 c72cbc6 commit b66294e

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
@@ -1426,6 +1441,17 @@ def _dependencies_swiftmodules_vfsoverlay_configurator(prerequisites, args):
14261441
inputs = swiftmodules + [prerequisites.vfsoverlay_file],
14271442
)
14281443

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

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

swift/internal/derived_files.bzl

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

319+
def _explicit_module_map(actions, target_name):
320+
"""Declares a file for the explicit module map confoiguration for a
321+
compilation action.
322+
323+
The explicit module map file is JSON-formatted file that allows us to place
324+
the `.swiftmodule` files for all dependencies into a single file used for
325+
lookup instead of discovering them through search paths.
326+
327+
Args:
328+
actions: The context's actions object.
329+
target_name: The name of the target being built.
330+
331+
Returns:
332+
The declared `File`.
333+
"""
334+
return actions.declare_file("{}.explicitmodulemap.json".format(target_name))
335+
319336
def _whole_module_object_file(actions, target_name):
320337
"""Declares a file for object files created with whole module optimization.
321338
@@ -348,6 +365,7 @@ derived_files = struct(
348365
ast = _ast,
349366
autolink_flags = _autolink_flags,
350367
executable = _executable,
368+
explicit_module_map = _explicit_module_map,
351369
indexstore_directory = _indexstore_directory,
352370
intermediate_bc_file = _intermediate_bc_file,
353371
intermediate_object_file = _intermediate_object_file,
@@ -357,8 +375,8 @@ derived_files = struct(
357375
precompiled_module = _precompiled_module,
358376
reexport_modules_src = _reexport_modules_src,
359377
static_archive = _static_archive,
360-
swiftc_output_file_map = _swiftc_output_file_map,
361378
swiftc_derived_output_file_map = _swiftc_derived_output_file_map,
379+
swiftc_output_file_map = _swiftc_output_file_map,
362380
swiftdoc = _swiftdoc,
363381
swiftinterface = _swiftinterface,
364382
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)