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

Commit

Permalink
Add a generates_header attribute to swift_library to control Obje…
Browse files Browse the repository at this point in the history
…ctive-C header generation.

Today, `swift_library` unconditionally generates a header and module map for all targets (unless rarely-used features are applied), even if the library has no APIs exported to Objective-C. This creates a small amount of unnecessary work, but that work grows significantly when explicit modules are used in the build, because we also need to compile the explicit modules for those generated headers _just in case_ some `objc_library` further up in the build graph needs to import the header.

This is the first of a few changes that will eventually require the `generates_header` attribute to be set on targets to have the generated header emitted and propagated.

This change also removes the `swift.no_generated_header` feature, since the attribute's behavior supplants it.

PiperOrigin-RevId: 362562962
  • Loading branch information
allevato authored and swiple-rules-gardener committed Mar 12, 2021
1 parent ab1c5cd commit e621e5e
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 139 deletions.
23 changes: 21 additions & 2 deletions swift/internal/attrs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,27 @@ a `.h` extension and cannot contain any path separators.
If this attribute is not specified, then the default behavior is to name the
header `${target_name}-Swift.h`.
This attribute is ignored if the toolchain does not support generating headers
or if the target has the `swift.no_generated_header` feature enabled.
It is an error to specify a value for this attribute when `generates_header` is
False.
""",
mandatory = False,
),
"generates_header": attr.bool(
# TODO(b/182493307): Make the default False after migrating all
# targets to explicitly specify it when needed.
default = True,
doc = """\
If True, an Objective-C header will be generated for this target, in the same
build package where the target is defined. By default, the name of the header is
`${target_name}-Swift.h`; this can be changed using the `generated_header_name`
attribute.
Targets should only set this attribute to True if they export Objective-C APIs.
A header generated for a target that does not export Objective-C APIs will be
effectively empty (except for a large amount of prologue and epilogue code) and
this is generally wasteful because the extra file needs to be propagated in the
build graph and, when explicit modules are enabled, extra actions must be
executed to compile the Objective-C module for the generated header.
""",
mandatory = False,
),
Expand Down
37 changes: 12 additions & 25 deletions swift/internal/compiling.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ load(
"SWIFT_FEATURE_MINIMAL_DEPS",
"SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD",
"SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE",
"SWIFT_FEATURE_NO_GENERATED_HEADER",
"SWIFT_FEATURE_NO_GENERATED_MODULE_MAP",
"SWIFT_FEATURE_OPT",
"SWIFT_FEATURE_OPT_USES_OSIZE",
Expand Down Expand Up @@ -177,7 +176,6 @@ def compile_action_configs(
swift_toolchain_config.action_config(
actions = [swift_action_names.COMPILE],
configurators = [_emit_objc_header_path_configurator],
not_features = [SWIFT_FEATURE_NO_GENERATED_HEADER],
),

# Configure the location where compiler performance statistics are
Expand Down Expand Up @@ -728,7 +726,8 @@ def _emit_module_interface_path_configurator(prerequisites, args):

def _emit_objc_header_path_configurator(prerequisites, args):
"""Adds the generated header output path to the command line."""
args.add("-emit-objc-header-path", prerequisites.generated_header_file)
if prerequisites.generated_header_file:
args.add("-emit-objc-header-path", prerequisites.generated_header_file)

def _global_module_cache_configurator(prerequisites, args):
"""Adds flags to enable the global module cache."""
Expand Down Expand Up @@ -1266,8 +1265,8 @@ def compile(
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.
should be generated for this module. If omitted, no header will be
generated.
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
Expand Down Expand Up @@ -1430,10 +1429,7 @@ def compile(

# 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(
if generated_header_name and not is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_NO_GENERATED_MODULE_MAP,
):
Expand Down Expand Up @@ -1627,7 +1623,7 @@ def _declare_compile_outputs(
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`.
module, or `None` if no header should be generated.
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.
Expand Down Expand Up @@ -1684,22 +1680,13 @@ def _declare_compile_outputs(
else:
stats_directory = None

# If supported, generate the Swift header for this library so that it can be
# If requested, generate the Swift header for this library so that it can be
# included by Objective-C code that depends on it.
if not is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_NO_GENERATED_HEADER,
):
if generated_header_name:
generated_header = _declare_validated_generated_header(
actions = actions,
generated_header_name = generated_header_name,
)
else:
generated_header = derived_files.default_generated_header(
actions = actions,
target_name = target_name,
)
if generated_header_name:
generated_header = _declare_validated_generated_header(
actions = actions,
generated_header_name = generated_header_name,
)
else:
generated_header = None

Expand Down
13 changes: 0 additions & 13 deletions swift/internal/derived_files.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,6 @@ def _autolink_flags(actions, target_name):
"""
return actions.declare_file("{}.autolink".format(target_name))

def _default_generated_header(actions, target_name):
"""Declares the automatically-named generated header for a Swift target.
Args:
actions: The context's actions object.
target_name: The name of the target being built.
Returns:
The declared `File`.
"""
return actions.declare_file("{}-Swift.h".format(target_name))

def _executable(actions, target_name):
"""Declares a file for the executable created by a binary or test rule.
Expand Down Expand Up @@ -320,7 +308,6 @@ def _xctest_runner_script(actions, target_name):

derived_files = struct(
autolink_flags = _autolink_flags,
default_generated_header = _default_generated_header,
executable = _executable,
indexstore_directory = _indexstore_directory,
intermediate_object_file = _intermediate_object_file,
Expand Down
7 changes: 1 addition & 6 deletions swift/internal/feature_names.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,9 @@ SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS = (
"swift.module_map_no_private_headers"
)

# If enabled, the compilation action for a library target will not generate an
# Objective-C header for the module. This feature also implies
# `swift.no_generated_module_map`.
SWIFT_FEATURE_NO_GENERATED_HEADER = "swift.no_generated_header"

# If enabled, the compilation action for a library target will not generate a
# module map for the Objective-C generated header. This feature is ignored if
# `swift.no_generated_header` is not present.
# the target is not generating a header.
SWIFT_FEATURE_NO_GENERATED_MODULE_MAP = "swift.no_generated_module_map"

# If enabled, builds using the "opt" compilation mode will invoke `swiftc` with
Expand Down
3 changes: 1 addition & 2 deletions swift/internal/swift_grpc_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ load(
":feature_names.bzl",
"SWIFT_FEATURE_ENABLE_TESTING",
"SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES",
"SWIFT_FEATURE_NO_GENERATED_HEADER",
)
load(":linking.bzl", "create_linker_input")
load(
Expand Down Expand Up @@ -213,7 +212,7 @@ def _swift_grpc_library_impl(ctx):

feature_configuration = swift_common.configure_features(
ctx = ctx,
requested_features = ctx.features + [SWIFT_FEATURE_NO_GENERATED_HEADER],
requested_features = ctx.features,
swift_toolchain = swift_toolchain,
unsupported_features = unsupported_features,
)
Expand Down
16 changes: 15 additions & 1 deletion swift/internal/swift_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,20 @@ def _swift_library_impl(ctx):
deps = ctx.attr.deps
private_deps = []

if ctx.attr.generates_header:
generated_header_name = (
ctx.attr.generated_header_name or
"{}-Swift.h".format(ctx.label.name)
)
elif not ctx.attr.generated_header_name:
generated_header_name = None
else:
fail(
"'generated_header_name' may only be provided when " +
"'generates_header' is True.",
attr = "generated_header_name",
)

compilation_outputs = swift_common.compile(
actions = ctx.actions,
additional_inputs = additional_inputs,
Expand All @@ -155,7 +169,7 @@ def _swift_library_impl(ctx):
defines = ctx.attr.defines,
deps = deps,
feature_configuration = feature_configuration,
generated_header_name = ctx.attr.generated_header_name,
generated_header_name = generated_header_name,
genfiles_dir = ctx.genfiles_dir,
module_name = module_name,
private_deps = private_deps,
Expand Down
5 changes: 1 addition & 4 deletions swift/internal/swift_protoc_gen_aspect.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ load(
"SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION",
"SWIFT_FEATURE_ENABLE_TESTING",
"SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES",
"SWIFT_FEATURE_NO_GENERATED_HEADER",
)
load(":linking.bzl", "create_linker_input")
load(
Expand Down Expand Up @@ -369,9 +368,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx):
# compile action.
feature_configuration = swift_common.configure_features(
ctx = aspect_ctx,
requested_features = aspect_ctx.features + extra_features + [
SWIFT_FEATURE_NO_GENERATED_HEADER,
],
requested_features = aspect_ctx.features + extra_features,
swift_toolchain = swift_toolchain,
unsupported_features = aspect_ctx.disabled_features + [
SWIFT_FEATURE_ENABLE_TESTING,
Expand Down
6 changes: 1 addition & 5 deletions swift/internal/swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ load(":debugging.bzl", "modulewrap_action_configs")
load(
":feature_names.bzl",
"SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD",
"SWIFT_FEATURE_NO_GENERATED_HEADER",
"SWIFT_FEATURE_NO_GENERATED_MODULE_MAP",
"SWIFT_FEATURE_USE_RESPONSE_FILES",
)
Expand Down Expand Up @@ -180,10 +179,7 @@ def _swift_toolchain_impl(ctx):
features_for_build_modes(ctx) +
features_from_swiftcopts(swiftcopts = ctx.fragments.swift.copts())
)
requested_features.extend([
SWIFT_FEATURE_NO_GENERATED_HEADER,
SWIFT_FEATURE_NO_GENERATED_MODULE_MAP,
])
requested_features.append(SWIFT_FEATURE_NO_GENERATED_MODULE_MAP)
requested_features.extend(ctx.features)

# Swift.org toolchains assume everything is just available on the PATH so we
Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/generated_header/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,48 @@ package(

licenses(["notice"])

swift_library(
name = "no_header",
srcs = ["Empty.swift"],
generates_header = False,
tags = FIXTURE_TAGS,
)

swift_library(
name = "auto_header",
srcs = ["Empty.swift"],
generates_header = True,
tags = FIXTURE_TAGS,
)

swift_library(
name = "explicit_header",
srcs = ["Empty.swift"],
generated_header_name = "SomeOtherName.h",
generates_header = True,
tags = FIXTURE_TAGS,
)

swift_library(
name = "invalid_extension",
srcs = ["Empty.swift"],
generated_header_name = "Invalid.extension",
generates_header = True,
tags = FIXTURE_TAGS,
)

swift_library(
name = "invalid_path_separator",
srcs = ["Empty.swift"],
generated_header_name = "Invalid/Separator.h",
generates_header = True,
tags = FIXTURE_TAGS,
)

swift_library(
name = "invalid_attribute_combination",
srcs = ["Empty.swift"],
generated_header_name = "SomeOtherName.h",
generates_header = False,
tags = FIXTURE_TAGS,
)
15 changes: 8 additions & 7 deletions test/fixtures/private_deps/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ licenses(["notice"])
swift_library(
name = "private_swift",
srcs = ["Empty.swift"],
generates_header = True,
tags = FIXTURE_TAGS,
)

swift_library(
name = "public_swift",
srcs = ["Empty.swift"],
generates_header = True,
tags = FIXTURE_TAGS,
)

swift_library(
name = "client_swift_deps",
srcs = ["Empty.swift"],
generates_header = True,
private_deps = [
":private_swift",
],
Expand Down Expand Up @@ -65,13 +68,11 @@ cc_library(
swift_library(
name = "client_cc_deps",
srcs = ["Empty.swift"],
features = [
# Suppress the generated header/module map on platforms that support
# Objective-C interop so that we don't have to worry about
# conditionally checking for it in the transitive modules on just those
# platforms.
"swift.no_generated_header",
],
# Suppress the generated header/module map on platforms that support
# Objective-C interop so that we don't have to worry about
# conditionally checking for it in the transitive modules on just those
# platforms.
generates_header = False,
private_deps = [
":private_cc",
],
Expand Down
Loading

0 comments on commit e621e5e

Please sign in to comment.