rust: refactor {prost_proto|tonic_grpc}_library macros

So, I think I understand where the original work is coming from, but
fundamentally disagree with its implementation.

The idea was to create "drop in" macros that you can use to easily
create rust pb bindings, abstracting over the varied and complex tooling
that the rust ecosystem requires.

I believe this to be a mistake:

1. Potential for version mismatch for rlib symbols

    Anyone who remembers the "bad old days" of tokio 0.x (and futures
    0.1, for that matter) knows the pain of attempting to link against
    two different versions of the same symbol, because some dep you have
    is using an older version of the exported symbol.

    The use of "bundled" fallbacks in the varied xxx_dep(s) macro args
    invite this same issue.

    Instead, callers should made aware of the needed deps and be
    required to provide their own, ensuring their projects remain
    coherent.

    The bundled should *only* be used for creating the needed binaries
    for protoc codegen

2. Focus on UX over documentation

    The entire //rust:... subsystem of this project is misleadingly
    documented, to the point that it is easier to simply read the
    entire code base, rather than the docs.

    There was an attempt to compensate for this via the examples/ and
    ease-of-use in the public macros and rules, however the lack of
    documentation leaves users that need to integrate with more complex
    monorepos completely confused about how to correctly satisfy the
    mandatory args, what expected values for these args are, etc

Therefore, this refactor of the top level *_library macros adds proper
documentation each, and simplifies the args and notifies the caller of
the requirements to call each macro.
This commit is contained in:
Paul Stemmet 2024-09-28 00:48:14 +00:00
parent decb8d8c26
commit 87aee8e13b
Signed by: Paul Stemmet
GPG Key ID: EDEA539F594E7E75
2 changed files with 101 additions and 43 deletions

View File

@ -1,23 +1,56 @@
"""Generated definition of rust_prost_proto_library."""
load("@rules_rust//rust:defs.bzl", "rust_library")
load("//:defs.bzl", "bazel_build_rule_common_attrs", "proto_compile_attrs")
load("//rust:common.bzl", "create_name_to_label", "prepare_prost_proto_deps", "prost_compile_attrs")
load("//rust:rust_prost_proto_compile.bzl", "rust_prost_proto_compile")
load("//:defs.bzl", "bazel_build_rule_common_attrs", "proto_compile_attrs")
load("//rust:rust_fixer.bzl", "rust_proto_crate_fixer", "rust_proto_crate_root")
load("@rules_rust//rust:defs.bzl", "rust_library")
def rust_prost_proto_library(name, **kwargs): # buildifier: disable=function-docstring
def rust_prost_proto_library(name, **kwargs):
"""
Wrapper around %rust_prost_proto_compile and @rules_rust://defs.bzl%rust_library
that creates a rust_library binding to the given $protos.
This macro requires that you pass labels to the following crates as a part
of your $deps:
- pbjson, pbjson-types
- prost, prost-types
- serde
and $proc_macro_deps:
- prost-derive
Failing to do so will lead to compile errors, as the default set of protoc
plugins generate code that requires these crates' types be in scope.
Args:
* name | The name of the rust_library target
* protos | List of proto_library labels to compile
* declared_proto_packages | List of protobuf 'package's defined in $protos
* deps | List of deps to link into the rust_library
* proc_macro_deps | List of proc_macro_deps to link into the rust_library
? crate_name | Override the rust_library's crate name (default: $name, normalized)
? options | Dict plugin-label -> strings of options to pass to protoc plugins
? extra_protoc_args | Extra args to pass directly to protoc
? extra_protoc_files | Extra data file labels to make available to protoc invocations
? verbose | Int 0-5, enables debugging logs during protoc invocations (default: 0)
? **kwargs | https://bazel.build/reference/be/common-definitions#common-attributes
"""
# Compile protos
name_pb = name + "_pb"
name_pb = name + "_pb"
name_fixed = name_pb + "_fixed"
name_root = name + "_root"
name_root = name + "_root"
prost_proto_deps = kwargs.get("prost_proto_deps", [])
prost_proto_deps = kwargs.get("prost_proto_deps", [])
prost_proto_compiled_targets = prepare_prost_proto_deps(prost_proto_deps)
rust_prost_proto_compile(
name = name_pb,
crate_name = name,
name = name_pb,
crate_name = name,
prost_proto_deps = prost_proto_compiled_targets,
**{
k: v
@ -30,28 +63,24 @@ def rust_prost_proto_library(name, **kwargs): # buildifier: disable=function-do
# Fix up imports
rust_proto_crate_fixer(
name = name_fixed,
name = name_fixed,
compilation = name_pb,
)
rust_proto_crate_root(
name = name_root,
name = name_root,
crate_dir = name_fixed,
)
# Create rust_prost library
rust_library(
name = name,
edition = "2021",
crate_root = name_root,
crate_name = kwargs.get("crate_name"),
srcs = [name_fixed],
deps = kwargs.get("prost_deps", [create_name_to_label("prost"), create_name_to_label("prost-types")]) +
kwargs.get("pbjson_deps", [create_name_to_label("pbjson-types"), create_name_to_label("pbjson")]) +
kwargs.get("serde_deps", [create_name_to_label("serde")]) +
kwargs.get("deps", []) +
prost_proto_deps,
proc_macro_deps = [kwargs.get("prost_derive_dep", create_name_to_label("prost-derive"))],
name = name,
edition = "2021",
crate_root = name_root,
crate_name = kwargs.get("crate_name"),
srcs = [name_fixed],
deps = kwargs.get("deps", []) + prost_proto_deps,
proc_macro_deps = kwargs.get("proc_macro_deps", []),
**{
k: v
for (k, v) in kwargs.items()

View File

@ -1,23 +1,57 @@
"""Generated definition of rust_tonic_grpc_library."""
load("@rules_rust//rust:defs.bzl", "rust_library")
load("//:defs.bzl", "bazel_build_rule_common_attrs", "proto_compile_attrs")
load("//rust:common.bzl", "create_name_to_label", "prepare_prost_proto_deps", "prost_compile_attrs")
load("//rust:rust_tonic_grpc_compile.bzl", "rust_tonic_grpc_compile")
load("//:defs.bzl", "bazel_build_rule_common_attrs", "proto_compile_attrs")
load("//rust:rust_fixer.bzl", "rust_proto_crate_fixer", "rust_proto_crate_root")
load("@rules_rust//rust:defs.bzl", "rust_library")
def rust_tonic_grpc_library(name, **kwargs): # buildifier: disable=function-docstring
def rust_tonic_grpc_library(name, **kwargs):
"""
Wrapper around %rust_tonic_grpc_compile and @rules_rust://defs.bzl%rust_library
that creates a rust_library binding to the given $protos.
This macro requires that you pass labels to the following crates as a part
of your $deps:
- pbjson, pbjson-types
- prost, prost-types
- serde
- tonic
and $proc_macro_deps:
- prost-derive
Failing to do so will lead to compile errors, as the default set of protoc
plugins generate code that requires these crates' types be in scope.
Args:
* name | The name of the rust_library target
* protos | List of proto_library labels to compile
* declared_proto_packages | List of protobuf 'package's defined in $protos
* deps | List of deps to link into the rust_library
* proc_macro_deps | List of proc_macro_deps to link into the rust_library
? crate_name | Override the rust_library's crate name (default: $name, normalized)
? options | Dict plugin-label -> strings of options to pass to protoc plugins
? extra_protoc_args | Extra args to pass directly to protoc
? extra_protoc_files | Extra data file labels to make available to protoc invocations
? verbose | Int 0-5, enables debugging logs during protoc invocations (default: 0)
? **kwargs | https://bazel.build/reference/be/common-definitions#common-attributes
"""
# Compile protos
name_pb = name + "_pb"
name_pb = name + "_pb"
name_fixed = name_pb + "_fixed"
name_root = name + "_root"
name_root = name + "_root"
prost_proto_deps = kwargs.get("prost_proto_deps", [])
prost_proto_deps = kwargs.get("prost_proto_deps", [])
prost_proto_compiled_targets = prepare_prost_proto_deps(prost_proto_deps)
rust_tonic_grpc_compile(
name = name_pb,
crate_name = name,
name = name_pb,
crate_name = name,
prost_proto_deps = prost_proto_compiled_targets,
**{
k: v
@ -30,29 +64,24 @@ def rust_tonic_grpc_library(name, **kwargs): # buildifier: disable=function-doc
# Fix up imports
rust_proto_crate_fixer(
name = name_fixed,
name = name_fixed,
compilation = name_pb,
)
rust_proto_crate_root(
name = name_root,
name = name_root,
crate_dir = name_fixed,
)
# Create rust_tonic library
rust_library(
name = name,
edition = "2021",
crate_root = name_root,
crate_name = kwargs.get("crate_name"),
srcs = [name_fixed],
deps = kwargs.get("prost_deps", [create_name_to_label("prost"), create_name_to_label("prost-types")]) +
kwargs.get("pbjson_deps", [create_name_to_label("pbjson-types"), create_name_to_label("pbjson")]) +
kwargs.get("serde_deps", [create_name_to_label("serde")]) +
kwargs.get("tonic_deps", [create_name_to_label("tonic")]) +
kwargs.get("deps", []) +
prost_proto_deps,
proc_macro_deps = [kwargs.get("prost_derive_dep", create_name_to_label("prost-derive"))],
name = name,
edition = "2021",
crate_root = name_root,
crate_name = kwargs.get("crate_name"),
srcs = [name_fixed],
deps = kwargs.get("deps", []) + prost_proto_deps,
proc_macro_deps = kwargs.get("proc_macro_deps", []),
**{
k: v
for (k, v) in kwargs.items()