Skip to content

Commit ea2d4bd

Browse files
authored
Add swift_proto_library_group rule (#1173)
1 parent 72347ab commit ea2d4bd

29 files changed

+1139
-209
lines changed

doc/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ _DOC_SRCS = {
3232
"swift_package_configuration",
3333
"swift_test",
3434
"swift_proto_library",
35+
"swift_proto_library_group",
3536
"swift_proto_compiler",
3637
"deprecated_swift_grpc_library",
3738
"deprecated_swift_proto_library",

doc/doc.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ load(
4141
# rules
4242
_swift_proto_compiler = "swift_proto_compiler",
4343
_swift_proto_library = "swift_proto_library",
44+
_swift_proto_library_group = "swift_proto_library_group",
4445
)
4546
load(
4647
"//swift:swift.bzl",
@@ -77,6 +78,7 @@ SwiftProtoCompilerInfo = _SwiftProtoCompilerInfo
7778
SwiftProtoInfo = _SwiftProtoInfo
7879
swift_proto_compiler = _swift_proto_compiler
7980
swift_proto_library = _swift_proto_library
81+
swift_proto_library_group = _swift_proto_library_group
8082

8183
# swift symbols
8284
swift_common = _swift_common

doc/providers.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ has reasonable defaults for any fields not explicitly set.
6262
## SwiftProtoCompilerInfo
6363

6464
<pre>
65-
SwiftProtoCompilerInfo(<a href="#SwiftProtoCompilerInfo-compile">compile</a>, <a href="#SwiftProtoCompilerInfo-compiler_deps">compiler_deps</a>, <a href="#SwiftProtoCompilerInfo-internal">internal</a>)
65+
SwiftProtoCompilerInfo(<a href="#SwiftProtoCompilerInfo-bundled_proto_paths">bundled_proto_paths</a>, <a href="#SwiftProtoCompilerInfo-compile">compile</a>, <a href="#SwiftProtoCompilerInfo-compiler_deps">compiler_deps</a>, <a href="#SwiftProtoCompilerInfo-internal">internal</a>)
6666
</pre>
6767

6868
Provides information needed to generate Swift code from `ProtoInfo` providers
@@ -72,7 +72,8 @@ Provides information needed to generate Swift code from `ProtoInfo` providers
7272

7373
| Name | Description |
7474
| :------------- | :------------- |
75-
| <a id="SwiftProtoCompilerInfo-compile"></a>compile | A function which compiles Swift source files from `ProtoInfo` providers.<br><br>Args: ctx: the `swift_proto_library` target's context swift_proto_compiler_info: this `SwiftProtoCompilerInfo` provider additional_compiler_info: information passed from the `swift_proto_library` target to the compiler proto_infos: the list of `ProtoInfo` providers to compile module_mappings: the module_mappings field of the `SwiftProtoInfo` for the `swift_proto_library` target<br><br>Returns: A list of .swift Files generated by the compiler. |
75+
| <a id="SwiftProtoCompilerInfo-bundled_proto_paths"></a>bundled_proto_paths | List of proto paths for which to skip generation because they're built into the modules imported by the generated Swift proto code, e.g., SwiftProtobuf. |
76+
| <a id="SwiftProtoCompilerInfo-compile"></a>compile | A function which compiles Swift source files from `ProtoInfo` providers.<br><br>Args: label: The label of the target for which the Swift files are being generated. actions: The actions object used to declare the files to be generated and the actions that generate them. swift_proto_compiler_info: This `SwiftProtoCompilerInfo` provider. additional_compiler_info: Additional information passed from the target target to the compiler. proto_infos: The list of `ProtoInfo` providers to compile. module_mappings: The module_mappings field of the `SwiftProtoInfo` for the target.<br><br>Returns: A list of .swift Files generated by the compiler. |
7677
| <a id="SwiftProtoCompilerInfo-compiler_deps"></a>compiler_deps | List of targets providing SwiftInfo and CcInfo. These are added as dependencies to the swift compile action of the swift_proto_library. Typically these are proto runtime libraries.<br><br>Well Known Types should be added as dependencies of the swift_proto_library targets as needed to avoid compiling them unnecessarily. |
7778
| <a id="SwiftProtoCompilerInfo-internal"></a>internal | Opaque struct passing information from the compiler target to the compile function. |
7879

doc/rules.md

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ On this page:
3131
* [swift_package_configuration](#swift_package_configuration)
3232
* [swift_test](#swift_test)
3333
* [swift_proto_library](#swift_proto_library)
34+
* [swift_proto_library_group](#swift_proto_library_group)
3435
* [swift_proto_compiler](#swift_proto_compiler)
3536
* [deprecated_swift_grpc_library](#deprecated_swift_grpc_library)
3637
* [deprecated_swift_proto_library](#deprecated_swift_proto_library)
@@ -594,8 +595,8 @@ target's label is included by the package specifications in the configuration.
594595
## swift_proto_compiler
595596

596597
<pre>
597-
swift_proto_compiler(<a href="#swift_proto_compiler-name">name</a>, <a href="#swift_proto_compiler-deps">deps</a>, <a href="#swift_proto_compiler-plugin">plugin</a>, <a href="#swift_proto_compiler-plugin_name">plugin_name</a>, <a href="#swift_proto_compiler-plugin_option_allowlist">plugin_option_allowlist</a>, <a href="#swift_proto_compiler-plugin_options">plugin_options</a>,
598-
<a href="#swift_proto_compiler-protoc">protoc</a>, <a href="#swift_proto_compiler-suffixes">suffixes</a>)
598+
swift_proto_compiler(<a href="#swift_proto_compiler-name">name</a>, <a href="#swift_proto_compiler-deps">deps</a>, <a href="#swift_proto_compiler-bundled_proto_paths">bundled_proto_paths</a>, <a href="#swift_proto_compiler-plugin">plugin</a>, <a href="#swift_proto_compiler-plugin_name">plugin_name</a>, <a href="#swift_proto_compiler-plugin_option_allowlist">plugin_option_allowlist</a>,
599+
<a href="#swift_proto_compiler-plugin_options">plugin_options</a>, <a href="#swift_proto_compiler-protoc">protoc</a>, <a href="#swift_proto_compiler-suffixes">suffixes</a>)
599600
</pre>
600601

601602

@@ -607,6 +608,7 @@ swift_proto_compiler(<a href="#swift_proto_compiler-name">name</a>, <a href="#sw
607608
| :------------- | :------------- | :------------- | :------------- | :------------- |
608609
| <a id="swift_proto_compiler-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
609610
| <a id="swift_proto_compiler-deps"></a>deps | List of targets providing SwiftInfo and CcInfo. Added as implicit dependencies for any swift_proto_library using this compiler. Typically, these are Well Known Types and proto runtime libraries. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
611+
| <a id="swift_proto_compiler-bundled_proto_paths"></a>bundled_proto_paths | List of proto paths for which to skip generation because they're built into the modules imported by the generated Swift proto code, e.g., SwiftProtobuf. | List of strings | optional | `["google/protobuf/any.proto", "google/protobuf/api.proto", "google/protobuf/descriptor.proto", "google/protobuf/duration.proto", "google/protobuf/empty.proto", "google/protobuf/field_mask.proto", "google/protobuf/source_context.proto", "google/protobuf/struct.proto", "google/protobuf/timestamp.proto", "google/protobuf/type.proto", "google/protobuf/wrappers.proto"]` |
610612
| <a id="swift_proto_compiler-plugin"></a>plugin | A proto compiler plugin executable binary.<br><br>For example: "//tools/protoc_wrapper:protoc-gen-grpc-swift" "//tools/protoc_wrapper:ProtoCompilerPlugin" | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
611613
| <a id="swift_proto_compiler-plugin_name"></a>plugin_name | Name of the proto compiler plugin passed to protoc.<br><br>For example:<br><br><pre><code>protoc --plugin=protoc-gen-NAME=path/to/plugin/binary</code></pre><br><br>This name will be used to prefix the option and output directory arguments. E.g.:<br><br><pre><code>protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR --NAME_opt=Visibility=Public</code></pre><br><br>See the [protobuf API reference](https://protobuf.dev/reference/cpp/api-docs/google.protobuf.compiler.plugin) for more information. | String | required | |
612614
| <a id="swift_proto_compiler-plugin_option_allowlist"></a>plugin_option_allowlist | Allowlist of options allowed by the plugin. This is used to filter out any irrelevant plugin options passed down to the compiler from the library, which is especially useful when using multiple plugins in combination like GRPC and SwiftProtobuf. | List of strings | required | |
@@ -690,6 +692,84 @@ swift_proto_library(
690692
| <a id="swift_proto_library-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 | `[]` |
691693

692694

695+
<a id="swift_proto_library_group"></a>
696+
697+
## swift_proto_library_group
698+
699+
<pre>
700+
swift_proto_library_group(<a href="#swift_proto_library_group-name">name</a>, <a href="#swift_proto_library_group-compiler">compiler</a>, <a href="#swift_proto_library_group-proto">proto</a>)
701+
</pre>
702+
703+
Generates a collection of Swift static library from a target producing `ProtoInfo` and its dependencies.
704+
705+
This rule is intended to facilitate migration from the deprecated swift proto library rules to the new ones.
706+
Unlike `swift_proto_library` which is a drop-in-replacement for `swift_library`,
707+
this rule uses an aspect over the direct proto library dependency and its transitive dependencies,
708+
compiling each into a swift static library.
709+
710+
For example, in the following targets, the `proto_library_group_swift_proto` target only depends on
711+
`package_2_proto` target, and this transitively depends on `package_1_proto`.
712+
713+
When used as a dependency from a `swift_library` or `swift_binary` target,
714+
two modules generated from these proto library targets are visible.
715+
716+
Because these are derived from the proto library targets via an aspect, though,
717+
you cannot customize many of the attributes including the swift proto compiler targets or
718+
the module names. The module names are derived from the proto library names.
719+
720+
In this case, the module names are:
721+
```
722+
import examples_xplatform_proto_library_group_package_1_package_1_proto
723+
import examples_xplatform_proto_library_group_package_2_package_2_proto
724+
```
725+
726+
For this reason, we would encourage new consumers of the proto rules to use
727+
`swift_proto_library` when possible.
728+
729+
```python
730+
proto_library(
731+
name = "package_1_proto",
732+
srcs = glob(["*.proto"]),
733+
visibility = ["//visibility:public"],
734+
)
735+
736+
...
737+
738+
proto_library(
739+
name = "package_2_proto",
740+
srcs = glob(["*.proto"]),
741+
visibility = ["//visibility:public"],
742+
deps = ["//examples/xplatform/proto_library_group/package_1:package_1_proto"],
743+
)
744+
745+
...
746+
747+
swift_proto_library_group(
748+
name = "proto_library_group_swift_proto",
749+
proto = "//examples/xplatform/proto_library_group/package_2:package_2_proto",
750+
)
751+
752+
...
753+
754+
swift_binary(
755+
name = "proto_library_group_example",
756+
srcs = ["main.swift"],
757+
deps = [
758+
":proto_library_group_swift_proto",
759+
],
760+
)
761+
```
762+
763+
**ATTRIBUTES**
764+
765+
766+
| Name | Description | Type | Mandatory | Default |
767+
| :------------- | :------------- | :------------- | :------------- | :------------- |
768+
| <a id="swift_proto_library_group-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
769+
| <a id="swift_proto_library_group-compiler"></a>compiler | A `swift_proto_compiler` target (or target producing `SwiftProtoCompilerInfo`), from which the Swift protos will be generated. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `"@build_bazel_rules_swift//proto/compilers:swift_proto"` |
770+
| <a id="swift_proto_library_group-proto"></a>proto | Exactly one `proto_library` target (or target producing `ProtoInfo`), from which the Swift source files should be generated. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
771+
772+
693773
<a id="swift_test"></a>
694774

695775
## swift_test

examples/xplatform/custom_swift_proto_compiler/rules/custom_swift_proto_compiler.bzl

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,19 @@ load(
3030
"SwiftInfo",
3131
)
3232

33-
def _custom_swift_proto_compile(ctx, swift_proto_compiler_info, additional_compiler_info, proto_infos, module_mappings):
33+
def _custom_swift_proto_compile(label, actions, swift_proto_compiler_info, additional_compiler_info, proto_infos, module_mappings):
3434
"""Compiles Swift source files from `ProtoInfo` providers.
3535
3636
Args:
37-
ctx: the `swift_proto_library` target's context
38-
swift_proto_compiler_info: this `SwiftProtoCompilerInfo` provider
39-
additional_compiler_info: information passed from the `swift_proto_library` target to the compiler
40-
proto_infos: the list of `ProtoInfo` providers to compile
41-
module_mappings: the module_mappings field of the `SwiftProtoInfo` for the `swift_proto_library` target
37+
label: The label of the target for which the Swift files are being generated.
38+
actions: The actions object used to declare the files to be generated and the actions that generate them.
39+
swift_proto_compiler_info: This `SwiftProtoCompilerInfo` provider.
40+
additional_compiler_info: Additional information passed from the target target to the compiler.
41+
proto_infos: The list of `ProtoInfo` providers to compile.
42+
module_mappings: The module_mappings field of the `SwiftProtoInfo` for the target.
4243
4344
Returns:
44-
A list of .swift Files generated by the compiler.
45+
A `list` of `.swift` `File`s generated by the compiler.
4546
"""
4647

4748
# Declare the Swift files that will be generated:
@@ -68,8 +69,8 @@ def _custom_swift_proto_compile(ctx, swift_proto_compiler_info, additional_compi
6869

6970
# Declare the Swift source files that will be generated:
7071
base_swift_src_path = paths.replace_extension(path, ".swift")
71-
swift_src_path = paths.join(ctx.label.name, base_swift_src_path)
72-
swift_src = ctx.actions.declare_file(swift_src_path)
72+
swift_src_path = paths.join(label.name, base_swift_src_path)
73+
swift_src = actions.declare_file(swift_src_path)
7374
swift_srcs.append(swift_src)
7475
transitive_proto_srcs = depset(direct = [], transitive = transitive_proto_srcs_list)
7576

@@ -78,15 +79,15 @@ def _custom_swift_proto_compile(ctx, swift_proto_compiler_info, additional_compi
7879
swift_srcs.extend([])
7980

8081
# Build the arguments for compiler:
81-
arguments = ctx.actions.args()
82+
arguments = actions.args()
8283
arguments.use_param_file("--param=%s")
8384

8485
# Finally, add the proto paths:
8586
# arguments.add_all(proto_paths.keys())
8687
arguments.add_all(swift_srcs)
8788

8889
# Run the compiler action:
89-
ctx.actions.run(
90+
actions.run(
9091
inputs = depset(
9192
direct = [],
9293
transitive = [transitive_proto_srcs],
@@ -103,6 +104,7 @@ def _custom_swift_proto_compile(ctx, swift_proto_compiler_info, additional_compi
103104
def _custom_swift_proto_compiler_impl(ctx):
104105
return [
105106
SwiftProtoCompilerInfo(
107+
bundled_proto_paths = [],
106108
compile = _custom_swift_proto_compile,
107109
compiler_deps = ctx.attr.deps,
108110
internal = struct(
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
load(
2+
"//swift:swift.bzl",
3+
"swift_binary",
4+
"swift_test",
5+
)
6+
7+
swift_binary(
8+
name = "echo_server",
9+
srcs = ["server_main.swift"],
10+
deps = [
11+
"//examples/xplatform/proto_library_group/service:service_server_swift_proto",
12+
],
13+
)
14+
15+
swift_binary(
16+
name = "echo_client",
17+
srcs = ["client_main.swift"],
18+
deps = [
19+
"//examples/xplatform/proto_library_group/service:service_client_swift_proto",
20+
],
21+
)
22+
23+
swift_test(
24+
name = "echo_client_unit_test",
25+
srcs = [
26+
"client_unit_test.swift",
27+
"main.swift",
28+
],
29+
deps = [
30+
"//examples/xplatform/proto_library_group/service:service_client_swift_proto",
31+
"//examples/xplatform/proto_library_group/service:service_server_swift_proto",
32+
],
33+
)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2019 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import Foundation
16+
import SwiftProtobuf
17+
import GRPC
18+
import NIOCore
19+
import NIOPosix
20+
import examples_xplatform_proto_library_group_request_request_proto
21+
import ServiceClient
22+
23+
@main
24+
struct ClientMain {
25+
static func main() throws {
26+
// Setup an `EventLoopGroup` for the connection to run on.
27+
//
28+
// See: https://github.com/apple/swift-nio#eventloops-and-eventloopgroups
29+
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
30+
31+
// Make sure the group is shutdown when we're done with it.
32+
defer {
33+
try! group.syncShutdownGracefully()
34+
}
35+
36+
// Configure the channel, we're not using TLS so the connection is `insecure`.
37+
let channel = try GRPCChannelPool.with(
38+
target: .host("localhost", port: 9000),
39+
transportSecurity: .plaintext,
40+
eventLoopGroup: group
41+
)
42+
43+
// Initialize the client using the same address the server is started on.
44+
let client = Service_EchoServiceNIOClient(channel: channel)
45+
46+
// Construct a request to the echo service.
47+
let request = Request_Request.with {
48+
$0.message = "Hello, world!"
49+
let timestamp = Google_Protobuf_Timestamp(date: Date())
50+
$0.extra = try! Google_Protobuf_Any(message: timestamp)
51+
}
52+
53+
let call = client.echo(request)
54+
55+
// Make the remote method call and print the response we receive.
56+
do {
57+
let response = try call.response.wait()
58+
print(response.request.message)
59+
print(response.request.extra)
60+
} catch {
61+
print("Echo failed: \(error)")
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)