1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
"""This file implements rust_proto_library."""
load("@rules_rust//rust:defs.bzl", "rust_common")
load("//bazel/common:proto_common.bzl", "proto_common")
load("//bazel/common:proto_info.bzl", "ProtoInfo")
load(
"//rust/bazel:aspects.bzl",
"RustProtoInfo",
"label_to_crate_name",
"proto_rust_toolchain_label",
"rust_cc_proto_library_aspect",
"rust_upb_proto_library_aspect",
)
ProtoCrateNamesInfo = provider(
doc = """A provider that contains both names a Protobuf crate has throughout the build.""",
fields = {
"crate_name": "The name of rust_proto_library.",
"old_crate_name": "The name of the proto_library.",
},
)
def rust_proto_library(name, deps, **args):
"""Declares all the boilerplate needed to use Rust protobufs conveniently.
Hopefully no user will ever need to read this code.
Args:
name: name of the Rust protobuf target.
deps: proto_library target for which to generate Rust gencode.
**args: other args passed to the rust_<kernel>_proto_library targets.
"""
if not name.endswith("_rust_proto"):
fail(
"Name rust_proto_library target should end with `_rust_proto`, but was '{}'"
.format(name),
)
name = name.removesuffix("_rust_proto")
alias_args = {}
if "visibility" in args:
alias_args["visibility"] = args.pop("visibility")
native.alias(
name = name + "_rust_proto",
actual = select({
"//rust:use_upb_kernel": name + "_upb_rust_proto",
"//conditions:default": name + "_cpp_rust_proto",
}),
**alias_args
)
rust_upb_proto_library(
name = name + "_upb_rust_proto",
deps = deps,
visibility = ["//visibility:private"],
**args
)
rust_cc_proto_library(
name = name + "_cpp_rust_proto",
deps = deps,
visibility = ["//visibility:private"],
**args
)
def _user_visible_label(ctx):
label = str(ctx.label)
label = label.removesuffix("_cpp_rust_proto")
label = label.removesuffix("_upb_rust_proto")
return label + "_rust_proto"
def _rust_proto_library_impl(ctx):
if not ctx.label.name.endswith("_rust_proto"):
fail(
"{}: Name of rust_proto_library target should end with `_rust_proto`."
.format(_user_visible_label(ctx)),
)
deps = ctx.attr.deps
if not deps:
fail(
"{}: Exactly 1 dependency in `deps` attribute expected, none were provided."
.format(_user_visible_label(ctx)),
)
if len(deps) > 1:
fail(
"{}: Exactly 1 dependency in `deps` attribute expected, too many were provided."
.format(_user_visible_label(ctx)),
)
dep = deps[0]
rust_proto_info = dep[RustProtoInfo]
proto_common.check_collocated(
ctx.label,
dep[ProtoInfo],
ctx.attr._proto_lang_toolchain[proto_common.ProtoLangToolchainInfo],
)
if len(rust_proto_info.dep_variant_infos) != 1:
fail(
"{}: rust_proto_library does not support src-less proto_library targets."
.format(_user_visible_label(ctx)),
)
dep_variant_info = rust_proto_info.dep_variant_infos[0]
crate_info = dep_variant_info.crate_info
# Change the crate name from the name of the proto_library to the name of the rust_proto_library.
#
# When the aspect visits proto_libraries, it doesn't know and cannot deduce the name of the
# rust_proto_library (although the name of rust_proto_libraries is consistently ending with
# _rust_proto, we can't rely on all proto_libraries to have a name consistently ending with
# _proto), therefore we have to modify it after the fact here.
#
# Since Starlark providers are frozen once they leave the _impl function that defines them,
# we have to create a shallow copy.
toolchain = ctx.toolchains["@rules_rust//rust:toolchain_type"]
fields = {field: getattr(crate_info, field) for field in dir(crate_info)}
pkg, name = _user_visible_label(ctx).rsplit(":")
# Construct a label and compute the crate name.
# Package and workspace root are only relevant when 1P crate renaming is enabled.
# The current implementation of crate renaming supports only monorepos which
# means that it will only rename wen label.workspace_root is empty.
label = struct(**{"name": name, "package": pkg, "workspace_root": ""})
fields["name"] = label_to_crate_name(ctx, label, toolchain)
# These two fields present on the dir(crate_info) but break on some versions of Bazel when
# passed back in to crate_info. Strip them for now.
fields.pop("to_json", None)
fields.pop("to_proto", None)
crate_info_with_rust_proto_name = rust_common.crate_info(**fields)
return [
ProtoCrateNamesInfo(
crate_name = crate_info_with_rust_proto_name.name,
old_crate_name = crate_info.name,
),
crate_info_with_rust_proto_name,
dep_variant_info.dep_info,
dep_variant_info.cc_info,
DefaultInfo(files = dep_variant_info.crate_info.srcs),
]
def _make_rust_proto_library(is_upb):
return rule(
implementation = _rust_proto_library_impl,
attrs = {
"deps": attr.label_list(
mandatory = True,
providers = [ProtoInfo],
aspects = [rust_upb_proto_library_aspect if is_upb else rust_cc_proto_library_aspect],
),
"_proto_lang_toolchain": attr.label(
default = Label(proto_rust_toolchain_label(is_upb)),
),
},
toolchains = [
"@rules_rust//rust:toolchain_type",
],
)
rust_upb_proto_library = _make_rust_proto_library(is_upb = True)
rust_cc_proto_library = _make_rust_proto_library(is_upb = False)
|