1*d4726bddSHONG Yifan# gRPC Client & Server 2*d4726bddSHONG Yifan 3*d4726bddSHONG YifanThis example shows how to build a gRPC server and client in Rust with Bazel. 4*d4726bddSHONG YifanThere is a Cargo Workspace configuration and a Bazelmod configuration. Furthermore, 5*d4726bddSHONG Yifanall binary targets apply optimization from the [compiler optimization example](../03-comp-opt). 6*d4726bddSHONG Yifan 7*d4726bddSHONG YifanTo run the example with Cargo, open one terminal and start the server with: 8*d4726bddSHONG Yifan 9*d4726bddSHONG Yifan` 10*d4726bddSHONG Yifancargo run --bin grpc_server 11*d4726bddSHONG Yifan` 12*d4726bddSHONG Yifan 13*d4726bddSHONG YifanAnd, in a second terminal, to run the client: 14*d4726bddSHONG Yifan 15*d4726bddSHONG Yifan` 16*d4726bddSHONG Yifancargo run --bin grpc_client 17*d4726bddSHONG Yifan` 18*d4726bddSHONG Yifan 19*d4726bddSHONG YifanThe equivalent Bazel targets are: 20*d4726bddSHONG Yifan 21*d4726bddSHONG YifanServer: 22*d4726bddSHONG Yifan 23*d4726bddSHONG Yifan`bazel run //grpc_server:bin` 24*d4726bddSHONG Yifan 25*d4726bddSHONG YifanClient: 26*d4726bddSHONG Yifan 27*d4726bddSHONG Yifan`bazel run //grpc_client:bin` 28*d4726bddSHONG Yifan 29*d4726bddSHONG Yifan## Setup 30*d4726bddSHONG Yifan 31*d4726bddSHONG YifanThe Prost and Tonic rules do not specify a default toolchain in order to avoid mismatched dependency issues. 32*d4726bddSHONG YifanWhile the Tonic toolchain works out of the box when its dependencies are matched, however, 33*d4726bddSHONG YifanProst requires a custom toolchain that you have to define. 34*d4726bddSHONG Yifan 35*d4726bddSHONG YifanThe setup requires three steps to complete: 36*d4726bddSHONG Yifan1. Configure rules and dependencies in MODULE.bazel 37*d4726bddSHONG Yifan2. Configure a custom Prost toolchain 38*d4726bddSHONG Yifan3. Register custom Prost toolchain. 39*d4726bddSHONG Yifan 40*d4726bddSHONG YifanTo keep the build hermetic, we use the LLVM Clang compiler to compile all C/C++ dependencies. 41*d4726bddSHONG Yifan 42*d4726bddSHONG Yifan### 1) Configure rules and dependencies 43*d4726bddSHONG Yifan 44*d4726bddSHONG YifanIn your MODULE.bazel, you add the following: 45*d4726bddSHONG Yifan 46*d4726bddSHONG Yifan```starlark 47*d4726bddSHONG Yifan# rules for proto 48*d4726bddSHONG Yifan############################################################################### 49*d4726bddSHONG Yifan# https://github.com/bazelbuild/rules_proto/releases 50*d4726bddSHONG Yifanbazel_dep(name = "rules_proto", version = "6.0.2") 51*d4726bddSHONG Yifan# https://github.com/aspect-build/toolchains_protoc/releases 52*d4726bddSHONG Yifanbazel_dep(name = "toolchains_protoc", version = "0.3.1") 53*d4726bddSHONG Yifan# https://registry.bazel.build/modules/protobuf 54*d4726bddSHONG Yifanbazel_dep(name = "protobuf", version = "27.1") 55*d4726bddSHONG Yifan# rules for LLVM 56*d4726bddSHONG Yifan# https://github.com/bazel-contrib/toolchains_llvm 57*d4726bddSHONG Yifanbazel_dep(name = "toolchains_llvm", version = "1.0.0") 58*d4726bddSHONG Yifan 59*d4726bddSHONG Yifan# 1 Register LLVM 60*d4726bddSHONG Yifan############################################################################### 61*d4726bddSHONG Yifan# L L V M 62*d4726bddSHONG Yifan# https://github.com/bazel-contrib/toolchains_llvm/blob/master/tests/MODULE.bazel 63*d4726bddSHONG Yifan############################################################################### 64*d4726bddSHONG Yifanllvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm") 65*d4726bddSHONG YifanLLVM_VERSIONS = { "": "16.0.0",} 66*d4726bddSHONG Yifan 67*d4726bddSHONG Yifan# LLVM toolchain. 68*d4726bddSHONG Yifanllvm.toolchain( 69*d4726bddSHONG Yifan name = "llvm_toolchain", 70*d4726bddSHONG Yifan llvm_versions = LLVM_VERSIONS, 71*d4726bddSHONG Yifan) 72*d4726bddSHONG Yifanuse_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm") 73*d4726bddSHONG Yifanregister_toolchains("@llvm_toolchain//:all") 74*d4726bddSHONG Yifan 75*d4726bddSHONG Yifan# 2 Register Proto toolchain 76*d4726bddSHONG Yifan############################################################################### 77*d4726bddSHONG Yifan# Proto toolchain 78*d4726bddSHONG Yifanregister_toolchains("@rules_rust//proto/protobuf:default-proto-toolchain") 79*d4726bddSHONG Yifan 80*d4726bddSHONG Yifan# Custom Prost toolchain will be added later. See next section 81*d4726bddSHONG Yifan 82*d4726bddSHONG Yifan# 3 Register proto / prost / tonic crates 83*d4726bddSHONG Yifan############################################################################### 84*d4726bddSHONG Yifancrate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate") 85*d4726bddSHONG Yifan 86*d4726bddSHONG Yifan# protobufs / gRPC 87*d4726bddSHONG Yifancrate.spec( 88*d4726bddSHONG Yifan package = "prost", 89*d4726bddSHONG Yifan version = "0.12", 90*d4726bddSHONG Yifan) 91*d4726bddSHONG Yifancrate.spec( 92*d4726bddSHONG Yifan default_features = False, 93*d4726bddSHONG Yifan package = "prost-types", 94*d4726bddSHONG Yifan version = "0.12", 95*d4726bddSHONG Yifan) 96*d4726bddSHONG Yifancrate.spec( 97*d4726bddSHONG Yifan features = ["transport"], 98*d4726bddSHONG Yifan package = "tonic", 99*d4726bddSHONG Yifan version = "0.11", 100*d4726bddSHONG Yifan) 101*d4726bddSHONG Yifancrate.spec( 102*d4726bddSHONG Yifan package = "tonic-build", 103*d4726bddSHONG Yifan version = "0.11", 104*d4726bddSHONG Yifan) 105*d4726bddSHONG Yifancrate.spec( 106*d4726bddSHONG Yifan package = "protoc-gen-prost", 107*d4726bddSHONG Yifan version = "0.3.1", 108*d4726bddSHONG Yifan) 109*d4726bddSHONG Yifancrate.annotation( 110*d4726bddSHONG Yifan crate = "protoc-gen-prost", 111*d4726bddSHONG Yifan gen_binaries = ["protoc-gen-prost"], 112*d4726bddSHONG Yifan) 113*d4726bddSHONG Yifancrate.spec( 114*d4726bddSHONG Yifan package = "protoc-gen-tonic", 115*d4726bddSHONG Yifan version = "0.4.0", 116*d4726bddSHONG Yifan) 117*d4726bddSHONG Yifancrate.annotation( 118*d4726bddSHONG Yifan crate = "protoc-gen-tonic", 119*d4726bddSHONG Yifan gen_binaries = ["protoc-gen-tonic"], 120*d4726bddSHONG Yifan) 121*d4726bddSHONG Yifan 122*d4726bddSHONG Yifan# Other Rust dependencies ... 123*d4726bddSHONG Yifan 124*d4726bddSHONG Yifancrate.from_specs() 125*d4726bddSHONG Yifanuse_repo(crate, "crates") 126*d4726bddSHONG Yifan``` 127*d4726bddSHONG Yifan 128*d4726bddSHONG Yifan### 2) Configure a custom Prost toolchain 129*d4726bddSHONG Yifan 130*d4726bddSHONG YifanConfiguring a custom Prost toolchain is straightforward, you create a new folder with an empty BUILD.bazl file, and add 131*d4726bddSHONG Yifanthe toolchain definition. 132*d4726bddSHONG YifanAs your Bazel setup grows over time, it is a best practice to put all custom macros, rules, and toolchains in a 133*d4726bddSHONG Yifandedicated folder, for example: `build/`. 134*d4726bddSHONG Yifan 135*d4726bddSHONG YifanSuppose you have your BUILD.bazl file in `build/prost_toolchain/BUILD.bazel`, then add the following content: 136*d4726bddSHONG Yifan 137*d4726bddSHONG Yifan```starlark 138*d4726bddSHONG Yifanload("@rules_rust//proto/prost:defs.bzl", "rust_prost_toolchain") 139*d4726bddSHONG Yifanload("@rules_rust//rust:defs.bzl", "rust_library_group") 140*d4726bddSHONG Yifan 141*d4726bddSHONG Yifanrust_library_group( 142*d4726bddSHONG Yifan name = "prost_runtime", 143*d4726bddSHONG Yifan deps = [ 144*d4726bddSHONG Yifan "@crates//:prost", 145*d4726bddSHONG Yifan ], 146*d4726bddSHONG Yifan) 147*d4726bddSHONG Yifan 148*d4726bddSHONG Yifanrust_library_group( 149*d4726bddSHONG Yifan name = "tonic_runtime", 150*d4726bddSHONG Yifan deps = [ 151*d4726bddSHONG Yifan ":prost_runtime", 152*d4726bddSHONG Yifan "@crates//:tonic", 153*d4726bddSHONG Yifan ], 154*d4726bddSHONG Yifan) 155*d4726bddSHONG Yifan 156*d4726bddSHONG Yifanrust_prost_toolchain( 157*d4726bddSHONG Yifan name = "prost_toolchain_impl", 158*d4726bddSHONG Yifan prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost", 159*d4726bddSHONG Yifan prost_runtime = ":prost_runtime", 160*d4726bddSHONG Yifan prost_types = "@crates//:prost-types", 161*d4726bddSHONG Yifan proto_compiler = "@protobuf//:protoc", 162*d4726bddSHONG Yifan tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic", 163*d4726bddSHONG Yifan tonic_runtime = ":tonic_runtime", 164*d4726bddSHONG Yifan) 165*d4726bddSHONG Yifan 166*d4726bddSHONG Yifantoolchain( 167*d4726bddSHONG Yifan name = "prost_toolchain", 168*d4726bddSHONG Yifan toolchain = "prost_toolchain_impl", 169*d4726bddSHONG Yifan toolchain_type = "@rules_rust//proto/prost:toolchain_type", 170*d4726bddSHONG Yifan) 171*d4726bddSHONG Yifan``` 172*d4726bddSHONG Yifan 173*d4726bddSHONG YifanThe Prost and Tonic dependencies are pulled from the previously configured 174*d4726bddSHONG Yifancrate dependencies in the MODULE file. With this custom toolchain in place, the last step is to register it. 175*d4726bddSHONG Yifan 176*d4726bddSHONG Yifan### 3. Register custom Prost toolchain. 177*d4726bddSHONG Yifan 178*d4726bddSHONG YifanIn your MODULE.bazel file, locate your toolchains and add the following entry right below the proto toolchain. 179*d4726bddSHONG Yifan 180*d4726bddSHONG Yifan```starlark 181*d4726bddSHONG Yifan# 2 Register Proto toolchain 182*d4726bddSHONG Yifan############################################################################### 183*d4726bddSHONG Yifan# Proto toolchain 184*d4726bddSHONG Yifanregister_toolchains("@rules_rust//proto/protobuf:default-proto-toolchain") 185*d4726bddSHONG Yifan 186*d4726bddSHONG Yifan# Custom Prost toolchain 187*d4726bddSHONG Yifanregister_toolchains("@//build/prost_toolchain") 188*d4726bddSHONG Yifan``` 189*d4726bddSHONG Yifan 190*d4726bddSHONG YifanPay attention to the path, `build/prost_toolchain` because if your toolchain 191*d4726bddSHONG Yifanis in a different folder, you have to update this path to make the build work. 192*d4726bddSHONG Yifan 193*d4726bddSHONG Yifan## Usage 194*d4726bddSHONG Yifan 195*d4726bddSHONG YifanOnce the setup has been completed, you use the proto & prost targets as you normally do. For example, to configure rust 196*d4726bddSHONG Yifanbindings for a proto file, just add the target: 197*d4726bddSHONG Yifan 198*d4726bddSHONG Yifan```starlark 199*d4726bddSHONG Yifanload("@rules_proto//proto:defs.bzl", "proto_library") 200*d4726bddSHONG Yifanload("@rules_rust//proto/prost:defs.bzl", "rust_prost_library") 201*d4726bddSHONG Yifan 202*d4726bddSHONG Yifan# Build proto files 203*d4726bddSHONG Yifan# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_proto_library 204*d4726bddSHONG Yifanproto_library( 205*d4726bddSHONG Yifan name = "proto_bindings", 206*d4726bddSHONG Yifan srcs = [ 207*d4726bddSHONG Yifan "proto/helloworld.proto", 208*d4726bddSHONG Yifan ], 209*d4726bddSHONG Yifan) 210*d4726bddSHONG Yifan 211*d4726bddSHONG Yifan# Generate Rust bindings from the generated proto files 212*d4726bddSHONG Yifan# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_prost_library 213*d4726bddSHONG Yifanrust_prost_library( 214*d4726bddSHONG Yifan name = "rust_proto", 215*d4726bddSHONG Yifan proto = ":proto_bindings", 216*d4726bddSHONG Yifan visibility = ["//visibility:public"], 217*d4726bddSHONG Yifan) 218*d4726bddSHONG Yifan``` 219*d4726bddSHONG Yifan 220*d4726bddSHONG YifanFrom there, you 221*d4726bddSHONG Yifanjust [follow the target documentation](https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_proto_library). 222