| """Rule for running the gRPC C++ code generator. |
| |
| This is a simplified and modernised version of the upstream gRPC |
| `bazel/cc_grpc_library.bzl` file, which as of release v1.45 |
| (published 2022-03-19) does not support separating the `proto_library` and |
| `cc_proto_library` targets into separate packages or repositories. |
| |
| The following logic should eventually find a home in upstream gRPC, rules_proto, |
| or rules_cc so that the Bazel Remote APIs repository can be further decoupled |
| from language-specific concerns. |
| """ |
| |
| load("@com_github_grpc_grpc//bazel:protobuf.bzl", "get_include_protoc_args") |
| |
| _EXT_PROTO = ".proto" |
| _EXT_PROTODEVEL = ".protodevel" |
| _EXT_GRPC_HDR = ".grpc.pb.h" |
| _EXT_GRPC_SRC = ".grpc.pb.cc" |
| |
| def _drop_proto_ext(name): |
| if name.endswith(_EXT_PROTO): |
| return name[:-len(_EXT_PROTO)] |
| if name.endswith(_EXT_PROTODEVEL): |
| return name[:-len(_EXT_PROTODEVEL)] |
| fail("{!r} does not end with {!r} or {!r}".format( |
| name, |
| _EXT_PROTO, |
| _EXT_PROTODEVEL, |
| )) |
| |
| def _proto_srcname(file): |
| """Return the Protobuf source name for a proto_library source file. |
| |
| The source name is what the Protobuf compiler uses to identify a .proto |
| source file. It is relative to the compiler's `--proto_path` flag. |
| """ |
| ws_root = file.owner.workspace_root |
| if ws_root != "" and file.path.startswith(ws_root): |
| return file.path[len(ws_root) + 1:] |
| return file.short_path |
| |
| def _cc_grpc_codegen(ctx): |
| """Run the gRPC C++ code generator to produce sources and headers""" |
| proto = ctx.attr.proto[ProtoInfo] |
| proto_srcs = proto.check_deps_sources.to_list() |
| proto_imports = proto.transitive_imports.to_list() |
| |
| protoc_out = ctx.actions.declare_directory(ctx.attr.name + "_protoc_out") |
| protoc_outputs = [protoc_out] |
| rule_outputs = [] |
| |
| for proto_src in proto_srcs: |
| srcname = _drop_proto_ext(_proto_srcname(proto_src)) |
| basename = _drop_proto_ext(proto_src.basename) |
| |
| out_hdr = ctx.actions.declare_file(basename + _EXT_GRPC_HDR) |
| out_src = ctx.actions.declare_file(basename + _EXT_GRPC_SRC) |
| |
| protoc_out_prefix = protoc_out.basename |
| protoc_out_hdr = ctx.actions.declare_file( |
| "{}/{}".format(protoc_out_prefix, srcname + _EXT_GRPC_HDR), |
| ) |
| protoc_out_src = ctx.actions.declare_file( |
| "{}/{}".format(protoc_out_prefix, srcname + _EXT_GRPC_SRC), |
| ) |
| |
| rule_outputs.extend([out_hdr, out_src]) |
| protoc_outputs.extend([protoc_out_hdr, protoc_out_src]) |
| |
| ctx.actions.expand_template( |
| template = protoc_out_hdr, |
| output = out_hdr, |
| substitutions = {}, |
| ) |
| ctx.actions.expand_template( |
| template = protoc_out_src, |
| output = out_src, |
| substitutions = {}, |
| ) |
| |
| plugin = ctx.executable._protoc_gen_grpc |
| protoc_args = ctx.actions.args() |
| protoc_args.add("--plugin", "protoc-gen-grpc=" + plugin.path) |
| protoc_args.add("--grpc_out", protoc_out.path) |
| |
| protoc_args.add_all(get_include_protoc_args(proto_imports)) |
| protoc_args.add_all(proto_srcs, map_each = _proto_srcname) |
| |
| ctx.actions.run( |
| executable = ctx.executable._protoc, |
| arguments = [protoc_args], |
| inputs = proto_srcs + proto_imports, |
| outputs = protoc_outputs, |
| tools = [plugin], |
| ) |
| |
| return DefaultInfo(files = depset(rule_outputs)) |
| |
| cc_grpc_codegen = rule( |
| implementation = _cc_grpc_codegen, |
| attrs = { |
| "proto": attr.label( |
| mandatory = True, |
| allow_single_file = True, |
| providers = [ProtoInfo], |
| ), |
| "_protoc_gen_grpc": attr.label( |
| default = Label("@com_github_grpc_grpc//src/compiler:grpc_cpp_plugin"), |
| executable = True, |
| cfg = "host", |
| ), |
| "_protoc": attr.label( |
| default = Label("//external:protocol_compiler"), |
| executable = True, |
| cfg = "host", |
| ), |
| }, |
| ) |