diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 03320fb7f6..12c16cc86f 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -765,6 +765,12 @@ tasks: working_directory: examples/bzlmod/proto build_targets: - "//..." + bzlmod_proto: + name: Proto and Prost with prebuilt protoc with bzlmod + platform: ubuntu2004 + working_directory: examples/bzlmod/proto_with_toolchain + build_targets: + - "//..." compile_one_dependency: name: --compile_one_dependency flag platform: ubuntu2004 diff --git a/MODULE.bazel b/MODULE.bazel index 5484512013..e2ce9d3948 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -27,7 +27,7 @@ bazel_dep( ) bazel_dep( name = "rules_proto", - version = "5.3.0-21.7", + version = "6.0.2", ) bazel_dep( name = "apple_support", @@ -68,7 +68,6 @@ use_repo( "cargo_bazel.buildifier-linux-amd64", "cargo_bazel.buildifier-linux-arm64", "cargo_bazel.buildifier-windows-amd64.exe", - "com_google_googleapis", "cui", "cui__anyhow-1.0.75", "cui__camino-1.1.6", diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 76c40e913c..ef6b2a479e 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -11,6 +11,7 @@ bzl_library( "@com_google_protobuf//:bzl_srcs", ], deps = [ + "@bazel_features//:deps", "@bazel_features//:features", "@bazel_skylib//lib:paths", "@bazel_skylib//lib:selects", diff --git a/docs/MODULE.bazel b/docs/MODULE.bazel index 767b5cf167..23022157dc 100644 --- a/docs/MODULE.bazel +++ b/docs/MODULE.bazel @@ -8,5 +8,5 @@ bazel_dep( ) bazel_dep( name = "bazel_features", - version = "1.11.0", + version = "1.14.0", ) diff --git a/docs/flatten.md b/docs/flatten.md index c828c8df78..7eab948ae9 100644 --- a/docs/flatten.md +++ b/docs/flatten.md @@ -809,7 +809,7 @@ Rust Prost toolchain rule. | prost_plugin_flag | Prost plugin flag format. (e.g. `--plugin=protoc-gen-prost=%s`) | String | optional | `"--plugin=protoc-gen-prost=%s"` | | prost_runtime | The Prost runtime crates to use. | Label | required | | | prost_types | The Prost types crates to use. | Label | required | | -| proto_compiler | The protoc compiler to use. | Label | required | | +| proto_compiler | The protoc compiler to use. Note that this attribute is deprecated - prefer to use --incompatible_enable_proto_toolchain_resolution. | Label | optional | `None` | | tonic_opts | Additional options to add to Tonic. | List of strings | optional | `[]` | | tonic_plugin | Additional plugins to add to Tonic. | Label | optional | `None` | | tonic_plugin_flag | Tonic plugin flag format. (e.g. `--plugin=protoc-gen-tonic=%s`)) | String | optional | `"--plugin=protoc-gen-tonic=%s"` | @@ -1778,14 +1778,18 @@ This macro should be called immediately after the `rust_protobuf_dependencies` m rust_proto_protobuf_dependencies(bzlmod) - +Sets up dependencies for rules_rust's proto support. **PARAMETERS** | Name | Description | Default Value | | :------------- | :------------- | :------------- | -| bzlmod |

-

| `False` | +| bzlmod | Whether this function is being called from a bzlmod context rather than a workspace context. | `False` | + +**RETURNS** + +A list of structs containing information about root module deps to report to bzlmod's extension_metadata. diff --git a/docs/rust_proto.md b/docs/rust_proto.md index 08eca3759f..9d0e1a5a49 100644 --- a/docs/rust_proto.md +++ b/docs/rust_proto.md @@ -319,7 +319,7 @@ Rust Prost toolchain rule. | prost_plugin_flag | Prost plugin flag format. (e.g. `--plugin=protoc-gen-prost=%s`) | String | optional | `"--plugin=protoc-gen-prost=%s"` | | prost_runtime | The Prost runtime crates to use. | Label | required | | | prost_types | The Prost types crates to use. | Label | required | | -| proto_compiler | The protoc compiler to use. | Label | required | | +| proto_compiler | The protoc compiler to use. Note that this attribute is deprecated - prefer to use --incompatible_enable_proto_toolchain_resolution. | Label | optional | `None` | | tonic_opts | Additional options to add to Tonic. | List of strings | optional | `[]` | | tonic_plugin | Additional plugins to add to Tonic. | Label | optional | `None` | | tonic_plugin_flag | Tonic plugin flag format. (e.g. `--plugin=protoc-gen-tonic=%s`)) | String | optional | `"--plugin=protoc-gen-tonic=%s"` | @@ -434,14 +434,18 @@ This macro should be called immediately after the `rust_protobuf_dependencies` m rust_proto_protobuf_dependencies(bzlmod) - +Sets up dependencies for rules_rust's proto support. **PARAMETERS** | Name | Description | Default Value | | :------------- | :------------- | :------------- | -| bzlmod |

-

| `False` | +| bzlmod | Whether this function is being called from a bzlmod context rather than a workspace context. | `False` | + +**RETURNS** + +A list of structs containing information about root module deps to report to bzlmod's extension_metadata. diff --git a/examples/bzlmod/all_deps_vendor/MODULE.bazel b/examples/bzlmod/all_deps_vendor/MODULE.bazel index fed1e7b81c..654be4e41c 100644 --- a/examples/bzlmod/all_deps_vendor/MODULE.bazel +++ b/examples/bzlmod/all_deps_vendor/MODULE.bazel @@ -11,6 +11,10 @@ bazel_dep(name = "bazel_skylib", version = "1.7.1") # https://github.com/bazelbuild/rules_rust/releases bazel_dep(name = "rules_rust", version = "0.46.0") +local_path_override( + module_name = "rules_rust", + path = "../../..", +) ############################################################################### # T O O L C H A I N S diff --git a/examples/bzlmod/compile_opt/MODULE.bazel b/examples/bzlmod/compile_opt/MODULE.bazel index 03dd51ecf5..3ba5c5ea46 100644 --- a/examples/bzlmod/compile_opt/MODULE.bazel +++ b/examples/bzlmod/compile_opt/MODULE.bazel @@ -8,6 +8,10 @@ module( ############################################################################### # https://github.com/bazelbuild/rules_rust/releases bazel_dep(name = "rules_rust", version = "0.46.0") +local_path_override( + module_name = "rules_rust", + path = "../../..", +) ############################################################################### # T O O L C H A I N S diff --git a/examples/bzlmod/cross_compile/MODULE.bazel b/examples/bzlmod/cross_compile/MODULE.bazel index 50457ab537..d2d11a0c7c 100644 --- a/examples/bzlmod/cross_compile/MODULE.bazel +++ b/examples/bzlmod/cross_compile/MODULE.bazel @@ -5,6 +5,10 @@ module( # https://github.com/bazelbuild/rules_rust/releases bazel_dep(name = "rules_rust", version = "0.46.0") +local_path_override( + module_name = "rules_rust", + path = "../../..", +) # Rules for cross compilation bazel_dep(name = "toolchains_musl", version = "0.1.16", dev_dependency = True) diff --git a/examples/bzlmod/ffi/MODULE.bazel b/examples/bzlmod/ffi/MODULE.bazel index e3dc485feb..ccb9a2a939 100644 --- a/examples/bzlmod/ffi/MODULE.bazel +++ b/examples/bzlmod/ffi/MODULE.bazel @@ -8,6 +8,10 @@ module( ############################################################################### # https://github.com/bazelbuild/rules_rust/releases bazel_dep(name = "rules_rust", version = "0.46.0") +local_path_override( + module_name = "rules_rust", + path = "../../..", +) ############################################################################### # T O O L C H A I N S diff --git a/examples/bzlmod/proto/MODULE.bazel b/examples/bzlmod/proto/MODULE.bazel index fc6cd78459..17eda81f10 100644 --- a/examples/bzlmod/proto/MODULE.bazel +++ b/examples/bzlmod/proto/MODULE.bazel @@ -8,6 +8,10 @@ module( ############################################################################### # https://github.com/bazelbuild/rules_rust/releases bazel_dep(name = "rules_rust", version = "0.46.0") +local_path_override( + module_name = "rules_rust", + path = "../../..", +) # # Rules for protobuf / gRPC diff --git a/examples/bzlmod/proto/build/prost_toolchain/BUILD.bazel b/examples/bzlmod/proto/build/prost_toolchain/BUILD.bazel index 1075543a16..99dc284ccf 100644 --- a/examples/bzlmod/proto/build/prost_toolchain/BUILD.bazel +++ b/examples/bzlmod/proto/build/prost_toolchain/BUILD.bazel @@ -21,7 +21,6 @@ rust_prost_toolchain( prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost", prost_runtime = ":prost_runtime", prost_types = "@crates//:prost-types", - proto_compiler = "@protobuf//:protoc", tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic", tonic_runtime = ":tonic_runtime", ) diff --git a/examples/bzlmod/proto_with_toolchain/.bazelrc b/examples/bzlmod/proto_with_toolchain/.bazelrc new file mode 100644 index 0000000000..67ff2b3d98 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/.bazelrc @@ -0,0 +1,9 @@ +# Required on windows +common --enable_platform_specific_config +startup --windows_enable_symlinks +build:windows --enable_runfiles + +# Required for cargo_build_script support before Bazel 7 +build --incompatible_merge_fixed_and_default_shell_env + +common --incompatible_enable_proto_toolchain_resolution diff --git a/examples/bzlmod/proto_with_toolchain/.bazelversion b/examples/bzlmod/proto_with_toolchain/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/proto_with_toolchain/.gitignore b/examples/bzlmod/proto_with_toolchain/.gitignore new file mode 100644 index 0000000000..c29ff2bab2 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/.gitignore @@ -0,0 +1,5 @@ +/bazel-* +.DS_Store +/proto/.DS_Store +/proto/grpc_server/.DS_Store +/proto/proto_bindings/.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/proto_with_toolchain/BUILD.bazel b/examples/bzlmod/proto_with_toolchain/BUILD.bazel new file mode 100644 index 0000000000..ed9b5e7a0e --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/BUILD.bazel @@ -0,0 +1,6 @@ +config_setting( + name = "release", + values = { + "compilation_mode": "opt", + }, +) diff --git a/examples/bzlmod/proto_with_toolchain/Cargo.toml b/examples/bzlmod/proto_with_toolchain/Cargo.toml new file mode 100644 index 0000000000..3f3017dac4 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/Cargo.toml @@ -0,0 +1,42 @@ +[workspace] +resolver = "2" + +members = [ + "proto_bindings", + "grpc_server", + "grpc_client", +] + + +[workspace.package] +edition = "2021" +rust-version = "1.78.0" +readme = "README.md" + + +[workspace.dependencies] +# Internal crates +proto_bindings = { path = "proto_bindings" } +# External crates +prost = { version = "0.12.6" } +prost-types = { version = "0.12.6", default-features = false } +tonic = { version = "0.11.0", features = ["transport"] } +tonic-build = "0.11.0" +tokio = { version = "1.38", default-features = false, features = ["macros", "net", "rt-multi-thread", "signal"] } + + +# Optimize all crates +[profile.release] +opt-level = 3 +strip = true # Automatically strip debug symbols from the binary +lto = true # Enable Link Time Optimization (LTO) +codegen-units = 1 # Reduce Parallel Code Generation Units to Increase Optimization + + +# There's a Cargo feature named profile-overrides +# that lets you override the optimization level of dependencies. +# https://docs.rust-embedded.org/book/unsorted/speed-vs-size.html +[profile.release.package."*"] +opt-level = 3 +strip = 'debuginfo' # Automatically strip debug infos from the binary to reduce size +codegen-units = 1 # Reduce Parallel Code Generation Units to Increase Optimization diff --git a/examples/bzlmod/proto_with_toolchain/MODULE.bazel b/examples/bzlmod/proto_with_toolchain/MODULE.bazel new file mode 100644 index 0000000000..17eda81f10 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/MODULE.bazel @@ -0,0 +1,133 @@ +module( + name = "grpc-client-server", + version = "0.0.0", +) + +############################################################################### +# B A Z E L C E N T R A L R E G I S T R Y # https://registry.bazel.build/ +############################################################################### +# https://github.com/bazelbuild/rules_rust/releases +bazel_dep(name = "rules_rust", version = "0.46.0") +local_path_override( + module_name = "rules_rust", + path = "../../..", +) + +# +# Rules for protobuf / gRPC +# https://github.com/bazelbuild/rules_proto/releases +bazel_dep(name = "rules_proto", version = "6.0.2") + +# https://github.com/aspect-build/toolchains_protoc/releases +bazel_dep(name = "toolchains_protoc", version = "0.3.1") + +# https://registry.bazel.build/modules/protobuf +bazel_dep(name = "protobuf", version = "27.1") + +# https://github.com/bazel-contrib/toolchains_llvm +bazel_dep(name = "toolchains_llvm", version = "1.0.0") + +############################################################################### +# L L V M +# https://github.com/bazel-contrib/toolchains_llvm/blob/master/tests/MODULE.bazel +############################################################################### +llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm") + +# LLVM Versions and platforms +# https://github.com/bazel-contrib/toolchains_llvm/blob/master/toolchain/internal/llvm_distributions.bzl +LLVM_VERSIONS = { + "": "16.0.0", + "darwin-aarch64": "16.0.3", + "darwin-x86_64": "15.0.7", +} + +# Host LLVM toolchain. +llvm.toolchain( + name = "llvm_toolchain", + llvm_versions = LLVM_VERSIONS, +) +use_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm") + +register_toolchains("@llvm_toolchain//:all") + +############################################################################### +# T O O L C H A I N S +############################################################################### + +# Rust toolchain +RUST_EDITION = "2021" + +RUST_VERSION = "1.79.0" + +rust = use_extension("@rules_rust//rust:extensions.bzl", "rust") +rust.toolchain( + edition = RUST_EDITION, + versions = [RUST_VERSION], +) +use_repo(rust, "rust_toolchains") + +register_toolchains("@rust_toolchains//:all") + +# Proto toolchain +register_toolchains("@rules_rust//proto/protobuf:default-proto-toolchain") + +# Custom Prost toolchain +register_toolchains("@//build/prost_toolchain") + +############################################################################### +# R U S T C R A T E S +############################################################################### +crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate") + +# +# protobuf / gRPC dependencies +crate.spec( + package = "prost", + version = "0.12", +) +crate.spec( + default_features = False, + package = "prost-types", + version = "0.12", +) +crate.spec( + features = ["transport"], + package = "tonic", + version = "0.11", +) +crate.spec( + package = "tonic-build", + version = "0.11", +) +crate.spec( + package = "protoc-gen-prost", + version = "0.3.1", +) +crate.annotation( + crate = "protoc-gen-prost", + gen_binaries = ["protoc-gen-prost"], +) +crate.spec( + package = "protoc-gen-tonic", + version = "0.4.0", +) +crate.annotation( + crate = "protoc-gen-tonic", + gen_binaries = ["protoc-gen-tonic"], +) + +# +# External crates +crate.spec( + default_features = False, + features = [ + "macros", + "net", + "rt-multi-thread", + "signal", + ], + package = "tokio", + version = "1.38", +) +crate.from_specs() +use_repo(crate, "crates") diff --git a/examples/bzlmod/proto_with_toolchain/README.md b/examples/bzlmod/proto_with_toolchain/README.md new file mode 100644 index 0000000000..8ce7fc6125 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/README.md @@ -0,0 +1,221 @@ +# gRPC Client & Server + +This example shows how to build a gRPC server and client in Rust with Bazel. +There is a Cargo Workspace configuration and a Bazelmod configuration. Furthermore, +all binary targets apply optimization from the [compiler optimization example](../03-comp-opt). + +To run the example with Cargo, open one terminal and start the server with: + +` +cargo run --bin grpc_server +` + +And, in a second terminal, to run the client: + +` +cargo run --bin grpc_client +` + +The equivalent Bazel targets are: + +Server: + +`bazel run //grpc_server:bin` + +Client: + +`bazel run //grpc_client:bin` + +## Setup + +The Prost and Tonic rules do not specify a default toolchain in order to avoid mismatched dependency issues. +While the Tonic toolchain works out of the box when its dependencies are matched, however, +Prost requires a custom toolchain that you have to define. + +The setup requires three steps to complete: +1. Configure rules and dependencies in MODULE.bazel +2. Configure a custom Prost toolchain +3. Register custom Prost toolchain. + +To keep the build hermetic, we use the LLVM Clang compiler to compile all C/C++ dependencies. + +### 1) Configure rules and dependencies + +In your MODULE.bazel, you add the following: + +```starlark +# rules for proto +############################################################################### +# https://github.com/bazelbuild/rules_proto/releases +bazel_dep(name = "rules_proto", version = "6.0.2") +# https://github.com/aspect-build/toolchains_protoc/releases +bazel_dep(name = "toolchains_protoc", version = "0.3.1") +# https://registry.bazel.build/modules/protobuf +bazel_dep(name = "protobuf", version = "27.1") +# rules for LLVM +# https://github.com/bazel-contrib/toolchains_llvm +bazel_dep(name = "toolchains_llvm", version = "1.0.0") + +# 1 Register LLVM +############################################################################### +# L L V M +# https://github.com/bazel-contrib/toolchains_llvm/blob/master/tests/MODULE.bazel +############################################################################### +llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm") +LLVM_VERSIONS = { "": "16.0.0",} + +# LLVM toolchain. +llvm.toolchain( + name = "llvm_toolchain", + llvm_versions = LLVM_VERSIONS, +) +use_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm") +register_toolchains("@llvm_toolchain//:all") + +# 2 Register Proto toolchain +############################################################################### +# Proto toolchain +register_toolchains("@rules_rust//proto/protobuf:default-proto-toolchain") + +# Custom Prost toolchain will be added later. See next section + +# 3 Register proto / prost / tonic crates +############################################################################### +crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate") + +# protobufs / gRPC +crate.spec( + package = "prost", + version = "0.12", +) +crate.spec( + default_features = False, + package = "prost-types", + version = "0.12", +) +crate.spec( + features = ["transport"], + package = "tonic", + version = "0.11", +) +crate.spec( + package = "tonic-build", + version = "0.11", +) +crate.spec( + package = "protoc-gen-prost", + version = "0.3.1", +) +crate.annotation( + crate = "protoc-gen-prost", + gen_binaries = ["protoc-gen-prost"], +) +crate.spec( + package = "protoc-gen-tonic", + version = "0.4.0", +) +crate.annotation( + crate = "protoc-gen-tonic", + gen_binaries = ["protoc-gen-tonic"], +) + +# Other Rust dependencies ... + +crate.from_specs() +use_repo(crate, "crates") +``` + +### 2) Configure a custom Prost toolchain + +Configuring a custom Prost toolchain is straightforward, you create a new folder with an empty BUILD.bazl file, and add +the toolchain definition. +As your Bazel setup grows over time, it is a best practice to put all custom macros, rules, and toolchains in a +dedicated folder, for example: `build/`. + +Suppose you have your BUILD.bazl file in `build/prost_toolchain/BUILD.bazel`, then add the following content: + +```starlark +load("@rules_rust//proto/prost:defs.bzl", "rust_prost_toolchain") +load("@rules_rust//rust:defs.bzl", "rust_library_group") + +rust_library_group( + name = "prost_runtime", + deps = [ + "@crates//:prost", + ], +) + +rust_library_group( + name = "tonic_runtime", + deps = [ + ":prost_runtime", + "@crates//:tonic", + ], +) + +rust_prost_toolchain( + name = "prost_toolchain_impl", + prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost", + prost_runtime = ":prost_runtime", + prost_types = "@crates//:prost-types", + proto_compiler = "@protobuf//:protoc", + tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic", + tonic_runtime = ":tonic_runtime", +) + +toolchain( + name = "prost_toolchain", + toolchain = "prost_toolchain_impl", + toolchain_type = "@rules_rust//proto/prost:toolchain_type", +) +``` + +The Prost and Tonic dependencies are pulled from the previously configured +crate dependencies in the MODULE file. With this custom toolchain in place, the last step is to register it. + +### 3. Register custom Prost toolchain. + +In your MODULE.bazel file, locate your toolchains and add the following entry right below the proto toolchain. + +```starlark +# 2 Register Proto toolchain +############################################################################### +# Proto toolchain +register_toolchains("@rules_rust//proto/protobuf:default-proto-toolchain") + +# Custom Prost toolchain +register_toolchains("@//build/prost_toolchain") +``` + +Pay attention to the path, `build/prost_toolchain` because if your toolchain +is in a different folder, you have to update this path to make the build work. + +## Usage + +Once the setup has been completed, you use the proto & prost targets as you normally do. For example, to configure rust +bindings for a proto file, just add the target: + +```starlark +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@rules_rust//proto/prost:defs.bzl", "rust_prost_library") + +# Build proto files +# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_proto_library +proto_library( + name = "proto_bindings", + srcs = [ + "proto/helloworld.proto", + ], +) + +# Generate Rust bindings from the generated proto files +# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_prost_library +rust_prost_library( + name = "rust_proto", + proto = ":proto_bindings", + visibility = ["//visibility:public"], +) +``` + +From there, you +just [follow the target documentation](https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_proto_library). diff --git a/examples/bzlmod/proto_with_toolchain/build/prost_toolchain/BUILD.bazel b/examples/bzlmod/proto_with_toolchain/build/prost_toolchain/BUILD.bazel new file mode 100644 index 0000000000..99dc284ccf --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/build/prost_toolchain/BUILD.bazel @@ -0,0 +1,32 @@ +load("@rules_rust//proto/prost:defs.bzl", "rust_prost_toolchain") +load("@rules_rust//rust:defs.bzl", "rust_library_group") + +rust_library_group( + name = "prost_runtime", + deps = [ + "@crates//:prost", + ], +) + +rust_library_group( + name = "tonic_runtime", + deps = [ + ":prost_runtime", + "@crates//:tonic", + ], +) + +rust_prost_toolchain( + name = "prost_toolchain_impl", + prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost", + prost_runtime = ":prost_runtime", + prost_types = "@crates//:prost-types", + tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic", + tonic_runtime = ":tonic_runtime", +) + +toolchain( + name = "prost_toolchain", + toolchain = "prost_toolchain_impl", + toolchain_type = "@rules_rust//proto/prost:toolchain_type", +) diff --git a/examples/bzlmod/proto_with_toolchain/grpc_client/BUILD.bazel b/examples/bzlmod/proto_with_toolchain/grpc_client/BUILD.bazel new file mode 100644 index 0000000000..94b11e926d --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_client/BUILD.bazel @@ -0,0 +1,47 @@ +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_doc", "rust_doc_test") + +# Build binary +# https://bazelbuild.github.io/rules_rust/defs.html#rust_binary +rust_binary( + name = "bin", + srcs = glob([ + "src/*.rs", + ]), + crate_root = "src/main.rs", + rustc_flags = select({ + "//:release": [ + "-Clto", + "-Ccodegen-units=1", + "-Cpanic=abort", + "-Copt-level=3", + "-Cstrip=symbols", + ], + "//conditions:default": [ + "-Copt-level=0", + ], + }), + visibility = ["//visibility:public"], + deps = [ + # Internal crates + "//proto_bindings:rust_proto", + # External crates + "@crates//:tokio", + "@crates//:tonic", + ], +) + +# Build documentation +# https://bazelbuild.github.io/rules_rust/rust_doc.html +rust_doc( + name = "client_doc", + crate = ":bin", + visibility = ["//visibility:public"], +) + +# Test documentation +# https://bazelbuild.github.io/rules_rust/rust_doc.html#rust_doc_test +rust_doc_test( + name = "client_doc_test", + crate = ":bin", + visibility = ["//visibility:public"], +) diff --git a/examples/bzlmod/proto_with_toolchain/grpc_client/Cargo.toml b/examples/bzlmod/proto_with_toolchain/grpc_client/Cargo.toml new file mode 100644 index 0000000000..357a3919c2 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_client/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "grpc_client" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +readme.workspace = true + + +[[bin]] +name = "grpc_client" +path = "src/main.rs" + + +[dependencies] +# Internal crates +proto_bindings = { workspace = true } +# External crates +tokio = { workspace = true } +tonic = { workspace = true } diff --git a/examples/bzlmod/proto_with_toolchain/grpc_client/src/main.rs b/examples/bzlmod/proto_with_toolchain/grpc_client/src/main.rs new file mode 100644 index 0000000000..4b7cdd3f93 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_client/src/main.rs @@ -0,0 +1,23 @@ +use proto_bindings::proto::greeter_client::GreeterClient; +use proto_bindings::proto::HelloRequest; + +// https://github.com/hyperium/tonic/blob/master/examples/src/helloworld/client.rs +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut client = GreeterClient::connect("http://[::1]:5042") + .await + .expect("[Client]: Failed to connect to server."); + + let request = tonic::Request::new(HelloRequest { + name: "Hello gRPC".into(), + }); + + let response = client + .say_hello(request) + .await + .expect("[Client]: Failed to get a response from the server"); + + println!("RESPONSE={:?}", response); + + Ok(()) +} diff --git a/examples/bzlmod/proto_with_toolchain/grpc_server/BUILD.bazel b/examples/bzlmod/proto_with_toolchain/grpc_server/BUILD.bazel new file mode 100644 index 0000000000..27e0b43e45 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_server/BUILD.bazel @@ -0,0 +1,61 @@ +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_doc", "rust_doc_test", "rust_test_suite") + +# Build binary +# https://bazelbuild.github.io/rules_rust/defs.html#rust_binary +rust_binary( + name = "bin", + srcs = glob([ + "src/*.rs", + ]), + crate_root = "src/main.rs", + rustc_flags = select({ + "//:release": [ + "-Clto", + "-Ccodegen-units=1", + "-Cpanic=abort", + "-Copt-level=3", + "-Cstrip=symbols", + ], + "//conditions:default": [ + "-Copt-level=0", + ], + }), + visibility = ["//visibility:public"], + deps = [ + # Internal crates + "//proto_bindings:rust_proto", + # External crates + "@crates//:tokio", + "@crates//:tonic", + ], +) + +# Build documentation +# https://bazelbuild.github.io/rules_rust/rust_doc.html +rust_doc( + name = "server_doc", + crate = ":bin", + visibility = ["//visibility:public"], +) + +# Test documentation +# https://bazelbuild.github.io/rules_rust/rust_doc.html#rust_doc_test +rust_doc_test( + name = "server_doc_test", + crate = ":bin", + visibility = ["//visibility:public"], +) + +rust_test_suite( + name = "demo_tests", + srcs = glob([ + "tests/*_tests.rs", + ]), + tags = ["unit"], + visibility = ["//visibility:public"], + deps = [ + # Crate to test + "//proto_bindings:rust_proto", + # External crates + ], +) diff --git a/examples/bzlmod/proto_with_toolchain/grpc_server/Cargo.toml b/examples/bzlmod/proto_with_toolchain/grpc_server/Cargo.toml new file mode 100644 index 0000000000..3c7c6a2fde --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_server/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "grpc_server" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +readme.workspace = true + + +[[bin]] +name = "grpc_server" +path = "src/main.rs" + + +[dependencies] +# Internal crates +proto_bindings = { workspace = true } +# External crates +tokio = { workspace = true } +tonic = { workspace = true } \ No newline at end of file diff --git a/examples/bzlmod/proto_with_toolchain/grpc_server/src/main.rs b/examples/bzlmod/proto_with_toolchain/grpc_server/src/main.rs new file mode 100644 index 0000000000..6f22bfac0c --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_server/src/main.rs @@ -0,0 +1,40 @@ +use std::error::Error; + +use tonic::transport::Server; + +use proto_bindings::proto::greeter_server::GreeterServer; + +use crate::server::MyGreeter; + +mod server; +mod shutdown_utils; + +// https://github.com/hyperium/tonic/blob/master/examples/src/helloworld/server.rs +#[tokio::main] +async fn main() -> Result<(), Box> { + let addr = "[::1]:5042" + .parse() + .expect("[Server]: Failed to parse socket address"); + + let grpc_svc = GreeterServer::new(MyGreeter::new()); + + // Shutdown signal handler + let signal = shutdown_utils::signal_handler("gRPC Greeter server"); + + let grpc_server = Server::builder() + .add_service(grpc_svc) + .serve_with_shutdown(addr, signal); + + let grpc_handle = tokio::spawn(grpc_server); + + println!("GreeterServer listening on {}", addr); + match tokio::try_join!(grpc_handle) { + Ok(_) => {} + Err(e) => { + println!("[Server]: Error: Failed to start gRPC Greeter server."); + println!("[Server]: Error: {:?}", e); + } + } + + Ok(()) +} diff --git a/examples/bzlmod/proto_with_toolchain/grpc_server/src/server.rs b/examples/bzlmod/proto_with_toolchain/grpc_server/src/server.rs new file mode 100644 index 0000000000..a1d457326c --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_server/src/server.rs @@ -0,0 +1,28 @@ +use tonic::{Request, Response, Status}; + +use proto_bindings::proto::greeter_server::Greeter; +use proto_bindings::proto::{HelloReply, HelloRequest}; + +#[derive(Copy, Clone)] +pub struct MyGreeter {} + +impl MyGreeter { + pub fn new() -> Self { + Self {} + } +} + +#[tonic::async_trait] +impl Greeter for MyGreeter { + async fn say_hello( + &self, + request: Request, + ) -> Result, Status> { + println!("Got a request from {:?}", request.remote_addr()); + + let reply = HelloReply { + message: format!("Hello {}!", request.into_inner().name), + }; + Ok(Response::new(reply)) + } +} diff --git a/examples/bzlmod/proto_with_toolchain/grpc_server/src/shutdown_utils.rs b/examples/bzlmod/proto_with_toolchain/grpc_server/src/shutdown_utils.rs new file mode 100644 index 0000000000..20d60e1b8c --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_server/src/shutdown_utils.rs @@ -0,0 +1,54 @@ +// +/// Registers a signal handler that waits for a signal that indicates a shutdown request. +// https://stackoverflow.com/questions/77585473/rust-tokio-how-to-handle-more-signals-than-just-sigint-i-e-sigquit?noredirect=1#comment136778587_77585473 +pub async fn signal_handler(svc: &str) { + wait_for_signal_impl(svc).await +} + +/// Waits for a signal that requests a graceful shutdown. Supports the following signals on unix: +/// * SIGTERM +/// * SIGINT (Ctrl-C) +/// * SIGQUIT +/// * SIGHUP +#[cfg(unix)] +async fn wait_for_signal_impl(svc: &str) { + use tokio::signal::unix::{signal, SignalKind}; + + // Docs: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html + let mut signal_terminate = signal(SignalKind::terminate()).unwrap(); + let mut signal_interrupt = signal(SignalKind::interrupt()).unwrap(); + let mut signal_quit = signal(SignalKind::quit()).unwrap(); + let mut signal_hang = signal(SignalKind::hangup()).unwrap(); + + // https://docs.rs/tokio/latest/tokio/macro.select.html + tokio::select! { + _ = signal_terminate.recv() => println!("* {svc} received SIGTERM"), + _ = signal_interrupt.recv() => println!("* {svc} received SIGINT"), + _ = signal_quit.recv() => println!("* {svc} received SIGQUIT"), + _ = signal_hang.recv() => println!(" * {svc} received SIGHUP"), + } +} + +/// Waits for a signal that requests a graceful shutdown. Supports the following signals on Windows: +/// * ctrl_c +/// * ctrl_break +/// * ctrl_close +/// * ctrl_shutdown +#[cfg(windows)] +async fn wait_for_signal_impl(svc: &str) { + use tokio::signal::windows; + + // Docs: https://learn.microsoft.com/en-us/windows/console/handlerroutine + let mut signal_c = windows::ctrl_c().unwrap(); + let mut signal_break = windows::ctrl_break().unwrap(); + let mut signal_close = windows::ctrl_close().unwrap(); + let mut signal_shutdown = windows::ctrl_shutdown().unwrap(); + + // https://docs.rs/tokio/latest/tokio/macro.select.html + tokio::select! { + _ = signal_c.recv() => println!("* {svc} received CTRL_C."), + _ = signal_break.recv() => println!("* {svc} received CTRL_BREAK."), + _ = signal_close.recv() => println!("* {svc} received CTRL_CLOSE."), + _ = signal_shutdown.recv() => println!("* {svc} received CTRL_SHUTDOWN."), + } +} diff --git a/examples/bzlmod/proto_with_toolchain/grpc_server/tests/demo_tests.rs b/examples/bzlmod/proto_with_toolchain/grpc_server/tests/demo_tests.rs new file mode 100644 index 0000000000..f12bef408b --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_server/tests/demo_tests.rs @@ -0,0 +1,4 @@ +#[test] +fn demo_test() { + assert_eq!(4 + 4, 8); +} diff --git a/examples/bzlmod/proto_with_toolchain/grpc_server/tests/mod.rs b/examples/bzlmod/proto_with_toolchain/grpc_server/tests/mod.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/grpc_server/tests/mod.rs @@ -0,0 +1 @@ + diff --git a/examples/bzlmod/proto_with_toolchain/proto_bindings/BUILD.bazel b/examples/bzlmod/proto_with_toolchain/proto_bindings/BUILD.bazel new file mode 100644 index 0000000000..d2f9e24f1e --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/proto_bindings/BUILD.bazel @@ -0,0 +1,19 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@rules_rust//proto/prost:defs.bzl", "rust_prost_library") + +# Build proto files +# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_proto_library +proto_library( + name = "proto_bindings", + srcs = [ + "proto/helloworld.proto", + ], +) + +# Generate Rust bindings from the generated proto files +# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_prost_library +rust_prost_library( + name = "rust_proto", + proto = ":proto_bindings", + visibility = ["//visibility:public"], +) diff --git a/examples/bzlmod/proto_with_toolchain/proto_bindings/Cargo.lock b/examples/bzlmod/proto_with_toolchain/proto_bindings/Cargo.lock new file mode 100644 index 0000000000..9d1ef987af --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/proto_bindings/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proto_bindings" +version = "0.1.0" diff --git a/examples/bzlmod/proto_with_toolchain/proto_bindings/Cargo.toml b/examples/bzlmod/proto_with_toolchain/proto_bindings/Cargo.toml new file mode 100644 index 0000000000..95255c32ca --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/proto_bindings/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "proto_bindings" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +readme.workspace = true + + + +[lib] +name = "proto_bindings" +path = "src/lib.rs" + + +[dependencies] +tonic = { workspace = true } +prost = { workspace = true } + + +[build-dependencies] +tonic-build = { workspace = true } diff --git a/examples/bzlmod/proto_with_toolchain/proto_bindings/build.rs b/examples/bzlmod/proto_with_toolchain/proto_bindings/build.rs new file mode 100644 index 0000000000..e1da7552bf --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/proto_bindings/build.rs @@ -0,0 +1,6 @@ +fn main() -> Result<(), Box> { + tonic_build::configure() + .compile(&["proto/helloworld.proto"], &["proto"]) + .expect("Failed to compile proto specification"); + Ok(()) +} diff --git a/examples/bzlmod/proto_with_toolchain/proto_bindings/proto/helloworld.proto b/examples/bzlmod/proto_with_toolchain/proto_bindings/proto/helloworld.proto new file mode 100644 index 0000000000..e838ddc9ec --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/proto_bindings/proto/helloworld.proto @@ -0,0 +1,34 @@ +// Copyright 2015 gRPC authors. +// +// 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. + +syntax = "proto3"; + +// https://github.com/hyperium/tonic/blob/master/examples/proto/helloworld/helloworld.proto +package proto; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello(HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} \ No newline at end of file diff --git a/examples/bzlmod/proto_with_toolchain/proto_bindings/src/lib.rs b/examples/bzlmod/proto_with_toolchain/proto_bindings/src/lib.rs new file mode 100644 index 0000000000..860d77e5a1 --- /dev/null +++ b/examples/bzlmod/proto_with_toolchain/proto_bindings/src/lib.rs @@ -0,0 +1,3 @@ +pub mod proto { + tonic::include_proto!("proto"); +} diff --git a/proto/private/BUILD.bazel b/proto/private/BUILD.bazel new file mode 100644 index 0000000000..512d913115 --- /dev/null +++ b/proto/private/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["BUILD.zlib.bazel"]) diff --git a/proto/private/BUILD.zlib.bazel b/proto/private/BUILD.zlib.bazel new file mode 100644 index 0000000000..687375d7b3 --- /dev/null +++ b/proto/private/BUILD.zlib.bazel @@ -0,0 +1,76 @@ +load("@bazel_skylib//rules:copy_file.bzl", "copy_file") +load("@rules_cc//cc:defs.bzl", "cc_library") + +_ZLIB_HEADERS = [ + "crc32.h", + "deflate.h", + "gzguts.h", + "inffast.h", + "inffixed.h", + "inflate.h", + "inftrees.h", + "trees.h", + "zconf.h", + "zlib.h", + "zutil.h", +] + +# In order to limit the damage from the `includes` propagation +# via `:zlib`, copy the public headers to a subdirectory and +# expose those. +_ZLIB_HEADER_PREFIX = "zlib/include" + +_ZLIB_PREFIXED_HEADERS = ["{}/{}".format(_ZLIB_HEADER_PREFIX, hdr) for hdr in _ZLIB_HEADERS] + +[ + copy_file( + name = "{}.copy".format(hdr), + src = hdr, + out = "{}/{}".format(_ZLIB_HEADER_PREFIX, hdr), + ) + for hdr in _ZLIB_HEADERS +] + +_COMMON_COPTS = [ + "-Wno-deprecated-non-prototype", + "-Wno-unused-variable", + "-Wno-implicit-function-declaration", +] + +cc_library( + name = "zlib", + srcs = [ + "adler32.c", + "compress.c", + "crc32.c", + "deflate.c", + "gzclose.c", + "gzlib.c", + "gzread.c", + "gzwrite.c", + "infback.c", + "inffast.c", + "inflate.c", + "inftrees.c", + "trees.c", + "uncompr.c", + "zutil.c", + # Include the un-prefixed headers in srcs to work + # around the fact that zlib isn't consistent in its + # choice of <> or "" delimiter when including itself. + ] + _ZLIB_HEADERS, + hdrs = _ZLIB_PREFIXED_HEADERS, + copts = select({ + "@platforms//os:linux": [ + # Required for opt builds to avoid + # `libzlib.a(crc32.o): requires unsupported dynamic reloc 11; recompile with -fPIC` + "-fPIC", + # Silence all warnings + "-w", + ] + _COMMON_COPTS, + "@platforms//os:windows": [], + "//conditions:default": _COMMON_COPTS, + }), + includes = ["zlib/include/"], + visibility = ["//visibility:public"], +) diff --git a/proto/prost/private/BUILD.bazel b/proto/prost/private/BUILD.bazel index 269721089c..4ae38fc902 100644 --- a/proto/prost/private/BUILD.bazel +++ b/proto/prost/private/BUILD.bazel @@ -55,7 +55,6 @@ rust_prost_toolchain( prost_plugin_flag = "--plugin=protoc-gen-prost=%s", prost_runtime = ":prost_runtime", prost_types = "//proto/prost/private/3rdparty/crates:prost-types", - proto_compiler = "@com_google_protobuf//:protoc", tonic_plugin = "//proto/prost/private/3rdparty/crates:protoc-gen-tonic__protoc-gen-tonic", tonic_plugin_flag = "--plugin=protoc-gen-tonic=%s", tonic_runtime = ":tonic_runtime", diff --git a/proto/prost/private/prost.bzl b/proto/prost/private/prost.bzl index 4c454018a3..c3a7d4e043 100644 --- a/proto/prost/private/prost.bzl +++ b/proto/prost/private/prost.bzl @@ -1,6 +1,7 @@ """Rules for building protos in Rust with Prost and Tonic.""" load("@rules_proto//proto:defs.bzl", "ProtoInfo", "proto_common") +load("@rules_proto//proto:proto_common.bzl", proto_toolchains = "toolchains") load("//proto/prost:providers.bzl", "ProstProtoInfo") load("//rust:defs.bzl", "rust_common") @@ -49,7 +50,7 @@ def _compile_proto(ctx, crate_name, proto_info, deps, prost_toolchain, rustfmt_t package_info_file = ctx.actions.declare_file(ctx.label.name + ".prost_package_info") lib_rs = ctx.actions.declare_file("{}.lib.rs".format(ctx.label.name)) - proto_compiler = prost_toolchain.proto_compiler[DefaultInfo].files_to_run + proto_compiler = prost_toolchain.proto_compiler tools = depset([proto_compiler.executable]) additional_args = ctx.actions.args() @@ -349,13 +350,23 @@ def _rust_prost_toolchain_impl(ctx): if any(tonic_attrs) and not all(tonic_attrs): fail("When one tonic attribute is added, all must be added") + if ctx.attr.proto_compiler: + # buildifier: disable=print + print("WARN: rust_prost_toolchain's proto_compiler attribute is deprecated. Make sure your rules_proto dependency is at least version 6.0.0 and stop setting proto_compiler") + + proto_toolchain = proto_toolchains.find_toolchain( + ctx, + legacy_attr = "_legacy_proto_toolchain", + toolchain_type = "@rules_proto//proto:toolchain_type", + ) + return [platform_common.ToolchainInfo( prost_opts = ctx.attr.prost_opts, prost_plugin = ctx.attr.prost_plugin, prost_plugin_flag = ctx.attr.prost_plugin_flag, prost_runtime = ctx.attr.prost_runtime, prost_types = ctx.attr.prost_types, - proto_compiler = ctx.attr.proto_compiler, + proto_compiler = ctx.attr.proto_compiler or proto_toolchain.proto_compiler, protoc_opts = ctx.fragments.proto.experimental_protoc_opts, tonic_opts = ctx.attr.tonic_opts, tonic_plugin = ctx.attr.tonic_plugin, @@ -367,7 +378,7 @@ rust_prost_toolchain = rule( implementation = _rust_prost_toolchain_impl, doc = "Rust Prost toolchain rule.", fragments = ["proto"], - attrs = { + attrs = dict({ "prost_opts": attr.string_list( doc = "Additional options to add to Prost.", ), @@ -392,10 +403,9 @@ rust_prost_toolchain = rule( mandatory = True, ), "proto_compiler": attr.label( - doc = "The protoc compiler to use.", + doc = "The protoc compiler to use. Note that this attribute is deprecated - prefer to use --incompatible_enable_proto_toolchain_resolution.", cfg = "exec", executable = True, - mandatory = True, ), "tonic_opts": attr.string_list( doc = "Additional options to add to Tonic.", @@ -413,7 +423,12 @@ rust_prost_toolchain = rule( doc = "The Tonic runtime crates to use.", providers = [[rust_common.crate_info], [rust_common.crate_group_info]], ), - }, + }, **proto_toolchains.if_legacy_toolchain({ + "_legacy_proto_toolchain": attr.label( + default = "//proto/protobuf:legacy_proto_toolchain", + ), + })), + toolchains = proto_toolchains.use_toolchain("@rules_proto//proto:toolchain_type"), ) def _current_prost_runtime_impl(ctx): diff --git a/proto/prost/repositories.bzl b/proto/prost/repositories.bzl index 0c9ca063b2..57727cb2c7 100644 --- a/proto/prost/repositories.bzl +++ b/proto/prost/repositories.bzl @@ -28,12 +28,9 @@ def rust_prost_dependencies(bzlmod = False): maybe( http_archive, name = "rules_proto", - sha256 = "dc3fb206a2cb3441b485eb1e423165b231235a1ea9b031b4433cf7bc1fa460dd", - strip_prefix = "rules_proto-5.3.0-21.7", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz", - "https://github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz", - ], + sha256 = "6fb6767d1bef535310547e03247f7518b03487740c11b6c6adb7952033fe1295", + strip_prefix = "rules_proto-6.0.2", + url = "https://github.com/bazelbuild/rules_proto/releases/download/6.0.2/rules_proto-6.0.2.tar.gz", ) maybe( diff --git a/proto/prost/transitive_repositories.bzl b/proto/prost/transitive_repositories.bzl index 11010e3574..13725e00fb 100644 --- a/proto/prost/transitive_repositories.bzl +++ b/proto/prost/transitive_repositories.bzl @@ -1,7 +1,6 @@ """Definitions for loading transitive `@rules_rust//proto` dependencies""" -load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") -load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") +load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies") def rust_prost_transitive_repositories(): """Load transitive dependencies of the `@rules_rust//proto` rules. @@ -9,7 +8,3 @@ def rust_prost_transitive_repositories(): This macro should be called immediately after the `rust_proto_dependencies` macro. """ rules_proto_dependencies() - - rules_proto_toolchains() - - protobuf_deps() diff --git a/proto/protobuf/BUILD.bazel b/proto/protobuf/BUILD.bazel index 8ab84afeb6..f8ba82c058 100644 --- a/proto/protobuf/BUILD.bazel +++ b/proto/protobuf/BUILD.bazel @@ -1,5 +1,6 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("//rust:defs.bzl", "rust_binary") +load(":legacy_proto_toolchain.bzl", "legacy_proto_toolchain") load(":toolchain.bzl", "rust_proto_toolchain") package(default_visibility = ["//visibility:public"]) @@ -33,3 +34,8 @@ bzl_library( "//proto/protobuf/3rdparty:bzl_lib", ], ) + +legacy_proto_toolchain( + name = "legacy_proto_toolchain", + visibility = ["//visibility:public"], +) diff --git a/proto/protobuf/legacy_proto_toolchain.bzl b/proto/protobuf/legacy_proto_toolchain.bzl new file mode 100644 index 0000000000..a64a1d950b --- /dev/null +++ b/proto/protobuf/legacy_proto_toolchain.bzl @@ -0,0 +1,28 @@ +"""Helper that wraps --proto_compiler into a ProtoLangToolchainInfo for backwards +compatibility with --noincompatible_enable_proto_toolchain_resolution. + +Borrowed from https://github.com/bazelbuild/rules_go/pull/3919 +""" + +load( + "@rules_proto//proto:proto_common.bzl", + "ProtoLangToolchainInfo", +) + +def _legacy_proto_toolchain_impl(ctx): + return [ + ProtoLangToolchainInfo( + proto_compiler = ctx.attr._protoc.files_to_run, + ), + ] + +legacy_proto_toolchain = rule( + implementation = _legacy_proto_toolchain_impl, + attrs = { + "_protoc": attr.label( + cfg = "exec", + default = configuration_field(fragment = "proto", name = "proto_compiler"), + ), + }, + fragments = ["proto"], +) diff --git a/proto/protobuf/repositories.bzl b/proto/protobuf/repositories.bzl index 747ee3d39c..ea45dbe93a 100644 --- a/proto/protobuf/repositories.bzl +++ b/proto/protobuf/repositories.bzl @@ -19,16 +19,22 @@ load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") load("//proto/protobuf/3rdparty/crates:defs.bzl", "crate_repositories") def rust_proto_protobuf_dependencies(bzlmod = False): + """Sets up dependencies for rules_rust's proto support. + + Args: + bzlmod (bool): Whether this function is being called from a bzlmod context rather than a workspace context. + + Returns: + A list of structs containing information about root module deps to report to bzlmod's extension_metadata. + + """ if not bzlmod: maybe( http_archive, name = "rules_proto", - sha256 = "dc3fb206a2cb3441b485eb1e423165b231235a1ea9b031b4433cf7bc1fa460dd", - strip_prefix = "rules_proto-5.3.0-21.7", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz", - "https://github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz", - ], + sha256 = "6fb6767d1bef535310547e03247f7518b03487740c11b6c6adb7952033fe1295", + strip_prefix = "rules_proto-6.0.2", + url = "https://github.com/bazelbuild/rules_proto/releases/download/6.0.2/rules_proto-6.0.2.tar.gz", ) maybe( @@ -46,6 +52,14 @@ def rust_proto_protobuf_dependencies(bzlmod = False): ], ) + maybe( + http_archive, + name = "bazel_features", + sha256 = "5d7e4eb0bb17aee392143cd667b67d9044c270a9345776a5e5a3cccbc44aa4b3", + strip_prefix = "bazel_features-1.13.0", + url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.13.0/bazel_features-v1.13.0.tar.gz", + ) + return crate_repositories() # buildifier: disable=unnamed-macro diff --git a/proto/protobuf/toolchain.bzl b/proto/protobuf/toolchain.bzl index d03268b4c9..848e267c15 100644 --- a/proto/protobuf/toolchain.bzl +++ b/proto/protobuf/toolchain.bzl @@ -14,6 +14,8 @@ """Toolchain for compiling rust stubs from protobuf and gRPC.""" +load("@rules_proto//proto:proto_common.bzl", proto_toolchains = "toolchains") + # buildifier: disable=bzl-visibility load("//rust/private:utils.bzl", "name_to_crate_name") @@ -71,6 +73,10 @@ def rust_generate_proto( outs = [ctx.actions.declare_file(path + ".rs") for path in paths] output_directory = outs[0].dirname + # Throughout we use rules_rust as the name as the plugin, not rust, because rust is an unstable builtin language in protoc. + # If we use rust as the plugin name, it triggers protoc to try to use its in-built support, which is experimental. + # The naming here doesn't matter, it's arbitrary, just the plugin name and the out dir need to match, so we pick rules_rust. + if is_grpc: # Add grpc stubs to the list of outputs grpc_files = [ctx.actions.declare_file(path + "_grpc.rs") for path in paths] @@ -84,14 +90,14 @@ def rust_generate_proto( args.add_all([ "--", proto_toolchain.protoc, - "--plugin=protoc-gen-grpc-rust=" + proto_toolchain.grpc_plugin.path, - "--grpc-rust_out=" + output_directory, + "--plugin=protoc-gen-grpc-rules_rust=" + proto_toolchain.grpc_plugin.path, + "--grpc-rules_rust_out=" + output_directory, ]) executable = ctx.executable._optional_output_wrapper args.add_all([ - "--plugin=protoc-gen-rust=" + proto_toolchain.proto_plugin.path, - "--rust_out=" + output_directory, + "--plugin=protoc-gen-rules_rust=" + proto_toolchain.proto_plugin.path, + "--rules_rust_out=" + output_directory, ]) args.add_joined( @@ -118,13 +124,23 @@ def rust_generate_proto( return outs def _rust_proto_toolchain_impl(ctx): + if ctx.attr.protoc: + # buildifier: disable=print + print("WARN: rust_prost_toolchain's proto_compiler attribute is deprecated. Make sure your rules_proto dependency is at least version 6.0.0 and stop setting proto_compiler") + + proto_toolchain = proto_toolchains.find_toolchain( + ctx, + legacy_attr = "_legacy_proto_toolchain", + toolchain_type = "@rules_proto//proto:toolchain_type", + ) + return platform_common.ToolchainInfo( edition = ctx.attr.edition, grpc_compile_deps = ctx.attr.grpc_compile_deps, - grpc_plugin = ctx.file.grpc_plugin, + grpc_plugin = ctx.attr.protoc or ctx.file.grpc_plugin, proto_compile_deps = ctx.attr.proto_compile_deps, proto_plugin = ctx.file.proto_plugin, - protoc = ctx.executable.protoc, + protoc = ctx.executable.protoc or proto_toolchain.proto_compiler, ) # Default dependencies needed to compile protobuf stubs. @@ -141,7 +157,7 @@ GRPC_COMPILE_DEPS = PROTO_COMPILE_DEPS + [ rust_proto_toolchain = rule( implementation = _rust_proto_toolchain_impl, - attrs = { + attrs = dict({ "edition": attr.string( doc = "The edition used by the generated rust source.", ), @@ -168,12 +184,15 @@ rust_proto_toolchain = rule( default = Label("//proto/protobuf/3rdparty/crates:protobuf-codegen__protoc-gen-rust"), ), "protoc": attr.label( - doc = "The location of the `protoc` binary. It should be an executable target.", + doc = "The location of the `protoc` binary. It should be an executable target. Note that this attribute is deprecated - prefer to use --incompatible_enable_proto_toolchain_resolution.", executable = True, cfg = "exec", - default = Label("@com_google_protobuf//:protoc"), ), - }, + }, **proto_toolchains.if_legacy_toolchain({ + "_legacy_proto_toolchain": attr.label( + default = "//proto/protobuf:legacy_proto_toolchain", + ), + })), doc = """\ Declares a Rust Proto toolchain for use. diff --git a/proto/protobuf/transitive_repositories.bzl b/proto/protobuf/transitive_repositories.bzl index 822b4e5a00..3cbae8b6e0 100644 --- a/proto/protobuf/transitive_repositories.bzl +++ b/proto/protobuf/transitive_repositories.bzl @@ -1,7 +1,9 @@ """Definitions for loading transitive `@rules_rust//proto/protobuf` dependencies""" -load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") -load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") +load("@bazel_features//:deps.bzl", "bazel_features_deps") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies") def rust_proto_protobuf_transitive_repositories(): """Load transitive dependencies of the `@rules_rust//proto/protobuf` rules. @@ -10,6 +12,16 @@ def rust_proto_protobuf_transitive_repositories(): """ rules_proto_dependencies() - rules_proto_toolchains() + bazel_features_deps() - protobuf_deps() + maybe( + http_archive, + name = "zlib", + build_file = Label("//proto/private:BUILD.zlib.bazel"), + sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", + strip_prefix = "zlib-1.2.11", + urls = [ + "https://zlib.net/zlib-1.2.11.tar.gz", + "https://storage.googleapis.com/mirror.tensorflow.org/zlib.net/zlib-1.2.11.tar.gz", + ], + ) diff --git a/test/deps.bzl b/test/deps.bzl index 412128a8d9..53aad9b89e 100644 --- a/test/deps.bzl +++ b/test/deps.bzl @@ -63,10 +63,19 @@ def rules_rust_test_deps(): sha256 = "b8c487191eb942361af905e40172644eab490190e717c3d09bf83e87f3994fff", ) + maybe( + http_archive, + name = "rules_python", + sha256 = "778aaeab3e6cfd56d681c89f5c10d7ad6bf8d2f1a72de9de55b23081b2d31618", + strip_prefix = "rules_python-0.34.0", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.34.0/rules_python-0.34.0.tar.gz", + ) + direct_deps.extend([ struct(repo = "libc", is_dev_dep = True), struct(repo = "rules_rust_toolchain_test_target_json", is_dev_dep = True), struct(repo = "com_google_googleapis", is_dev_dep = True), + struct(repo = "rules_python", is_dev_dep = True), ]) return direct_deps diff --git a/test/deps_transitive.bzl b/test/deps_transitive.bzl index 396dc14133..389d959c5b 100644 --- a/test/deps_transitive.bzl +++ b/test/deps_transitive.bzl @@ -1,8 +1,11 @@ """Rules rust test dependencies transitive dependencies.""" load("@com_google_googleapis//:repository_rules.bzl", "switched_rules_by_language") +load("@rules_python//python:repositories.bzl", "py_repositories") def rules_rust_test_deps_transitive(): + py_repositories() + switched_rules_by_language( name = "com_google_googleapis_imports", cc = False,