Skip to content
This repository has been archived by the owner on Jan 25, 2024. It is now read-only.

Commit

Permalink
Compile an explicit module for the generated header of a `swift_libra…
Browse files Browse the repository at this point in the history
…ry`.

The notion of "implicit compile-time dependencies for generated header modules only" has been added to the toolchain because generated Obj-C headers always import Foundation and Darwin, but we don't necessarily want to force those as dependencies of every Swift compilation. Likewise, the private (implementation-only) dependencies of a module shouldn't be included when generating the module map `use` decls for the Obj-C header module, because by definition, they can't be exported.

PiperOrigin-RevId: 358406043
  • Loading branch information
allevato authored and swiple-rules-gardener committed Feb 19, 2021
1 parent f45eea8 commit ab1c5cd
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 22 deletions.
93 changes: 77 additions & 16 deletions swift/internal/compiling.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,8 @@ def compile(
defines = [],
deps = [],
generated_header_name = None,
genfiles_dir = None):
genfiles_dir = None,
private_deps = []):
"""Compiles a Swift module.
Args:
Expand Down Expand Up @@ -1259,16 +1260,23 @@ def compile(
determine whether whole module optimization is being requested,
which affects the nature of the output files.
defines: Symbols that should be defined by passing `-D` to the compiler.
deps: Dependencies of the target being compiled. These targets must
propagate one of the following providers: `CcInfo`, `SwiftInfo`, or
`apple_common.Objc`.
deps: Non-private dependencies of the target being compiled. These
targets are used as dependencies of both the Swift module being
compiled and the Clang module for the generated header. These
targets must propagate one of the following providers: `CcInfo`,
`SwiftInfo`, or `apple_common.Objc`.
generated_header_name: The name of the Objective-C generated header that
should be generated for this module. If omitted, the name
`${target_name}-Swift.h` will be used.
genfiles_dir: The Bazel `*-genfiles` directory root. If provided, its
path is added to ClangImporter's header search paths for
compatibility with Bazel's C++ and Objective-C rules which support
inclusions of generated headers from that location.
private_deps: Private (implementation-only) dependencies of the target
being compiled. These are only used as dependencies of the Swift
module, not of the Clang module for the generated header. These
targets must propagate one of the following providers: `CcInfo`,
`SwiftInfo`, or `apple_common.Objc`.
Returns:
A `struct` containing the following fields:
Expand All @@ -1293,6 +1301,9 @@ def compile(
never None.
* `object_files`: A list of `.o` files that were produced by the
compiler.
* `precompiled_module`: A `File` representing the explicit module
(`.pcm`) of the Clang module for the generated header, or `None` if
no explicit module was generated.
* `stats_directory`: A `File` representing the directory that contains
the timing statistics emitted by the compiler. If no stats were
requested, this field will be None.
Expand All @@ -1304,10 +1315,14 @@ def compile(
* `swiftmodule`: The `.swiftmodule` file that was produced by the
compiler.
"""
generated_module_deps = (
deps + swift_toolchain.generated_header_module_implicit_deps
)
compile_outputs, other_outputs = _declare_compile_outputs(
actions = actions,
generated_header_name = generated_header_name,
feature_configuration = feature_configuration,
generated_header_name = generated_header_name,
generated_module_deps = generated_module_deps,
module_name = module_name,
srcs = srcs,
target_name = target_name,
Expand All @@ -1330,13 +1345,12 @@ def compile(
# `SwiftInfo`, `CcInfo`, and `apple_common.Objc`. Then we can pass these
# into the action prerequisites so that configurators have easy access to
# the full set of values and inputs through a single accessor.
all_deps = deps + get_implicit_deps(
feature_configuration = feature_configuration,
swift_toolchain = swift_toolchain,
)
merged_providers = _merge_targets_providers(
supports_objc_interop = swift_toolchain.supports_objc_interop,
targets = all_deps,
targets = deps + private_deps + get_implicit_deps(
feature_configuration = feature_configuration,
swift_toolchain = swift_toolchain,
),
)

# Flattening this `depset` is necessary because we need to extract the
Expand Down Expand Up @@ -1410,12 +1424,42 @@ def compile(
feature_configuration = feature_configuration,
outputs = all_compile_outputs,
prerequisites = prerequisites,
progress_message = (
"Compiling Swift module {}".format(module_name)
),
progress_message = "Compiling Swift module {}".format(module_name),
swift_toolchain = swift_toolchain,
)

# If a header and module map were generated for this Swift module, attempt
# to precompile the explicit module for that header as well.
if not is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_NO_GENERATED_HEADER,
) and not is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_NO_GENERATED_MODULE_MAP,
):
precompiled_module = precompile_clang_module(
actions = actions,
bin_dir = bin_dir,
cc_compilation_context = cc_common.create_compilation_context(
headers = depset([compile_outputs.generated_header_file]),
),
feature_configuration = feature_configuration,
genfiles_dir = genfiles_dir,
module_map_file = compile_outputs.generated_module_map_file,
module_name = module_name,
swift_info = create_swift_info(
swift_infos = [
dep[SwiftInfo]
for dep in generated_module_deps
if SwiftInfo in dep
],
),
swift_toolchain = swift_toolchain,
target_name = target_name,
)
else:
precompiled_module = None

# As part of the full compilation flow, register additional post-compile
# actions that toolchains may conditionally support for their target
# platform, like module-wrap or autolink-extract.
Expand All @@ -1438,6 +1482,7 @@ def compile(
compile_outputs.object_files +
post_compile_results.additional_object_files
),
precompiled_module = precompiled_module,
stats_directory = compile_outputs.stats_directory,
swiftdoc = compile_outputs.swiftdoc_file,
swiftinterface = compile_outputs.swiftinterface_file,
Expand Down Expand Up @@ -1566,9 +1611,11 @@ def get_implicit_deps(feature_configuration, swift_toolchain):
return deps

def _declare_compile_outputs(
*,
actions,
generated_header_name,
feature_configuration,
generated_header_name,
generated_module_deps,
module_name,
srcs,
target_name,
Expand All @@ -1577,10 +1624,12 @@ def _declare_compile_outputs(
Args:
actions: The object used to register actions.
generated_header_name: The desired name of the generated header for this
module, or `None` to use `${target_name}-Swift.h`.
feature_configuration: A feature configuration obtained from
`swift_common.configure_features`.
generated_header_name: The desired name of the generated header for this
module, or `None` to use `${target_name}-Swift.h`.
generated_module_deps: Dependencies of the module for the generated
header of the target being compiled.
module_name: The name of the Swift module being compiled.
srcs: The list of source files that will be compiled.
target_name: The name (excluding package path) of the target being
Expand Down Expand Up @@ -1666,12 +1715,24 @@ def _declare_compile_outputs(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_NO_GENERATED_MODULE_MAP,
):
# Collect the names of Clang modules that the module being built
# directly depends on.
dependent_module_names = sets.make()
for dep in generated_module_deps:
if SwiftInfo in dep:
for module in dep[SwiftInfo].direct_modules:
if module.clang:
sets.insert(dependent_module_names, module.name)

generated_module_map = derived_files.module_map(
actions = actions,
target_name = target_name,
)
write_module_map(
actions = actions,
dependent_module_names = sorted(
sets.to_list(dependent_module_names),
),
module_map_file = generated_module_map,
module_name = module_name,
public_headers = [generated_header],
Expand Down
7 changes: 7 additions & 0 deletions swift/internal/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ Swift toolchain depends on.
""",
"cpu": """\
`String`. The CPU architecture that the toolchain is targeting.
""",
"generated_header_module_implicit_deps": """\
`List` of `Target`s. Targets whose `SwiftInfo` providers should be treated as
compile-time inputs to actions that precompile the explicit module for the
generated Objective-C header of a Swift module. This is used to provide modular
dependencies for the fixed inclusions (Darwin, Foundation) that are
unconditionally emitted in those files.
""",
"linker_opts_producer": """\
Skylib `partial`. A partial function that returns the flags that should be
Expand Down
12 changes: 6 additions & 6 deletions swift/internal/swift_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -153,27 +153,26 @@ def _swift_library_impl(ctx):
bin_dir = ctx.bin_dir,
copts = _maybe_parse_as_library_copts(srcs) + copts,
defines = ctx.attr.defines,
deps = deps + private_deps,
deps = deps,
feature_configuration = feature_configuration,
generated_header_name = ctx.attr.generated_header_name,
genfiles_dir = ctx.genfiles_dir,
module_name = module_name,
private_deps = private_deps,
srcs = srcs,
swift_toolchain = swift_toolchain,
target_name = ctx.label.name,
)

# If a module map was created for the generated header, propagate it as a
# Clang module so that it is passed as a module input to upstream
# compilation actions.
# If a module was created for the generated header, propagate it as well so
# that it is passed as a module input to upstream compilation actions.
if compilation_outputs.generated_module_map:
clang_module = swift_common.create_clang_module(
compilation_context = cc_common.create_compilation_context(
headers = depset([compilation_outputs.generated_header]),
),
module_map = compilation_outputs.generated_module_map,
# TODO(b/142867898): Precompile the module and place it here.
precompiled_module = None,
precompiled_module = compilation_outputs.precompiled_module,
)
else:
clang_module = None
Expand All @@ -197,6 +196,7 @@ def _swift_library_impl(ctx):

direct_output_files = compact([
compilation_outputs.generated_header,
compilation_outputs.precompiled_module,
compilation_outputs.swiftdoc,
compilation_outputs.swiftinterface,
compilation_outputs.swiftmodule,
Expand Down
1 change: 1 addition & 0 deletions swift/internal/swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ def _swift_toolchain_impl(ctx):
all_files = depset(all_files),
cc_toolchain_info = cc_toolchain,
cpu = ctx.attr.arch,
generated_header_module_implicit_deps = [],
linker_opts_producer = linker_opts_producer,
object_format = "elf",
optional_implicit_deps = [],
Expand Down
11 changes: 11 additions & 0 deletions swift/internal/xcode_swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,9 @@ def _xcode_swift_toolchain_impl(ctx):
all_files = depset(all_files),
cc_toolchain_info = cc_toolchain,
cpu = cpu,
generated_header_module_implicit_deps = (
ctx.attr.generated_header_module_implicit_deps
),
linker_opts_producer = linker_opts_producer,
object_format = "macho",
optional_implicit_deps = ctx.attr.optional_implicit_deps,
Expand All @@ -749,6 +752,14 @@ xcode_swift_toolchain = rule(
attrs = dicts.add(
swift_toolchain_driver_attrs(),
{
"generated_header_module_implicit_deps": attr.label_list(
doc = """\
Targets whose `SwiftInfo` providers should be treated as compile-time inputs to
actions that precompile the explicit module for the generated Objective-C header
of a Swift module.
""",
providers = [[SwiftInfo]],
),
"optional_implicit_deps": attr.label_list(
allow_files = True,
doc = """\
Expand Down

0 comments on commit ab1c5cd

Please sign in to comment.