Skip to content

Commit

Permalink
Add support for emitting private swiftinterface (#1176)
Browse files Browse the repository at this point in the history
This PR adds a new feature: `swift.emit_private_swiftinterface` which
enables emitting `.private.swiftinterface` files for Swift modules.
These interface files are required when using `@_spi` and library
evolution.

## Example

```
bazel build //examples/apple/private_swiftinterface    
```

```
Target //examples/apple/private_swiftinterface:private_swiftinterface up-to-date:
  bazel-bin/examples/apple/private_swiftinterface/PrivateSwiftInterfaceLib.swiftdoc
  bazel-bin/examples/apple/private_swiftinterface/PrivateSwiftInterfaceLib.swiftinterface
  bazel-bin/examples/apple/private_swiftinterface/PrivateSwiftInterfaceLib.private.swiftinterface
  bazel-bin/examples/apple/private_swiftinterface/PrivateSwiftInterfaceLib.swiftmodule
  bazel-bin/examples/apple/private_swiftinterface/PrivateSwiftInterfaceLib.swiftsourceinfo
  bazel-bin/examples/apple/private_swiftinterface/libprivate_swiftinterface.a
```
  • Loading branch information
luispadron authored Mar 13, 2024
1 parent d4e6589 commit 477df3a
Show file tree
Hide file tree
Showing 17 changed files with 282 additions and 12 deletions.
4 changes: 3 additions & 1 deletion doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,8 @@ A provider whose type/layout is an implementation detail and should not

<pre>
swift_common.create_swift_module(<a href="#swift_common.create_swift_module-swiftdoc">swiftdoc</a>, <a href="#swift_common.create_swift_module-swiftmodule">swiftmodule</a>, <a href="#swift_common.create_swift_module-ast_files">ast_files</a>, <a href="#swift_common.create_swift_module-defines">defines</a>, <a href="#swift_common.create_swift_module-indexstore">indexstore</a>, <a href="#swift_common.create_swift_module-plugins">plugins</a>,
<a href="#swift_common.create_swift_module-swiftsourceinfo">swiftsourceinfo</a>, <a href="#swift_common.create_swift_module-swiftinterface">swiftinterface</a>, <a href="#swift_common.create_swift_module-symbol_graph">symbol_graph</a>)
<a href="#swift_common.create_swift_module-swiftsourceinfo">swiftsourceinfo</a>, <a href="#swift_common.create_swift_module-swiftinterface">swiftinterface</a>, <a href="#swift_common.create_swift_module-private_swiftinterface">private_swiftinterface</a>,
<a href="#swift_common.create_swift_module-symbol_graph">symbol_graph</a>)
</pre>

Creates a value representing a Swift module use as a Swift dependency.
Expand All @@ -492,6 +493,7 @@ Creates a value representing a Swift module use as a Swift dependency.
| <a id="swift_common.create_swift_module-plugins"></a>plugins | A list of `SwiftCompilerPluginInfo` providers representing compiler plugins that are required by this module and should be loaded by the compiler when this module is directly depended on. | `[]` |
| <a id="swift_common.create_swift_module-swiftsourceinfo"></a>swiftsourceinfo | The `.swiftsourceinfo` file emitted by the compiler for this module. May be `None` if no source info file was emitted. | `None` |
| <a id="swift_common.create_swift_module-swiftinterface"></a>swiftinterface | The `.swiftinterface` file emitted by the compiler for this module. May be `None` if no module interface file was emitted. | `None` |
| <a id="swift_common.create_swift_module-private_swiftinterface"></a>private_swiftinterface | The `.private.swiftinterface` file emitted by the compiler for this module. May be `None` if no private module interface file was emitted. | `None` |
| <a id="swift_common.create_swift_module-symbol_graph"></a>symbol_graph | A `File` representing the directory that contains the symbol graph data generated by the compiler if the `"swift.emit_symbol_graph"` feature is enabled, otherwise this will be `None`. | `None` |

**RETURNS**
Expand Down
5 changes: 3 additions & 2 deletions proto/swift_proto_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ def _swift_proto_library_impl(ctx):
files = depset(compact([
module_context.swift.swiftdoc,
module_context.swift.swiftinterface,
module_context.swift.private_swiftinterface,
module_context.swift.swiftmodule,
module_context.swift.swiftsourceinfo,
linking_output.library_to_link.static_library,
Expand Down Expand Up @@ -266,7 +267,7 @@ from which the Swift protos will be generated.
],
default = [],
doc = """\
List of additional dependencies required by the generated Swift code at compile time,
List of additional dependencies required by the generated Swift code at compile time,
whose SwiftProtoInfo will be ignored.
""",
),
Expand Down Expand Up @@ -298,7 +299,7 @@ swift_proto_library(
)
```
If your protos depend on protos from other targets, add dependencies between the
If your protos depend on protos from other targets, add dependencies between the
swift_proto_library targets which mirror the dependencies between the proto targets.
```python
Expand Down
6 changes: 6 additions & 0 deletions swift/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ bool_setting(
build_setting_default = False,
)

# Configuration setting for enabling the generation of private swiftinterface files (e.g. those for `@_spi`).
bool_setting(
name = "emit_private_swiftinterface",
build_setting_default = False,
)

# NOTE: Enabling this flag will transition --proto_compiler to
# //tools/protoc_wrapper:protoc for swift_grpc_library and swift_proto_library,
# unless you set --proto_compiler manually.
Expand Down
5 changes: 5 additions & 0 deletions swift/deprecated_proto/swift_protoc_gen_aspect.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ load(
)
load(
"//swift/internal:feature_names.bzl",
"SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE",
"SWIFT_FEATURE_EMIT_SWIFTINTERFACE",
"SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION",
"SWIFT_FEATURE_ENABLE_TESTING",
Expand Down Expand Up @@ -406,6 +407,10 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx):
extra_features.append(SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION)
extra_features.append(SWIFT_FEATURE_EMIT_SWIFTINTERFACE)

if aspect_ctx.attr._config_emit_private_swiftinterface[BuildSettingInfo].value:
extra_features.append(SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION)
extra_features.append(SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE)

# Compile the generated Swift sources and produce a static library and a
# .swiftmodule as outputs. In addition to the other proto deps, we also
# pass support libraries like the SwiftProtobuf runtime as deps to the
Expand Down
7 changes: 5 additions & 2 deletions swift/internal/attrs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ support location expansion.
"always_include_developer_search_paths": attr.bool(
default = False,
doc = """\
If `True`, the developer framework search paths will be added to the compilation
command. This enables a Swift module to access `XCTest` without having to mark
If `True`, the developer framework search paths will be added to the compilation
command. This enables a Swift module to access `XCTest` without having to mark
the target as `testonly = True`.
""",
mandatory = False,
Expand All @@ -186,6 +186,9 @@ def swift_config_attrs():
configuration settings.
"""
return {
"_config_emit_private_swiftinterface": attr.label(
default = "@build_bazel_rules_swift//swift:emit_private_swiftinterface",
),
"_config_emit_swiftinterface": attr.label(
default = "@build_bazel_rules_swift//swift:emit_swiftinterface",
),
Expand Down
34 changes: 34 additions & 0 deletions swift/internal/compiling.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ load(
"SWIFT_FEATURE_DISABLE_SYSTEM_INDEX",
"SWIFT_FEATURE_EMIT_BC",
"SWIFT_FEATURE_EMIT_C_MODULE",
"SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE",
"SWIFT_FEATURE_EMIT_SWIFTINTERFACE",
"SWIFT_FEATURE_EMIT_SYMBOL_GRAPH",
"SWIFT_FEATURE_ENABLE_BATCH_MODE",
Expand Down Expand Up @@ -363,6 +364,17 @@ def compile_action_configs(
SWIFT_FEATURE_EMIT_SWIFTINTERFACE,
],
),
swift_toolchain_config.action_config(
actions = [
swift_action_names.COMPILE,
swift_action_names.DERIVE_FILES,
],
configurators = [_emit_private_module_interface_path_configurator],
features = [
SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION,
SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE,
],
),

# Configure the path to the emitted *-Swift.h file.
swift_toolchain_config.action_config(
Expand Down Expand Up @@ -1351,6 +1363,10 @@ def _emit_module_interface_path_configurator(prerequisites, args):
"""Adds the `.swiftinterface` output path to the command line."""
args.add("-emit-module-interface-path", prerequisites.swiftinterface_file)

def _emit_private_module_interface_path_configurator(prerequisites, args):
"""Adds the `.private.swiftinterface` output path to the command line."""
args.add("-emit-private-module-interface-path", prerequisites.private_swiftinterface_file)

def _emit_objc_header_path_configurator(prerequisites, args):
"""Adds the generated header output path to the command line."""
if prerequisites.generated_header_file:
Expand Down Expand Up @@ -2375,6 +2391,7 @@ def compile(
if split_derived_file_generation:
all_compile_outputs = compact([
compile_outputs.swiftinterface_file,
compile_outputs.private_swiftinterface_file,
compile_outputs.indexstore_directory,
compile_outputs.macro_expansion_directory,
]) + compile_outputs.object_files
Expand All @@ -2398,6 +2415,7 @@ def compile(
compile_outputs.swiftmodule_file,
compile_outputs.swiftdoc_file,
compile_outputs.swiftinterface_file,
compile_outputs.private_swiftinterface_file,
compile_outputs.swiftsourceinfo_file,
compile_outputs.generated_header_file,
compile_outputs.indexstore_directory,
Expand Down Expand Up @@ -2628,6 +2646,7 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\
defines = defines,
indexstore = compile_outputs.indexstore_directory,
plugins = depset(plugins),
private_swiftinterface = compile_outputs.private_swiftinterface_file,
swiftdoc = compile_outputs.swiftdoc_file,
swiftinterface = compile_outputs.swiftinterface_file,
swiftmodule = compile_outputs.swiftmodule_file,
Expand Down Expand Up @@ -2964,6 +2983,20 @@ def _declare_compile_outputs(
else:
swiftinterface_file = None

if are_all_features_enabled(
feature_configuration = feature_configuration,
feature_names = [
SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION,
SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE,
],
):
private_swiftinterface_file = derived_files.private_swiftinterface(
actions = actions,
module_name = module_name,
)
else:
private_swiftinterface_file = None

# If requested, generate the Swift header for this library so that it can be
# included by Objective-C code that depends on it.
if generated_header_name:
Expand Down Expand Up @@ -3110,6 +3143,7 @@ def _declare_compile_outputs(
generated_module_map_file = generated_module_map,
indexstore_directory = indexstore_directory,
macro_expansion_directory = macro_expansion_directory,
private_swiftinterface_file = private_swiftinterface_file,
symbol_graph_directory = symbol_graph_directory,
object_files = object_files,
output_file_map = output_file_map,
Expand Down
13 changes: 13 additions & 0 deletions swift/internal/derived_files.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,18 @@ def _swiftinterface(actions, module_name):
"""
return actions.declare_file("{}.swiftinterface".format(module_name))

def _private_swiftinterface(actions, module_name):
"""Declares a file for the private Swift interface created by a compilation rule.
Args:
actions: The context's actions object.
module_name: The name of the module being built.
Returns:
The declared `File`.
"""
return actions.declare_file("{}.private.swiftinterface".format(module_name))

def _swiftmodule(actions, module_name):
"""Declares a file for the Swift module created by a compilation rule.
Expand Down Expand Up @@ -344,6 +356,7 @@ derived_files = struct(
module_map = _module_map,
modulewrap_object = _modulewrap_object,
precompiled_module = _precompiled_module,
private_swiftinterface = _private_swiftinterface,
reexport_modules_src = _reexport_modules_src,
static_archive = _static_archive,
swiftc_output_file_map = _swiftc_output_file_map,
Expand Down
4 changes: 4 additions & 0 deletions swift/internal/feature_names.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ SWIFT_FEATURE_EMIT_BC = "swift.emit_bc"
# invocation.
SWIFT_FEATURE_EMIT_SWIFTINTERFACE = "swift.emit_swiftinterface"

# If enabled, requests the private swiftinterface file to be built on the
# swiftc invocation.
SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE = "swift.emit_private_swiftinterface"

# If enabled, the toolchain supports private deps (implementation-only imports).
# This allows Bazel to avoid propagating swiftmodules of such dependencies
# higher in the dependency graph than they need to be.
Expand Down
13 changes: 9 additions & 4 deletions swift/internal/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Returns:
""",
"compiler_deps": """\
List of targets providing SwiftInfo and CcInfo.
These are added as dependencies to the swift compile action of the swift_proto_library.
These are added as dependencies to the swift compile action of the swift_proto_library.
Typically these are proto runtime libraries.
Well Known Types should be added as dependencies of the swift_proto_library
Expand All @@ -166,12 +166,12 @@ files to Swift modules. This allows messages that reference messages in other
libraries to import those modules in generated code.
""",
"direct_pbswift_files": """\
`list` of `File`s. The Swift source files (e.g. `.pb.swift`) generated from the
`list` of `File`s. The Swift source files (e.g. `.pb.swift`) generated from the
`ProtoInfo` providers of the direct proto dependencies of the `swift_proto_library` target.
""",
"pbswift_files": """\
`depset` of `File`s. The Swift source files (e.g. `.pb.swift`) generated from the
`ProtoInfo` providers of the direct and transitive transitive proto dependencies
`depset` of `File`s. The Swift source files (e.g. `.pb.swift`) generated from the
`ProtoInfo` providers of the direct and transitive transitive proto dependencies
of the `swift_proto_library` target.
""",
},
Expand Down Expand Up @@ -447,6 +447,7 @@ def create_swift_module(
plugins = [],
swiftsourceinfo = None,
swiftinterface = None,
private_swiftinterface = None,
symbol_graph = None):
"""Creates a value representing a Swift module use as a Swift dependency.
Expand All @@ -464,6 +465,9 @@ def create_swift_module(
plugins: A list of `SwiftCompilerPluginInfo` providers representing
compiler plugins that are required by this module and should be
loaded by the compiler when this module is directly depended on.
private_swiftinterface: The `.private.swiftinterface` file emitted by
the compiler for this module. May be `None` if no private module
interface file was emitted.
swiftsourceinfo: The `.swiftsourceinfo` file emitted by the compiler for
this module. May be `None` if no source info file was emitted.
swiftinterface: The `.swiftinterface` file emitted by the compiler for
Expand All @@ -482,6 +486,7 @@ def create_swift_module(
ast_files = tuple(ast_files),
defines = tuple(defines),
plugins = plugins,
private_swiftinterface = private_swiftinterface,
indexstore = indexstore,
swiftdoc = swiftdoc,
swiftinterface = swiftinterface,
Expand Down
6 changes: 6 additions & 0 deletions swift/internal/swift_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ load(
)
load(
":feature_names.bzl",
"SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE",
"SWIFT_FEATURE_EMIT_SWIFTINTERFACE",
"SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION",
"SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS",
Expand Down Expand Up @@ -124,6 +125,10 @@ def _swift_library_impl(ctx):
extra_features.append(SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION)
extra_features.append(SWIFT_FEATURE_EMIT_SWIFTINTERFACE)

if ctx.attr._config_emit_private_swiftinterface[BuildSettingInfo].value:
extra_features.append(SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION)
extra_features.append(SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE)

module_name = ctx.attr.module_name
if not module_name:
module_name = swift_common.derive_module_name(ctx.label)
Expand Down Expand Up @@ -228,6 +233,7 @@ def _swift_library_impl(ctx):
module_context.clang.precompiled_module,
module_context.swift.swiftdoc,
module_context.swift.swiftinterface,
module_context.swift.private_swiftinterface,
module_context.swift.swiftmodule,
module_context.swift.swiftsourceinfo,
linking_output.library_to_link.static_library,
Expand Down
1 change: 1 addition & 0 deletions swift/internal/swift_module_alias.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def _swift_module_alias_impl(ctx):
files = depset(compact([
module_context.swift.swiftdoc,
module_context.swift.swiftinterface,
module_context.swift.private_swiftinterface,
module_context.swift.swiftmodule,
linking_output.library_to_link.pic_static_library,
linking_output.library_to_link.static_library,
Expand Down
3 changes: 3 additions & 0 deletions test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ load(":module_interface_tests.bzl", "module_interface_test_suite")
load(":output_file_map_tests.bzl", "output_file_map_test_suite")
load(":pch_output_dir_tests.bzl", "pch_output_dir_test_suite")
load(":private_deps_tests.bzl", "private_deps_test_suite")
load(":private_swiftinterface_tests.bzl", "private_swiftinterface_test_suite")
load(":split_derived_files_tests.bzl", "split_derived_files_test_suite")
load(":swift_through_non_swift_tests.bzl", "swift_through_non_swift_test_suite")
load(":utils_tests.bzl", "utils_test_suite")
Expand Down Expand Up @@ -51,6 +52,8 @@ split_derived_files_test_suite(name = "split_derived_files")

pch_output_dir_test_suite(name = "pch_output_dir_settings")

private_swiftinterface_test_suite(name = "private_swiftinterface")

explicit_modules_test_suite(name = "explicit_modules")

xctest_runner_test_suite(name = "xctest_runner")
Expand Down
Loading

0 comments on commit 477df3a

Please sign in to comment.