1*ae21b2b4SYike Zhang"""Rule for running the gRPC C++ code generator. 2*ae21b2b4SYike Zhang 3*ae21b2b4SYike ZhangThis is a simplified and modernised version of the upstream gRPC 4*ae21b2b4SYike Zhang`bazel/cc_grpc_library.bzl` file, which as of release v1.45 5*ae21b2b4SYike Zhang(published 2022-03-19) does not support separating the `proto_library` and 6*ae21b2b4SYike Zhang`cc_proto_library` targets into separate packages or repositories. 7*ae21b2b4SYike Zhang 8*ae21b2b4SYike ZhangThe following logic should eventually find a home in upstream gRPC, rules_proto, 9*ae21b2b4SYike Zhangor rules_cc so that the Bazel Remote APIs repository can be further decoupled 10*ae21b2b4SYike Zhangfrom language-specific concerns. 11*ae21b2b4SYike Zhang""" 12*ae21b2b4SYike Zhang 13*ae21b2b4SYike Zhangload("@com_github_grpc_grpc//bazel:protobuf.bzl", "get_include_protoc_args") 14*ae21b2b4SYike Zhang 15*ae21b2b4SYike Zhang_EXT_PROTO = ".proto" 16*ae21b2b4SYike Zhang_EXT_PROTODEVEL = ".protodevel" 17*ae21b2b4SYike Zhang_EXT_GRPC_HDR = ".grpc.pb.h" 18*ae21b2b4SYike Zhang_EXT_GRPC_SRC = ".grpc.pb.cc" 19*ae21b2b4SYike Zhang 20*ae21b2b4SYike Zhangdef _drop_proto_ext(name): 21*ae21b2b4SYike Zhang if name.endswith(_EXT_PROTO): 22*ae21b2b4SYike Zhang return name[:-len(_EXT_PROTO)] 23*ae21b2b4SYike Zhang if name.endswith(_EXT_PROTODEVEL): 24*ae21b2b4SYike Zhang return name[:-len(_EXT_PROTODEVEL)] 25*ae21b2b4SYike Zhang fail("{!r} does not end with {!r} or {!r}".format( 26*ae21b2b4SYike Zhang name, 27*ae21b2b4SYike Zhang _EXT_PROTO, 28*ae21b2b4SYike Zhang _EXT_PROTODEVEL, 29*ae21b2b4SYike Zhang )) 30*ae21b2b4SYike Zhang 31*ae21b2b4SYike Zhangdef _proto_srcname(file): 32*ae21b2b4SYike Zhang """Return the Protobuf source name for a proto_library source file. 33*ae21b2b4SYike Zhang 34*ae21b2b4SYike Zhang The source name is what the Protobuf compiler uses to identify a .proto 35*ae21b2b4SYike Zhang source file. It is relative to the compiler's `--proto_path` flag. 36*ae21b2b4SYike Zhang """ 37*ae21b2b4SYike Zhang ws_root = file.owner.workspace_root 38*ae21b2b4SYike Zhang if ws_root != "" and file.path.startswith(ws_root): 39*ae21b2b4SYike Zhang return file.path[len(ws_root) + 1:] 40*ae21b2b4SYike Zhang return file.short_path 41*ae21b2b4SYike Zhang 42*ae21b2b4SYike Zhangdef _cc_grpc_codegen(ctx): 43*ae21b2b4SYike Zhang """Run the gRPC C++ code generator to produce sources and headers""" 44*ae21b2b4SYike Zhang proto = ctx.attr.proto[ProtoInfo] 45*ae21b2b4SYike Zhang proto_srcs = proto.check_deps_sources.to_list() 46*ae21b2b4SYike Zhang proto_imports = proto.transitive_imports.to_list() 47*ae21b2b4SYike Zhang 48*ae21b2b4SYike Zhang protoc_out = ctx.actions.declare_directory(ctx.attr.name + "_protoc_out") 49*ae21b2b4SYike Zhang protoc_outputs = [protoc_out] 50*ae21b2b4SYike Zhang rule_outputs = [] 51*ae21b2b4SYike Zhang 52*ae21b2b4SYike Zhang for proto_src in proto_srcs: 53*ae21b2b4SYike Zhang srcname = _drop_proto_ext(_proto_srcname(proto_src)) 54*ae21b2b4SYike Zhang basename = _drop_proto_ext(proto_src.basename) 55*ae21b2b4SYike Zhang 56*ae21b2b4SYike Zhang out_hdr = ctx.actions.declare_file(basename + _EXT_GRPC_HDR) 57*ae21b2b4SYike Zhang out_src = ctx.actions.declare_file(basename + _EXT_GRPC_SRC) 58*ae21b2b4SYike Zhang 59*ae21b2b4SYike Zhang protoc_out_prefix = protoc_out.basename 60*ae21b2b4SYike Zhang protoc_out_hdr = ctx.actions.declare_file( 61*ae21b2b4SYike Zhang "{}/{}".format(protoc_out_prefix, srcname + _EXT_GRPC_HDR), 62*ae21b2b4SYike Zhang ) 63*ae21b2b4SYike Zhang protoc_out_src = ctx.actions.declare_file( 64*ae21b2b4SYike Zhang "{}/{}".format(protoc_out_prefix, srcname + _EXT_GRPC_SRC), 65*ae21b2b4SYike Zhang ) 66*ae21b2b4SYike Zhang 67*ae21b2b4SYike Zhang rule_outputs.extend([out_hdr, out_src]) 68*ae21b2b4SYike Zhang protoc_outputs.extend([protoc_out_hdr, protoc_out_src]) 69*ae21b2b4SYike Zhang 70*ae21b2b4SYike Zhang ctx.actions.expand_template( 71*ae21b2b4SYike Zhang template = protoc_out_hdr, 72*ae21b2b4SYike Zhang output = out_hdr, 73*ae21b2b4SYike Zhang substitutions = {}, 74*ae21b2b4SYike Zhang ) 75*ae21b2b4SYike Zhang ctx.actions.expand_template( 76*ae21b2b4SYike Zhang template = protoc_out_src, 77*ae21b2b4SYike Zhang output = out_src, 78*ae21b2b4SYike Zhang substitutions = {}, 79*ae21b2b4SYike Zhang ) 80*ae21b2b4SYike Zhang 81*ae21b2b4SYike Zhang plugin = ctx.executable._protoc_gen_grpc 82*ae21b2b4SYike Zhang protoc_args = ctx.actions.args() 83*ae21b2b4SYike Zhang protoc_args.add("--plugin", "protoc-gen-grpc=" + plugin.path) 84*ae21b2b4SYike Zhang protoc_args.add("--grpc_out", protoc_out.path) 85*ae21b2b4SYike Zhang 86*ae21b2b4SYike Zhang protoc_args.add_all(get_include_protoc_args(proto_imports)) 87*ae21b2b4SYike Zhang protoc_args.add_all(proto_srcs, map_each = _proto_srcname) 88*ae21b2b4SYike Zhang 89*ae21b2b4SYike Zhang ctx.actions.run( 90*ae21b2b4SYike Zhang executable = ctx.executable._protoc, 91*ae21b2b4SYike Zhang arguments = [protoc_args], 92*ae21b2b4SYike Zhang inputs = proto_srcs + proto_imports, 93*ae21b2b4SYike Zhang outputs = protoc_outputs, 94*ae21b2b4SYike Zhang tools = [plugin], 95*ae21b2b4SYike Zhang ) 96*ae21b2b4SYike Zhang 97*ae21b2b4SYike Zhang return DefaultInfo(files = depset(rule_outputs)) 98*ae21b2b4SYike Zhang 99*ae21b2b4SYike Zhangcc_grpc_codegen = rule( 100*ae21b2b4SYike Zhang implementation = _cc_grpc_codegen, 101*ae21b2b4SYike Zhang attrs = { 102*ae21b2b4SYike Zhang "proto": attr.label( 103*ae21b2b4SYike Zhang mandatory = True, 104*ae21b2b4SYike Zhang allow_single_file = True, 105*ae21b2b4SYike Zhang providers = [ProtoInfo], 106*ae21b2b4SYike Zhang ), 107*ae21b2b4SYike Zhang "_protoc_gen_grpc": attr.label( 108*ae21b2b4SYike Zhang default = Label("@com_github_grpc_grpc//src/compiler:grpc_cpp_plugin"), 109*ae21b2b4SYike Zhang executable = True, 110*ae21b2b4SYike Zhang cfg = "host", 111*ae21b2b4SYike Zhang ), 112*ae21b2b4SYike Zhang "_protoc": attr.label( 113*ae21b2b4SYike Zhang default = Label("//external:protocol_compiler"), 114*ae21b2b4SYike Zhang executable = True, 115*ae21b2b4SYike Zhang cfg = "host", 116*ae21b2b4SYike Zhang ), 117*ae21b2b4SYike Zhang }, 118*ae21b2b4SYike Zhang) 119