diff options
Diffstat (limited to 'internal/cc_grpc_library.bzl')
-rw-r--r-- | internal/cc_grpc_library.bzl | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/internal/cc_grpc_library.bzl b/internal/cc_grpc_library.bzl new file mode 100644 index 0000000..a6e8ab0 --- /dev/null +++ b/internal/cc_grpc_library.bzl @@ -0,0 +1,118 @@ +"""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", + ), + }, +) |