From 477df3a4576e5594a86f27b96950c17f9fab3cea Mon Sep 17 00:00:00 2001 From: Luis Padron Date: Wed, 13 Mar 2024 12:49:14 -0400 Subject: [PATCH] Add support for emitting private swiftinterface (#1176) 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 ``` --- doc/api.md | 4 +- proto/swift_proto_library.bzl | 5 +- swift/BUILD | 6 ++ .../swift_protoc_gen_aspect.bzl | 5 ++ swift/internal/attrs.bzl | 7 +- swift/internal/compiling.bzl | 34 ++++++++ swift/internal/derived_files.bzl | 13 ++++ swift/internal/feature_names.bzl | 4 + swift/internal/providers.bzl | 13 +++- swift/internal/swift_library.bzl | 6 ++ swift/internal/swift_module_alias.bzl | 1 + test/BUILD | 3 + test/fixtures/private_swiftinterface/BUILD | 78 +++++++++++++++++++ .../fixtures/private_swiftinterface/Lib.swift | 22 ++++++ .../private_swiftinterface/main.swift | 20 +++++ test/private_swiftinterface_tests.bzl | 54 +++++++++++++ .../swift_library_artifact_collector.bzl | 19 ++++- 17 files changed, 282 insertions(+), 12 deletions(-) create mode 100644 test/fixtures/private_swiftinterface/BUILD create mode 100644 test/fixtures/private_swiftinterface/Lib.swift create mode 100644 test/fixtures/private_swiftinterface/main.swift create mode 100644 test/private_swiftinterface_tests.bzl diff --git a/doc/api.md b/doc/api.md index 3551443b4..d5d386a69 100644 --- a/doc/api.md +++ b/doc/api.md @@ -474,7 +474,8 @@ A provider whose type/layout is an implementation detail and should not
 swift_common.create_swift_module(swiftdoc, swiftmodule, ast_files, defines, indexstore, plugins,
-                                 swiftsourceinfo, swiftinterface, symbol_graph)
+                                 swiftsourceinfo, swiftinterface, private_swiftinterface,
+                                 symbol_graph)
 
Creates a value representing a Swift module use as a Swift dependency. @@ -492,6 +493,7 @@ Creates a value representing a Swift module use as a Swift dependency. | 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. | `[]` | | swiftsourceinfo | The `.swiftsourceinfo` file emitted by the compiler for this module. May be `None` if no source info file was emitted. | `None` | | swiftinterface | The `.swiftinterface` file emitted by the compiler for this module. May be `None` if no module interface file was emitted. | `None` | +| 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` | | 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** diff --git a/proto/swift_proto_library.bzl b/proto/swift_proto_library.bzl index 2a926f203..e92b73c13 100644 --- a/proto/swift_proto_library.bzl +++ b/proto/swift_proto_library.bzl @@ -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, @@ -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. """, ), @@ -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 diff --git a/swift/BUILD b/swift/BUILD index bf77237cc..f4439ad8b 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -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. diff --git a/swift/deprecated_proto/swift_protoc_gen_aspect.bzl b/swift/deprecated_proto/swift_protoc_gen_aspect.bzl index 0a49fa85a..8eefe38b7 100644 --- a/swift/deprecated_proto/swift_protoc_gen_aspect.bzl +++ b/swift/deprecated_proto/swift_protoc_gen_aspect.bzl @@ -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", @@ -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 diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index 176126e4d..42f8f13c4 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -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, @@ -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", ), diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index aac49c8e0..676c066a9 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -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", @@ -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( @@ -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: @@ -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 @@ -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, @@ -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, @@ -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: @@ -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, diff --git a/swift/internal/derived_files.bzl b/swift/internal/derived_files.bzl index 40b6d0705..ddf57d7a7 100644 --- a/swift/internal/derived_files.bzl +++ b/swift/internal/derived_files.bzl @@ -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. @@ -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, diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 18c45fb30..f92ef6033 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -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. diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index e936533a6..e39f07dda 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -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 @@ -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. """, }, @@ -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. @@ -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 @@ -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, diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index 28c270d00..aec321b9f 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -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", @@ -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) @@ -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, diff --git a/swift/internal/swift_module_alias.bzl b/swift/internal/swift_module_alias.bzl index 8a25e8de5..7a754e50b 100644 --- a/swift/internal/swift_module_alias.bzl +++ b/swift/internal/swift_module_alias.bzl @@ -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, diff --git a/test/BUILD b/test/BUILD index 11b768b0d..5b5dc2638 100644 --- a/test/BUILD +++ b/test/BUILD @@ -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") @@ -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") diff --git a/test/fixtures/private_swiftinterface/BUILD b/test/fixtures/private_swiftinterface/BUILD new file mode 100644 index 000000000..11f932c84 --- /dev/null +++ b/test/fixtures/private_swiftinterface/BUILD @@ -0,0 +1,78 @@ +# Copyright 2024 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. + +"""A rule to collect the outputs of a `swift_library`. + +This rule is used in tests to simulate "pre-built" artifacts without having to +check them in directly. +""" + +load( + "//swift:swift.bzl", + "swift_binary", + "swift_import", + "swift_library", +) +load( + "//test/fixtures:common.bzl", + "FIXTURE_TAGS", +) +load( + "//test/rules:swift_library_artifact_collector.bzl", + "swift_library_artifact_collector", +) + +package( + default_testonly = True, + default_visibility = ["//test:__subpackages__"], +) + +licenses(["notice"]) + +swift_binary( + name = "client", + srcs = ["main.swift"], + tags = FIXTURE_TAGS, + deps = [":private_swiftinterface_import"], +) + +swift_import( + name = "private_swiftinterface_import", + archives = [":private_swiftinterface_outputs/libPrivateSwiftInterface.a"], + module_name = "PrivateSwiftInterface", + swiftdoc = ":private_swiftinterface_outputs/PrivateSwiftInterface.swiftdoc", + # Using the private interface allows using both the normal and private interfaces of a module. + # Only one swiftinterface is allowed per module, so we can't use both at the same time. + # This tests that using the private interface allows a dependent module to use an `@_spi` symbol. + swiftinterface = ":private_swiftinterface_outputs/PrivateSwiftInterface.private.swiftinterface", + tags = FIXTURE_TAGS, +) + +swift_library( + name = "private_swiftinterface", + srcs = ["Lib.swift"], + module_name = "PrivateSwiftInterface", + tags = FIXTURE_TAGS, +) + +swift_library_artifact_collector( + name = "private_swiftinterface_artifact_collector", + private_swiftinterface = "private_swiftinterface_outputs/PrivateSwiftInterface.private.swiftinterface", + static_library = "private_swiftinterface_outputs/libPrivateSwiftInterface.a", + swiftdoc = "private_swiftinterface_outputs/PrivateSwiftInterface.swiftdoc", + swiftinterface = "private_swiftinterface_outputs/PrivateSwiftInterface.swiftinterface", + tags = FIXTURE_TAGS, + target = ":private_swiftinterface", + target_compatible_with = ["@platforms//os:macos"], +) diff --git a/test/fixtures/private_swiftinterface/Lib.swift b/test/fixtures/private_swiftinterface/Lib.swift new file mode 100644 index 000000000..fc252c697 --- /dev/null +++ b/test/fixtures/private_swiftinterface/Lib.swift @@ -0,0 +1,22 @@ +// Copyright 2024 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. + +@_spi(SPILib) +public enum SPIType: String { + case spi = "spi" +} + +public enum NonSPIType: String { + case nonSPI = "nonSPI" +} diff --git a/test/fixtures/private_swiftinterface/main.swift b/test/fixtures/private_swiftinterface/main.swift new file mode 100644 index 000000000..d451262c0 --- /dev/null +++ b/test/fixtures/private_swiftinterface/main.swift @@ -0,0 +1,20 @@ +// Copyright 2024 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. + +@_spi(SPILib) import PrivateSwiftInterface + +print(""" +SPIType: \(SPIType.spi.rawValue) +NonSPIType: \(NonSPIType.nonSPI.rawValue) +""") diff --git a/test/private_swiftinterface_tests.bzl b/test/private_swiftinterface_tests.bzl new file mode 100644 index 000000000..572208a16 --- /dev/null +++ b/test/private_swiftinterface_tests.bzl @@ -0,0 +1,54 @@ +# Copyright 2024 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. + +"""Tests for interoperability with `cc_library`-specific features.""" + +load( + "@bazel_skylib//rules:build_test.bzl", + "build_test", +) +load( + "@build_bazel_rules_swift//test/rules:action_command_line_test.bzl", + "make_action_command_line_test_rule", +) + +private_swiftinterface_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:features": [ + "swift.emit_private_swiftinterface", + ], + }, +) + +def private_swiftinterface_test_suite(name): + """Test suite for features that compile Swift module interfaces. + + Args: + name: The base name to be used in targets created by this macro. + """ + + # Verify that a `swift_binary` builds properly when depending on a + # `swift_import` target that references a `.private.swiftinterface` file. + build_test( + name = "{}_swift_binary_imports_private_swiftinterface".format(name), + targets = [ + "@build_bazel_rules_swift//test/fixtures/private_swiftinterface:client", + ], + tags = [name], + ) + + native.test_suite( + name = name, + tags = [name], + ) diff --git a/test/rules/swift_library_artifact_collector.bzl b/test/rules/swift_library_artifact_collector.bzl index a836f3a1b..16c5dfe7d 100644 --- a/test/rules/swift_library_artifact_collector.bzl +++ b/test/rules/swift_library_artifact_collector.bzl @@ -24,16 +24,22 @@ load( ) def _swiftinterface_transition_impl(_settings, attr): - # If the `.swiftinterface` file is requested, apply the setting that causes - # the rule to generate it. return { + # If the `.private.swiftinterface` file is requested, apply the setting that causes + # the rule to generate it. + "@build_bazel_rules_swift//swift:emit_private_swiftinterface": attr.private_swiftinterface != None, + # If the `.swiftinterface` file is requested, apply the setting that causes + # the rule to generate it. "@build_bazel_rules_swift//swift:emit_swiftinterface": attr.swiftinterface != None, } _swiftinterface_transition = transition( implementation = _swiftinterface_transition_impl, inputs = [], - outputs = ["@build_bazel_rules_swift//swift:emit_swiftinterface"], + outputs = [ + "@build_bazel_rules_swift//swift:emit_private_swiftinterface", + "@build_bazel_rules_swift//swift:emit_swiftinterface", + ], ) def _copy_file(actions, source, destination): @@ -78,6 +84,12 @@ def _swift_library_artifact_collector_impl(ctx): source = swift_info.direct_modules[0].swift.swiftdoc, destination = ctx.outputs.swiftdoc, ) + if ctx.outputs.private_swiftinterface: + _copy_file( + ctx.actions, + source = swift_info.direct_modules[0].swift.private_swiftinterface, + destination = ctx.outputs.private_swiftinterface, + ) if ctx.outputs.swiftinterface: _copy_file( ctx.actions, @@ -94,6 +106,7 @@ def _swift_library_artifact_collector_impl(ctx): swift_library_artifact_collector = rule( attrs = { + "private_swiftinterface": attr.output(mandatory = False), "static_library": attr.output(mandatory = False), "swiftdoc": attr.output(mandatory = False), "swiftinterface": attr.output(mandatory = False),