Skip to content

Commit

Permalink
Define the swift_cross_import_overlay rule
Browse files Browse the repository at this point in the history
This change only defines the rule, associated providers, and toolchain support. A subsequent change will update compilation logic to scan dependencies and add overlays implicitly to the prerequisites.

PiperOrigin-RevId: 491657254
(cherry picked from commit b18c272 and 2fe6f0d)
Signed-off-by: Brentley Jones <github@brentleyjones.com>
  • Loading branch information
allevato authored and brentleyjones committed Oct 7, 2024
1 parent e2df74b commit fad4faf
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 4 deletions.
1 change: 1 addition & 0 deletions doc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ _DOC_SRCS = {
"swift_binary",
"swift_compiler_plugin",
"universal_swift_compiler_plugin",
"swift_cross_import_overlay",
"swift_feature_allowlist",
"swift_import",
"swift_interop_hint",
Expand Down
5 changes: 5 additions & 0 deletions doc/doc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ load(
_swift_compiler_plugin = "swift_compiler_plugin",
_universal_swift_compiler_plugin = "universal_swift_compiler_plugin",
)
load(
"//swift:swift_cross_import_overlay.bzl",
_swift_cross_import_overlay = "swift_cross_import_overlay",
)
load(
"//swift:swift_feature_allowlist.bzl",
_swift_feature_allowlist = "swift_feature_allowlist",
Expand Down Expand Up @@ -114,6 +118,7 @@ SwiftToolchainInfo = _SwiftToolchainInfo
swift_binary = _swift_binary
swift_compiler_plugin = _swift_compiler_plugin
universal_swift_compiler_plugin = _universal_swift_compiler_plugin
swift_cross_import_overlay = _swift_cross_import_overlay
swift_feature_allowlist = _swift_feature_allowlist
swift_import = _swift_import
swift_interop_hint = _swift_interop_hint
Expand Down
5 changes: 3 additions & 2 deletions doc/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ Propagates Swift-specific information about a `proto_library`.

<pre>
SwiftToolchainInfo(<a href="#SwiftToolchainInfo-action_configs">action_configs</a>, <a href="#SwiftToolchainInfo-cc_toolchain_info">cc_toolchain_info</a>, <a href="#SwiftToolchainInfo-clang_implicit_deps_providers">clang_implicit_deps_providers</a>,
<a href="#SwiftToolchainInfo-const_protocols_to_gather">const_protocols_to_gather</a>, <a href="#SwiftToolchainInfo-debug_outputs_provider">debug_outputs_provider</a>, <a href="#SwiftToolchainInfo-developer_dirs">developer_dirs</a>,
<a href="#SwiftToolchainInfo-entry_point_linkopts_provider">entry_point_linkopts_provider</a>, <a href="#SwiftToolchainInfo-feature_allowlists">feature_allowlists</a>,
<a href="#SwiftToolchainInfo-const_protocols_to_gather">const_protocols_to_gather</a>, <a href="#SwiftToolchainInfo-cross_import_overlays">cross_import_overlays</a>, <a href="#SwiftToolchainInfo-debug_outputs_provider">debug_outputs_provider</a>,
<a href="#SwiftToolchainInfo-developer_dirs">developer_dirs</a>, <a href="#SwiftToolchainInfo-entry_point_linkopts_provider">entry_point_linkopts_provider</a>, <a href="#SwiftToolchainInfo-feature_allowlists">feature_allowlists</a>,
<a href="#SwiftToolchainInfo-generated_header_module_implicit_deps_providers">generated_header_module_implicit_deps_providers</a>, <a href="#SwiftToolchainInfo-implicit_deps_providers">implicit_deps_providers</a>,
<a href="#SwiftToolchainInfo-module_aliases">module_aliases</a>, <a href="#SwiftToolchainInfo-package_configurations">package_configurations</a>, <a href="#SwiftToolchainInfo-requested_features">requested_features</a>, <a href="#SwiftToolchainInfo-root_dir">root_dir</a>, <a href="#SwiftToolchainInfo-swift_worker">swift_worker</a>,
<a href="#SwiftToolchainInfo-test_configuration">test_configuration</a>, <a href="#SwiftToolchainInfo-tool_configs">tool_configs</a>, <a href="#SwiftToolchainInfo-unsupported_features">unsupported_features</a>)
Expand All @@ -103,6 +103,7 @@ that use the toolchain.
| <a id="SwiftToolchainInfo-cc_toolchain_info"></a>cc_toolchain_info | The `cc_common.CcToolchainInfo` provider from the Bazel C++ toolchain that this Swift toolchain depends on. |
| <a id="SwiftToolchainInfo-clang_implicit_deps_providers"></a>clang_implicit_deps_providers | A `struct` with the following fields, which represent providers from targets that should be added as implicit dependencies of any precompiled explicit C/Objective-C modules:<br><br>* `cc_infos`: A list of `CcInfo` providers from targets specified as the toolchain's implicit dependencies. * `objc_infos`: A list of `apple_common.Objc` providers from targets specified as the toolchain's implicit dependencies. * `swift_infos`: A list of `SwiftInfo` providers from targets specified as the toolchain's implicit dependencies.<br><br>For ease of use, this field is never `None`; it will always be a valid `struct` containing the fields described above, even if those lists are empty. |
| <a id="SwiftToolchainInfo-const_protocols_to_gather"></a>const_protocols_to_gather | `File`. A JSON file specifying a list of protocols for extraction of conformances' const values. |
| <a id="SwiftToolchainInfo-cross_import_overlays"></a>cross_import_overlays | A list of `SwiftCrossImportOverlayInfo` providers whose `SwiftInfo` providers will be automatically injected into the dependencies of Swift compilations if their declaring module and bystanding module are both already declared as dependencies. |
| <a id="SwiftToolchainInfo-debug_outputs_provider"></a>debug_outputs_provider | An optional function that provides toolchain-specific logic around the handling of additional debug outputs for `swift_binary` and `swift_test` targets. If specified, this function must take the following keyword arguments: * `ctx`: The rule context of the calling binary or test rule. It must return a `struct` with the following fields: * `additional_outputs`: Additional outputs expected from the linking action. * `variables_extension`: A dictionary of additional crosstool variables to pass to the linking action. |
| <a id="SwiftToolchainInfo-developer_dirs"></a>developer_dirs | A list of `structs` containing the following fields:* `developer_path_label`: A `string` representing the type of developer path. * `path`: A `string` representing the path to the developer framework. |
| <a id="SwiftToolchainInfo-entry_point_linkopts_provider"></a>entry_point_linkopts_provider | A function that returns flags that should be passed to the linker to control the name of the entry point of a linked binary for rules that customize their entry point. This function must take the following keyword arguments: * `entry_point_name`: The name of the entry point function, as was passed to the Swift compiler using the `-entry-point-function-name` flag. It must return a `struct` with the following fields: * `linkopts`: A list of strings that will be passed as additional linker flags when linking a binary with a custom entry point. |
Expand Down
42 changes: 42 additions & 0 deletions doc/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ On this page:
* [swift_binary](#swift_binary)
* [swift_compiler_plugin](#swift_compiler_plugin)
* [universal_swift_compiler_plugin](#universal_swift_compiler_plugin)
* [swift_cross_import_overlay](#swift_cross_import_overlay)
* [swift_feature_allowlist](#swift_feature_allowlist)
* [swift_import](#swift_import)
* [swift_interop_hint](#swift_interop_hint)
Expand Down Expand Up @@ -165,6 +166,47 @@ swift_library(
| <a id="swift_compiler_plugin-swiftc_inputs"></a>swiftc_inputs | Additional files that are referenced using `$(location ...)` in attributes that support location expansion. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |


<a id="swift_cross_import_overlay"></a>

## swift_cross_import_overlay

<pre>
swift_cross_import_overlay(<a href="#swift_cross_import_overlay-name">name</a>, <a href="#swift_cross_import_overlay-deps">deps</a>, <a href="#swift_cross_import_overlay-bystanding_module">bystanding_module</a>, <a href="#swift_cross_import_overlay-declaring_module">declaring_module</a>)
</pre>

Declares a cross-import overlay that will be automatically added as a dependency
by the toolchain if its declaring and bystanding modules are both imported.

Since Bazel requires the dependency graph to be explicit, cross-import overlays
do not work correctly when the Swift compiler attempts to import them
automatically when they aren't represented in the graph. Users can explicitly
depend on the cross-import overlay module, but this is unsatisfying because
there is no single `import` declaration in the source code that indicates what
needs to be depended on.

To address this, the toolchain owner can define a `swift_cross_import_overlay`
target for each cross-import overlay that they wish to support and set them as
`cross_import_overlays` on the toolchain. During Swift compilation analysis, the
direct dependencies will be scanned and if any pair of dependencies matches a
cross-import overlay defined by the toolchain, the overlay module will be
automatically injected as a dependency as well.

NOTE: This rule and its associated APIs only exists to support cross-import
overlays _already defined by Apple's SDKs_. Since cross-import overlays are not
a public feature of the compiler and its design and implementation may change in
the future, this rule is not recommended for other widespread use.

**ATTRIBUTES**


| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="swift_cross_import_overlay-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="swift_cross_import_overlay-deps"></a>deps | A non-empty list of targets representing modules that should be passed as dependencies when a target depends on both `declaring_module` and `bystanding_module`. | <a href="https://bazel.build/concepts/labels">List of labels</a> | required | |
| <a id="swift_cross_import_overlay-bystanding_module"></a>bystanding_module | A label for the target representing the second of the two modules (the other being `declaring_module`) that must be imported for the cross-import overlay modules to be imported. It is completely passive in the cross-import process, having no definition with or other association to either the declaring module or the cross-import modules. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="swift_cross_import_overlay-declaring_module"></a>declaring_module | A label for the target representing the first of the two modules (the other being `bystanding_module`) that must be imported for the cross-import overlay modules to be imported. This is the module that contains the `.swiftcrossimport` overlay definition that connects it to the bystander and to the overlay modules. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |


<a id="swift_feature_allowlist"></a>

## swift_feature_allowlist
Expand Down
10 changes: 10 additions & 0 deletions swift/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ bzl_library(
],
)

bzl_library(
name = "swift_cross_import_overlay",
srcs = ["swift_cross_import_overlay.bzl"],
deps = [
":providers",
"//swift/internal:providers",
],
)

bzl_library(
name = "swift_extract_symbol_graph",
srcs = ["swift_extract_symbol_graph.bzl"],
Expand Down Expand Up @@ -271,6 +280,7 @@ bzl_library(
":swift_clang_module_aspect",
":swift_common",
":swift_compiler_plugin",
":swift_cross_import_overlay",
":swift_extract_symbol_graph",
":swift_feature_allowlist",
":swift_import",
Expand Down
17 changes: 17 additions & 0 deletions swift/internal/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ Note that some of these definitions are exported via the `swift_common` module.

load("//swift:providers.bzl", "SwiftInfo")

SwiftCrossImportOverlayInfo = provider(
doc = "Information about a cross-import overlay module.",
fields = {
"bystanding_module": """\
The name of the bystanding module in the cross-import.
""",
"declaring_module": """\
The name of the declaring module in the cross-import.
""",
"swift_infos": """\
A list of `SwiftInfo` providers that describe the cross-import overlay modules
that should be injected into the dependencies of a compilation when both the
`declaring_module` and `bystanding_module` are imported.
""",
},
)

SwiftModuleAliasesInfo = provider(
doc = "Defines a remapping of Swift module names.",
fields = {
Expand Down
6 changes: 6 additions & 0 deletions swift/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ containing the fields described above, even if those lists are empty.
"const_protocols_to_gather": """\
`File`. A JSON file specifying a list of protocols for extraction of
conformances' const values.
""",
"cross_import_overlays": """\
A list of `SwiftCrossImportOverlayInfo` providers whose `SwiftInfo` providers
will be automatically injected into the dependencies of Swift compilations if
their declaring module and bystanding module are both already declared as
dependencies.
""",
"debug_outputs_provider": """\
An optional function that provides toolchain-specific logic around the handling
Expand Down
101 changes: 101 additions & 0 deletions swift/swift_cross_import_overlay.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Copyright 2022 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Implementation of the `swift_cross_import_overlay` rule."""

load("//swift/internal:providers.bzl", "SwiftCrossImportOverlayInfo")
load(":providers.bzl", "SwiftInfo")

def _get_sole_module_name(swift_info, attr):
if len(swift_info.direct_modules) != 1:
fail(("The target specified by '{}' must define exactly one Swift " +
"and/or Clang module.").format(attr))
return swift_info.direct_modules[0].name

def _swift_cross_import_overlay_impl(ctx):
bystanding_module = _get_sole_module_name(
ctx.attr.bystanding_module[SwiftInfo],
"bystanding_module",
)
declaring_module = _get_sole_module_name(
ctx.attr.declaring_module[SwiftInfo],
"declaring_module",
)
return [
SwiftCrossImportOverlayInfo(
bystanding_module = bystanding_module,
declaring_module = declaring_module,
swift_infos = [dep[SwiftInfo] for dep in ctx.attr.deps],
),
]

swift_cross_import_overlay = rule(
attrs = {
"bystanding_module": attr.label(
doc = """
A label for the target representing the second of the two modules (the other
being `declaring_module`) that must be imported for the cross-import overlay
modules to be imported. It is completely passive in the cross-import process,
having no definition with or other association to either the declaring module or
the cross-import modules.
""",
mandatory = True,
providers = [[SwiftInfo]],
),
"declaring_module": attr.label(
doc = """\
A label for the target representing the first of the two modules (the other
being `bystanding_module`) that must be imported for the cross-import overlay
modules to be imported. This is the module that contains the `.swiftcrossimport`
overlay definition that connects it to the bystander and to the overlay modules.
""",
mandatory = True,
providers = [[SwiftInfo]],
),
"deps": attr.label_list(
allow_empty = False,
doc = """\
A non-empty list of targets representing modules that should be passed as
dependencies when a target depends on both `declaring_module` and
`bystanding_module`.
""",
mandatory = True,
providers = [[SwiftInfo]],
),
},
doc = """\
Declares a cross-import overlay that will be automatically added as a dependency
by the toolchain if its declaring and bystanding modules are both imported.
Since Bazel requires the dependency graph to be explicit, cross-import overlays
do not work correctly when the Swift compiler attempts to import them
automatically when they aren't represented in the graph. Users can explicitly
depend on the cross-import overlay module, but this is unsatisfying because
there is no single `import` declaration in the source code that indicates what
needs to be depended on.
To address this, the toolchain owner can define a `swift_cross_import_overlay`
target for each cross-import overlay that they wish to support and set them as
`cross_import_overlays` on the toolchain. During Swift compilation analysis, the
direct dependencies will be scanned and if any pair of dependencies matches a
cross-import overlay defined by the toolchain, the overlay module will be
automatically injected as a dependency as well.
NOTE: This rule and its associated APIs only exists to support cross-import
overlays _already defined by Apple's SDKs_. Since cross-import overlays are not
a public feature of the compiler and its design and implementation may change in
the future, this rule is not recommended for other widespread use.
""",
implementation = _swift_cross_import_overlay_impl,
)
20 changes: 19 additions & 1 deletion swift/toolchains/swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ load(
"SWIFT_FEATURE_USE_MODULE_WRAP",
)
load("//swift/internal:features.bzl", "features_for_build_modes")
load("//swift/internal:providers.bzl", "SwiftModuleAliasesInfo")
load(
"//swift/internal:providers.bzl",
"SwiftCrossImportOverlayInfo",
"SwiftModuleAliasesInfo",
)
load("//swift/internal:target_triples.bzl", "target_triples")
load(
"//swift/internal:utils.bzl",
Expand Down Expand Up @@ -520,6 +524,10 @@ def _swift_toolchain_impl(ctx):
clang_implicit_deps_providers = (
collect_implicit_deps_providers([])
),
cross_import_overlays = [
target[SwiftCrossImportOverlayInfo]
for target in ctx.attr.cross_import_overlays
],
debug_outputs_provider = None,
developer_dirs = [],
entry_point_linkopts_provider = _entry_point_linkopts_provider,
Expand Down Expand Up @@ -579,6 +587,16 @@ architecture-specific content, such as "x86_64" in "lib/swift/linux/x86_64".
""",
mandatory = True,
),
"cross_import_overlays": attr.label_list(
allow_empty = True,
doc = """\
A list of `swift_cross_import_overlay` targets that will be automatically
injected into the dependencies of Swift compilations if their declaring module
and bystanding module are both already declared as dependencies.
""",
mandatory = False,
providers = [[SwiftCrossImportOverlayInfo]],
),
"feature_allowlists": attr.label_list(
doc = """\
A list of `swift_feature_allowlist` targets that allow or prohibit packages from
Expand Down
20 changes: 19 additions & 1 deletion swift/toolchains/xcode_swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ load(
"SWIFT_FEATURE__FORCE_ALWAYSLINK_TRUE",
)
load("//swift/internal:features.bzl", "features_for_build_modes")
load("//swift/internal:providers.bzl", "SwiftModuleAliasesInfo")
load(
"//swift/internal:providers.bzl",
"SwiftCrossImportOverlayInfo",
"SwiftModuleAliasesInfo",
)
load("//swift/internal:target_triples.bzl", "target_triples")
load(
"//swift/internal:utils.bzl",
Expand Down Expand Up @@ -780,6 +784,10 @@ def _xcode_swift_toolchain_impl(ctx):
clang_implicit_deps_providers = collect_implicit_deps_providers(
ctx.attr.clang_implicit_deps,
),
cross_import_overlays = [
target[SwiftCrossImportOverlayInfo]
for target in ctx.attr.cross_import_overlays
],
developer_dirs = swift_toolchain_developer_paths,
entry_point_linkopts_provider = _entry_point_linkopts_provider,
feature_allowlists = [
Expand Down Expand Up @@ -852,6 +860,16 @@ implicit dependencies.
""",
providers = [[SwiftInfo]],
),
"cross_import_overlays": attr.label_list(
allow_empty = True,
doc = """\
A list of `swift_cross_import_overlay` targets that will be automatically
injected into the dependencies of Swift compilations if their declaring module
and bystanding module are both already declared as dependencies.
""",
mandatory = False,
providers = [[SwiftCrossImportOverlayInfo]],
),
"feature_allowlists": attr.label_list(
doc = """\
A list of `swift_feature_allowlist` targets that allow or prohibit packages from
Expand Down

0 comments on commit fad4faf

Please sign in to comment.