Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust support #226

Closed
wants to merge 11 commits into from
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
# based on the name of the directory bazel is cloned into.
/bazel-*
/tests/build_in_workspace_root/bazel-*
/rust/raze/target
/rust/raze/Cargo.lock
48 changes: 25 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,21 @@ of this project are to:

### Rules

| Language | Compile <sup>1</sup> | Build <sup>2</sup> | gRPC <sup>3</sup> |
| ---------------------------: | -----------: | --------: | -------- |
| [C++](cpp) | [cc_proto_compile](cpp#cc_proto_compile) | [cc_proto_library](cpp#cc_proto_library) [v3.4.0](https://github.com/grpc/grpc/releases/tag/v1.6.1) | [v1.6.1](https://github.com/grpc/grpc/releases/tag/v1.6.1) |
| [C#](csharp) | [csharp_proto_compile](csharp#csharp_proto_compile) | [csharp_proto_library](csharp#csharp_proto_library) | [1.0.0](https://www.nuget.org/packages/Grpc/) |
| [Closure](closure) | [closure_proto_compile](closure#closure_proto_compile) | [closure_proto_library](closure#closure_proto_library) | |
| [Go](go) | [go_proto_compile](go#go_proto_compile) | [go_proto_library](go#go_proto_library) | [v1.6.0](https://github.com/grpc/grpc-go/releases/tag/v1.6.0) |
| [Go (gogo)](gogo) | [gogo_proto_compile](gogo#gogo_proto_compile) | [gogo_proto_library](gogo#gogo_proto_library) | [fb8a35](https://github.com/gogo/protobuf/commit/fb8a359905af6e2b6517cccda0ba25915322ee88) |
| [gRPC gateway](grpc_gateway) | [grpc_gateway_proto_compile](grpc_gateway#grpc_gateway_proto_compile)<br/>[grpc_gateway_swagger_compile](grpc_gateway#grpc_gateway_swagger_compile) | [grpc_gateway_proto_library](grpc_gateway#grpc_gateway_proto_library)<br/>[grpc_gateway_binary](grpc_gateway#grpc_gateway_binary) | [v1.2.2+ (f2862b)](https://github.com/grpc-ecosystem/grpc-gateway/commit/f2862b476edcef83412c7af8687c9cd8e4097c0f) |
| [Java](java) | [java_proto_compile](java#java_proto_compile) | [java_proto_library](java#java_proto_library) | [v1.7.0](https://github.com/grpc/grpc-java/releases/tag/v1.7.0) |
| [Node](node) | [node_proto_compile](node#node_proto_compile) | [node_proto_library](node#node_proto_library) | [1.6.0](https://www.npmjs.com/package/grpc) |
| [Objective-C](objc) | [objc_proto_compile](objc#objc_proto_compile) | [objc_proto_library](objc#objc_proto_library) <sup>4</sup> | [v1.6.1](https://github.com/grpc/grpc/commit/f5600e99be0fdcada4b3039c0f656a305264884a) |
| [Python](python) | [py_proto_compile](python#py_proto_compile) | [py_proto_library](python#py_proto_library) | [v1.6.1](https://github.com/grpc/grpc/commit/f5600e99be0fdcada4b3039c0f656a305264884a) |
| [Ruby](ruby) | [ruby_proto_compile](ruby#ruby_proto_compile) | | [v1.6.1](https://github.com/grpc/grpc/commit/f5600e99be0fdcada4b3039c0f656a305264884a) |
| Custom [proto_language](protobuf#proto_language) | [proto_compile](protobuf#proto_compile) | | |
| Language | Compile <sup>1</sup> | Build <sup>2</sup> | gRPC <sup>3</sup> |
| -----------------------------------------------: | --------------------------------------------------------------------------------------------------------------------------------------------------: | --------------------------------------------------------------------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------ |
| [C++](cpp) | [cc_proto_compile](cpp#cc_proto_compile) | [cc_proto_library](cpp#cc_proto_library) [v3.4.0](https://github.com/grpc/grpc/releases/tag/v1.6.1) | [v1.6.1](https://github.com/grpc/grpc/releases/tag/v1.6.1) |
| [C#](csharp) | [csharp_proto_compile](csharp#csharp_proto_compile) | [csharp_proto_library](csharp#csharp_proto_library) | [1.0.0](https://www.nuget.org/packages/Grpc/) |
| [Closure](closure) | [closure_proto_compile](closure#closure_proto_compile) | [closure_proto_library](closure#closure_proto_library) | |
| [Go](go) | [go_proto_compile](go#go_proto_compile) | [go_proto_library](go#go_proto_library) | [v1.6.0](https://github.com/grpc/grpc-go/releases/tag/v1.6.0) |
| [Go (gogo)](gogo) | [gogo_proto_compile](gogo#gogo_proto_compile) | [gogo_proto_library](gogo#gogo_proto_library) | [fb8a35](https://github.com/gogo/protobuf/commit/fb8a359905af6e2b6517cccda0ba25915322ee88) |
| [gRPC gateway](grpc_gateway) | [grpc_gateway_proto_compile](grpc_gateway#grpc_gateway_proto_compile)<br/>[grpc_gateway_swagger_compile](grpc_gateway#grpc_gateway_swagger_compile) | [grpc_gateway_proto_library](grpc_gateway#grpc_gateway_proto_library)<br/>[grpc_gateway_binary](grpc_gateway#grpc_gateway_binary) | [v1.2.2+ (f2862b)](https://github.com/grpc-ecosystem/grpc-gateway/commit/f2862b476edcef83412c7af8687c9cd8e4097c0f) |
| [Java](java) | [java_proto_compile](java#java_proto_compile) | [java_proto_library](java#java_proto_library) | [v1.7.0](https://github.com/grpc/grpc-java/releases/tag/v1.7.0) |
| [Node](node) | [node_proto_compile](node#node_proto_compile) | [node_proto_library](node#node_proto_library) | [1.6.0](https://www.npmjs.com/package/grpc) |
| [Objective-C](objc) | [objc_proto_compile](objc#objc_proto_compile) | [objc_proto_library](objc#objc_proto_library) <sup>4</sup> | [v1.6.1](https://github.com/grpc/grpc/commit/f5600e99be0fdcada4b3039c0f656a305264884a) |
| [Python](python) | [py_proto_compile](python#py_proto_compile) | [py_proto_library](python#py_proto_library) | [v1.6.1](https://github.com/grpc/grpc/commit/f5600e99be0fdcada4b3039c0f656a305264884a) |
| [Ruby](ruby) | [ruby_proto_compile](ruby#ruby_proto_compile) | | [v1.6.1](https://github.com/grpc/grpc/commit/f5600e99be0fdcada4b3039c0f656a305264884a) |
| [Rust](rust) | [rust_proto_compile](rust#rust_proto_compile) | | [v1.6.1](https://github.com/grpc/grpc/commit/f5600e99be0fdcada4b3039c0f656a305264884a) |

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add rust_proto_library here as well?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

| Custom [proto_language](protobuf#proto_language) | [proto_compile](protobuf#proto_compile) | | |

> Refer to [`DEPENDENCIES.md`](DEPENDENCIES.md) for a more detailed
> summary of workspace dependencies / versions.
Expand Down Expand Up @@ -101,15 +102,16 @@ go_proto_repositories()
Several languages have other `rules_*` dependencies that you'll need
to load before the `*_proto_repositories()` function is invoked:

| Language | Requires |
| ---: | :--- |
| closure_proto_repositories | [rules_closure](https://github.com/bazelbuild/rules_closure) |
| csharp_proto_repositories | [rules_dotnet](https://github.com/bazelbuild/rules_dotnet) |
| go_proto_repositories | [rules_go](https://github.com/bazelbuild/rules_go) |
| gogo_proto_repositories | [rules_go](https://github.com/bazelbuild/rules_go) |
| grpc_gateway_proto_repositories | [rules_go](https://github.com/bazelbuild/rules_go) |
| node_proto_repositories | [rules_node](https://github.com/pubref/rules_node) |
| py_proto_repositories <sup>1</sup> | [rules_python](https://github.com/bazelbuild/rules_python) |
| Language | Requires |
| ---------------------------------: | :----------------------------------------------------------- |
| closure_proto_repositories | [rules_closure](https://github.com/bazelbuild/rules_closure) |
| csharp_proto_repositories | [rules_dotnet](https://github.com/bazelbuild/rules_dotnet) |
| go_proto_repositories | [rules_go](https://github.com/bazelbuild/rules_go) |
| gogo_proto_repositories | [rules_go](https://github.com/bazelbuild/rules_go) |
| grpc_gateway_proto_repositories | [rules_go](https://github.com/bazelbuild/rules_go) |
| node_proto_repositories | [rules_node](https://github.com/pubref/rules_node) |
| py_proto_repositories <sup>1</sup> | [rules_python](https://github.com/bazelbuild/rules_python) |
| rust_proto_repositories | [rules_rust](https://github.com/bazelbuild/rules_rust) |

> <sup>1</sup> Only needed for python grpc support.

Expand Down
25 changes: 22 additions & 3 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,34 @@ github_archive(
sha256 = "7d06126d0d10ea8e63cc7eaf774d9ecebcd9583094ee8e93b0035da659eab5c1",
)

load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories", "pip_import")
load("@io_bazel_rules_python//python:pip.bzl", "pip_import", "pip_repositories")

pip_repositories()

pip_import(
name = "pip_grpcio",
requirements = "//python:requirements.txt",
name = "pip_grpcio",
requirements = "//python:requirements.txt",
)

load("@pip_grpcio//:requirements.bzl", pip_grpcio_install = "pip_install")

pip_grpcio_install()

# ================================================================
# rust_proto_library support requires rules_rust (HEAD)
# ================================================================

github_archive(
name = "io_bazel_rules_rust",
commit = "af9821bf3378b525ec3db0af3b1ca388920a8fb0",
org = "bazelbuild",
repo = "rules_rust",
sha256 = "3c53a5ead9db93460a03a85cd28ec5579f608a0bd044b7d767b1dfa85023ad78",
)

load("@io_bazel_rules_rust//rust:repositories.bzl", "rust_repositories")

rust_repositories()

# ================================================================
# Specific Languages Support
Expand Down Expand Up @@ -156,3 +171,7 @@ py_proto_repositories()
load("//ruby:rules.bzl", "ruby_proto_repositories")

ruby_proto_repositories()

load("//rust:rules.bzl", "rust_proto_repositories")

rust_proto_repositories()
21 changes: 21 additions & 0 deletions examples/helloworld/rust/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
load("//rust:rules.bzl", "rust_proto_library")

rust_proto_library(
name = "helloworld",
proto_deps = [
"//examples/proto:rust",
],
protos = ["//examples/helloworld/proto:protos"],
verbose = 0,
visibility = ["//examples/helloworld/rust:__subpackages__"],
with_grpc = True,
)

sh_test(
name = "test_rust",
srcs = ["test_rust.sh"],
data = [
"//examples/helloworld/rust/greeter_client",
"//examples/helloworld/rust/greeter_server",
],
)
9 changes: 9 additions & 0 deletions examples/helloworld/rust/greeter_client/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary")
load("//rust:rules.bzl", "GRPC_COMPILE_DEPS", "rust_proto_library")

rust_binary(
name = "greeter_client",
srcs = ["greeter_client.rs"],
deps = ["//examples/helloworld/rust:helloworld"] + GRPC_COMPILE_DEPS,
visibility = ["//examples/helloworld/rust:__subpackages__"],
)
29 changes: 29 additions & 0 deletions examples/helloworld/rust/greeter_client/greeter_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
extern crate grpc;
extern crate helloworld;

use std::env;
use std::str::FromStr;

use helloworld::*;

fn parse_args() -> (String, u16) {
let mut name = "world".to_owned();
let mut port = 50051;
for arg in env::args().skip(1) {
if arg.starts_with("-p=") {
port = u16::from_str(&arg[3..]).unwrap()
} else {
name = arg.to_owned();
}
}
(name, port)
}

fn main() {
let (name, port) = parse_args();
let client = GreeterClient::new_plain("::1", port, Default::default()).unwrap();
let mut req = HelloRequest::new();
req.set_name(name);
let resp = client.say_hello(grpc::RequestOptions::new(), req);
println!("{:?}", resp.wait());
}
9 changes: 9 additions & 0 deletions examples/helloworld/rust/greeter_server/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary")
load("//rust:rules.bzl", "GRPC_COMPILE_DEPS", "rust_proto_library")

rust_binary(
name = "greeter_server",
srcs = ["greeter_server.rs"],
deps = ["//examples/helloworld/rust:helloworld"] + GRPC_COMPILE_DEPS,
visibility = ["//examples/helloworld/rust:__subpackages__"],
)
36 changes: 36 additions & 0 deletions examples/helloworld/rust/greeter_server/greeter_server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
extern crate helloworld;
extern crate grpc;
extern crate tls_api_stub;

use std::thread;
use std::env;
use std::str::FromStr;

use helloworld::*;

struct GreeterImpl;

impl Greeter for GreeterImpl {
fn say_hello(&self, _m: grpc::RequestOptions, req: HelloRequest) -> grpc::SingleResponse<HelloReply> {
let mut r = HelloReply::new();
let name = if req.get_name().is_empty() { "world" } else { req.get_name() };
println!("greeting request from {}", name);
r.set_message(format!("Hello {}", name));
grpc::SingleResponse::completed(r)
}
}

fn main() {
let mut server = grpc::ServerBuilder::<tls_api_stub::TlsAcceptor>::new();
let port = u16::from_str(&env::args().nth(1).unwrap_or("50051".to_owned())).unwrap();
server.http.set_port(port);
server.add_service(GreeterServer::new_service_def(GreeterImpl));
server.http.set_cpu_pool_threads(4);
let server = server.build().expect("server");
let port = server.local_addr().port().unwrap();
println!("greeter server started on port {}", port);

loop {
thread::park();
}
}
57 changes: 57 additions & 0 deletions examples/helloworld/rust/test_rust.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash
# A simple test for the rust client-server.
set -eu
set -o pipefail

# Try to locate the runfiles directory
get_runfiles_dir() {
if [ -d "${BASH_SOURCE[0]}.runfiles" ]; then
cd "${BASH_SOURCE[0]}.runfiles/org_pubref_rules_protobuf"
elif ! [ -d "${PWD}/../org_pubref_rules_protobuf" ]; then
cd "$(readlink ${BASH_SOURCE[0]}).runfiles/org_pubref_rules_protobuf"
fi
pwd -P
}

RUNFILES="${RUNFILES:-"$(get_runfiles_dir)"}"
TEST_TMPDIR="${TEST_TMPDIR:-$(mktemp -d ${TMP:-/tmp}/tmp.XXXXXXXX)}"
SERVER="${RUNFILES}/examples/helloworld/rust/greeter_server/greeter_server"
CLIENT="${RUNFILES}/examples/helloworld/rust/greeter_client/greeter_client"

SERVER_LOG="${TEST_TMPDIR}/server.log"
CLIENT_LOG="${TEST_TMPDIR}/client.log"

# Simply match a string from the log
expect_log() {
local log="${2-${CLIENT_LOG}}"
if ! grep -qF "$1" "${log}"; then
echo "Substring '$1' not found in ${log}." >&2
echo "=== ${log} ===" >&2
cat "${log}" >&2
echo "=== end of ${log} ===" >&2
fi
}

# Start the server and get its pid and its port number
"${SERVER}" 0 | tee "${SERVER_LOG}" &
server_pid=$?
trap "kill ${server_pid}" EXIT

while ! grep -q "greeter server started on port" "${SERVER_LOG}" &>/dev/null; do
sleep 1
done

PORT=$(grep "greeter server started on port" "${SERVER_LOG}" \
| sed -E 's/^.*port //')

# Now run the client
"${CLIENT}" -p="${PORT}" | tee "${CLIENT_LOG}"
expect_log 'message: "Hello world"'
expect_log 'greeting request from world' "${SERVER_LOG}"

"${CLIENT}" -p="${PORT}" thou | tee "${CLIENT_LOG}"
expect_log 'message: "Hello thou"'
expect_log 'greeting request from thou' "${SERVER_LOG}"

echo ""
echo "SUCCESS"
7 changes: 7 additions & 0 deletions examples/proto/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ load("//objc:rules.bzl", "objc_proto_compile")
load("//python:rules.bzl", "py_proto_library")
load("//protobuf:rules.bzl", "proto_compile")
load("//ruby:rules.bzl", "ruby_proto_compile")
load("//rust:rules.bzl", "rust_proto_library")

filegroup(
name = "protos",
Expand Down Expand Up @@ -69,6 +70,12 @@ ruby_proto_compile(
with_grpc = False,
)

rust_proto_library(
name = "rust",
protos = [":protos"],
with_grpc = False,
)

# This conflicts with outputs from other rules here but demonstrates
# how to generate multiple language outputs simultaneously.
#
Expand Down
13 changes: 13 additions & 0 deletions protobuf/internal/proto_compile.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ def _build_output_files(run, builder):
build_package_path = generated_path + "/" + build_package_path

path = _get_relative_dirname(run, build_package_path, file)
if run.lang.output_to_libsubdir:
path.append(ctx.label.name)

for ext in exts:
temppath = list(path)
Expand All @@ -236,6 +238,15 @@ def _build_output_libdir(run, builder):
_build_output_files(run, builder)


def _build_output_libsubdir(run, builder):
# This is currently rust-specific, to output to a specific crate.
ctx = run.ctx
execdir = run.data.execdir
name = run.lang.name
builder[name + "_outdir"] = _get_offset_path(execdir, run.data.descriptor_set.dirname) + "/" + ctx.label.name
_build_output_files(run, builder)


def _build_descriptor_set(data, builder):
"""Build a list of files we expect to be generated."""
builder["args"] += ["--descriptor_set_out=" + _get_offset_path(data.execdir, data.descriptor_set.path)]
Expand Down Expand Up @@ -687,6 +698,8 @@ def _proto_compile_impl(ctx):
_build_output_library(run, builder)
elif run.lang.output_to_libdir:
_build_output_libdir(run, builder)
elif run.lang.output_to_libsubdir:
_build_output_libsubdir(run, builder)
else:
_build_output_files(run, builder)
if run.lang.go_prefix or ctx.attr.go_importpath: # golang-specific
Expand Down
Loading