Skip to content

Commit

Permalink
Add an API to compile a .swiftinterface file into a .swiftmodule.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 462641052
  • Loading branch information
Googler authored and swiple-rules-gardener committed Jul 22, 2022
1 parent 81f7b54 commit 47b4648
Show file tree
Hide file tree
Showing 15 changed files with 644 additions and 35 deletions.
4 changes: 4 additions & 0 deletions swift/internal/action_names.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
# object files.
SWIFT_ACTION_COMPILE = "SwiftCompile"

# Compiles a `.swiftinterface` file into a `.swiftmodule` file.
SWIFT_ACTION_COMPILE_MODULE_INTERFACE = "SwiftCompileModuleInterface"

# Wraps a `.swiftmodule` in a `.o` file on ELF platforms so that it can be
# linked into a binary for debugging.
SWIFT_ACTION_MODULEWRAP = "SwiftModuleWrap"
Expand All @@ -35,6 +38,7 @@ def all_action_names():
"""A convenience function to return all actions defined by this rule set."""
return (
SWIFT_ACTION_COMPILE,
SWIFT_ACTION_COMPILE_MODULE_INTERFACE,
SWIFT_ACTION_MODULEWRAP,
SWIFT_ACTION_PRECOMPILE_C_MODULE,
SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT,
Expand Down
124 changes: 124 additions & 0 deletions swift/internal/compiling.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ load("@bazel_skylib//lib:types.bzl", "types")
load(
":action_names.bzl",
"SWIFT_ACTION_COMPILE",
"SWIFT_ACTION_COMPILE_MODULE_INTERFACE",
"SWIFT_ACTION_PRECOMPILE_C_MODULE",
)
load(":actions.bzl", "is_action_enabled", "run_toolchain_action")
Expand All @@ -34,6 +35,7 @@ load(
"SWIFT_FEATURE_OPT",
"SWIFT_FEATURE_OPT_USES_WMO",
"SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION",
"SWIFT_FEATURE_SYSTEM_MODULE",
"SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP",
"SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS",
"SWIFT_FEATURE__WMO_IN_SWIFTCOPTS",
Expand Down Expand Up @@ -134,6 +136,128 @@ def derive_module_name(*args):
module_name = "_" + module_name
return module_name

def compile_module_interface(
*,
actions,
compilation_contexts,
feature_configuration,
module_name,
swiftinterface_file,
swift_infos,
swift_toolchain):
"""Compiles a Swift module interface.
Args:
actions: The context's `actions` object.
compilation_contexts: A list of `CcCompilationContext`s that represent
C/Objective-C requirements of the target being compiled, such as
Swift-compatible preprocessor defines, header search paths, and so
forth. These are typically retrieved from the `CcInfo` providers of
a target's dependencies.
feature_configuration: A feature configuration obtained from
`swift_common.configure_features`.
module_name: The name of the Swift module being compiled. This must be
present and valid; use `swift_common.derive_module_name` to generate
a default from the target's label if needed.
swiftinterface_file: The Swift module interface file to compile.
swift_infos: A list of `SwiftInfo` providers from dependencies of the
target being compiled.
swift_toolchain: The `SwiftToolchainInfo` provider of the toolchain.
Returns:
A Swift module context (as returned by `swift_common.create_module`)
that contains the Swift (and potentially C/Objective-C) compilation
prerequisites of the compiled module. This should typically be
propagated by a `SwiftInfo` provider of the calling rule, and the
`CcCompilationContext` inside the Clang module substructure should be
propagated by the `CcInfo` provider of the calling rule.
"""
swiftmodule_file = actions.declare_file("{}.swiftmodule".format(module_name))

merged_compilation_context = merge_compilation_contexts(
transitive_compilation_contexts = compilation_contexts + [
cc_info.compilation_context
for cc_info in swift_toolchain.implicit_deps_providers.cc_infos
],
)
merged_swift_info = create_swift_info(
swift_infos = (
swift_infos + swift_toolchain.implicit_deps_providers.swift_infos
),
)

# Flattening this `depset` is necessary because we need to extract the
# module maps or precompiled modules out of structured values and do so
# conditionally. This should not lead to poor performance because the
# flattening happens only once as the action is being registered, rather
# than the same `depset` being flattened and re-merged multiple times up
# the build graph.
transitive_modules = merged_swift_info.transitive_modules.to_list()
transitive_swiftmodules = []
for module in transitive_modules:
swift_module = module.swift
if not swift_module:
continue
transitive_swiftmodules.append(swift_module.swiftmodule)

if is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP,
):
explicit_swift_module_map_file = actions.declare_file(
"{}.swift-explicit-module-map.json".format(module_name),
)
write_explicit_swift_module_map_file(
actions = actions,
explicit_swift_module_map_file = explicit_swift_module_map_file,
module_contexts = transitive_modules,
)
else:
explicit_swift_module_map_file = None

prerequisites = struct(
bin_dir = feature_configuration._bin_dir,
cc_compilation_context = merged_compilation_context,
explicit_swift_module_map_file = explicit_swift_module_map_file,
genfiles_dir = feature_configuration._genfiles_dir,
is_swift = True,
module_name = module_name,
source_files = [swiftinterface_file],
swiftmodule_file = swiftmodule_file,
transitive_modules = transitive_modules,
transitive_swiftmodules = transitive_swiftmodules,
user_compile_flags = [],
)

run_toolchain_action(
actions = actions,
action_name = SWIFT_ACTION_COMPILE_MODULE_INTERFACE,
feature_configuration = feature_configuration,
outputs = [swiftmodule_file],
prerequisites = prerequisites,
progress_message = "Compiling Swift module {} from textual interface".format(module_name),
swift_toolchain = swift_toolchain,
)

module_context = create_module(
name = module_name,
clang = create_clang_module(
compilation_context = merged_compilation_context,
module_map = None,
),
is_system = is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_SYSTEM_MODULE,
),
swift = create_swift_module(
swiftdoc = None,
swiftinterface = swiftinterface_file,
swiftmodule = swiftmodule_file,
),
)

return module_context

def compile(
*,
actions,
Expand Down
2 changes: 2 additions & 0 deletions swift/swift_common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ load(
load(
"@build_bazel_rules_swift//swift/internal:compiling.bzl",
"compile",
"compile_module_interface",
"derive_module_name",
"precompile_clang_module",
)
Expand Down Expand Up @@ -71,6 +72,7 @@ swift_common = struct(
cc_feature_configuration = get_cc_feature_configuration,
compilation_attrs = swift_compilation_attrs,
compile = compile,
compile_module_interface = compile_module_interface,
configure_features = configure_features,
create_clang_module = create_clang_module,
create_linking_context_from_compilation_outputs = create_linking_context_from_compilation_outputs,
Expand Down
66 changes: 48 additions & 18 deletions swift/swift_import.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ load(
load(
"@build_bazel_rules_swift//swift/internal:utils.bzl",
"compact",
"get_compilation_contexts",
"get_providers",
)
load(":providers.bzl", "SwiftInfo")
Expand All @@ -36,9 +37,14 @@ def _swift_import_impl(ctx):
archives = ctx.files.archives
deps = ctx.attr.deps
swiftdoc = ctx.file.swiftdoc
swiftinterface = ctx.file.swiftinterface
swiftmodule = ctx.file.swiftmodule

swift_toolchain = swift_common.get_toolchain(ctx)
if not (swiftinterface or swiftmodule):
fail("One or both of 'swiftinterface' and 'swiftmodule' must be " +
"specified.")

swift_toolchain = swift_common.get_toolchain(ctx, attr = "toolchain")
feature_configuration = swift_common.configure_features(
ctx = ctx,
swift_toolchain = swift_toolchain,
Expand Down Expand Up @@ -69,21 +75,38 @@ def _swift_import_impl(ctx):
cc_infos = [dep[CcInfo] for dep in deps if CcInfo in dep],
)

module_context = swift_common.create_module(
name = ctx.attr.module_name,
clang = swift_common.create_clang_module(
compilation_context = cc_info.compilation_context,
module_map = None,
),
swift = swift_common.create_swift_module(
swiftdoc = swiftdoc,
swiftmodule = swiftmodule,
),
)
swift_infos = get_providers(deps, SwiftInfo)

if swiftinterface and not swiftmodule:
module_context = swift_common.compile_module_interface(
actions = ctx.actions,
compilation_contexts = get_compilation_contexts(ctx.attr.deps),
feature_configuration = feature_configuration,
module_name = ctx.attr.module_name,
swiftinterface_file = swiftinterface,
swift_infos = swift_infos,
swift_toolchain = swift_toolchain,
)
swift_outputs = [
module_context.swift.swiftmodule,
] + compact([module_context.swift.swiftdoc])
else:
module_context = swift_common.create_module(
name = ctx.attr.module_name,
clang = swift_common.create_clang_module(
compilation_context = cc_info.compilation_context,
module_map = None,
),
swift = swift_common.create_swift_module(
swiftdoc = swiftdoc,
swiftmodule = swiftmodule,
),
)
swift_outputs = [swiftmodule] + compact([swiftdoc])

providers = [
DefaultInfo(
files = depset(archives + [swiftmodule] + compact([swiftdoc])),
files = depset(archives + swift_outputs),
runfiles = ctx.runfiles(
collect_data = True,
collect_default = True,
Expand All @@ -105,7 +128,7 @@ def _swift_import_impl(ctx):
),
swift_common.create_swift_info(
modules = [module_context],
swift_infos = get_providers(deps, SwiftInfo),
swift_infos = swift_infos,
),
]

Expand All @@ -117,12 +140,12 @@ swift_import = rule(
swift_toolchain_attrs(),
{
"archives": attr.label_list(
allow_empty = False,
allow_empty = True,
allow_files = ["a"],
doc = """\
The list of `.a` files provided to Swift targets that depend on this target.
""",
mandatory = True,
mandatory = False,
),
"module_name": attr.string(
doc = "The name of the module represented by this target.",
Expand All @@ -132,6 +155,13 @@ The list of `.a` files provided to Swift targets that depend on this target.
allow_single_file = ["swiftdoc"],
doc = """\
The `.swiftdoc` file provided to Swift targets that depend on this target.
""",
mandatory = False,
),
"swiftinterface": attr.label(
allow_single_file = ["swiftinterface"],
doc = """\
The `.swiftinterface` file that defines the module interface for this target.
""",
mandatory = False,
),
Expand All @@ -140,12 +170,12 @@ The `.swiftdoc` file provided to Swift targets that depend on this target.
doc = """\
The `.swiftmodule` file provided to Swift targets that depend on this target.
""",
mandatory = True,
mandatory = False,
),
},
),
doc = """\
Allows for the use of precompiled Swift modules as dependencies in other
Allows for the use of Swift textual module interfaces and/or precompiled Swift modules as dependencies in other
`swift_library` and `swift_binary` targets.
""",
fragments = ["cpp"],
Expand Down
2 changes: 2 additions & 0 deletions swift/toolchains/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ bzl_library(
"//swift/toolchains/config:action_config",
"//swift/toolchains/config:all_actions_config",
"//swift/toolchains/config:compile_config",
"//swift/toolchains/config:compile_module_interface_config",
"//swift/toolchains/config:modulewrap_config",
"//swift/toolchains/config:symbol_graph_config",
"//swift/toolchains/config:tool_config",
Expand All @@ -41,6 +42,7 @@ bzl_library(
"//swift/toolchains/config:action_config",
"//swift/toolchains/config:all_actions_config",
"//swift/toolchains/config:compile_config",
"//swift/toolchains/config:compile_module_interface_config",
"//swift/toolchains/config:symbol_graph_config",
"//swift/toolchains/config:tool_config",
"@bazel_skylib//lib:dicts",
Expand Down
10 changes: 10 additions & 0 deletions swift/toolchains/config/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ bzl_library(
],
)

bzl_library(
name = "compile_module_interface_config",
srcs = ["compile_module_interface_config.bzl"],
deps = [
":action_config",
"//swift/internal:action_names",
"//swift/internal:feature_names",
],
)

bzl_library(
name = "modulewrap_config",
srcs = ["modulewrap_config.bzl"],
Expand Down
Loading

2 comments on commit 47b4648

@keith
Copy link
Member

@keith keith commented on 47b4648 Aug 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brentleyjones
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And #1250

Please sign in to comment.