1"""Generates C++ grpc stubs from proto_library rules. 2 3This is an internal rule used by cc_grpc_library, and shouldn't be used 4directly. 5""" 6 7def generate_cc_impl(ctx): 8 """Implementation of the generate_cc rule.""" 9 protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources] 10 includes = [f for src in ctx.attr.srcs for f in src.proto.transitive_imports] 11 outs = [] 12 # label_len is length of the path from WORKSPACE root to the location of this build file 13 label_len = 0 14 # proto_root is the directory relative to which generated include paths should be 15 proto_root = "" 16 if ctx.label.package: 17 # The +1 is for the trailing slash. 18 label_len += len(ctx.label.package) + 1 19 if ctx.label.workspace_root: 20 label_len += len(ctx.label.workspace_root) + 1 21 proto_root = "/" + ctx.label.workspace_root 22 23 if ctx.executable.plugin: 24 outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.h" for proto in protos] 25 outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.cc" for proto in protos] 26 if ctx.attr.generate_mocks: 27 outs += [proto.path[label_len:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos] 28 else: 29 outs += [proto.path[label_len:-len(".proto")] + ".pb.h" for proto in protos] 30 outs += [proto.path[label_len:-len(".proto")] + ".pb.cc" for proto in protos] 31 out_files = [ctx.new_file(out) for out in outs] 32 dir_out = str(ctx.genfiles_dir.path + proto_root) 33 34 arguments = [] 35 if ctx.executable.plugin: 36 arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path] 37 flags = list(ctx.attr.flags) 38 if ctx.attr.generate_mocks: 39 flags.append("generate_mock_code=true") 40 arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out] 41 additional_input = [ctx.executable.plugin] 42 else: 43 arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] 44 additional_input = [] 45 46 # Import protos relative to their workspace root so that protoc prints the 47 # right include paths. 48 for include in includes: 49 directory = include.path 50 if directory.startswith("external"): 51 external_sep = directory.find("/") 52 repository_sep = directory.find("/", external_sep + 1) 53 arguments += ["--proto_path=" + directory[:repository_sep]] 54 else: 55 arguments += ["--proto_path=."] 56 # Include the output directory so that protoc puts the generated code in the 57 # right directory. 58 arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)] 59 arguments += [proto.path for proto in protos] 60 61 # create a list of well known proto files if the argument is non-None 62 well_known_proto_files = [] 63 if ctx.attr.well_known_protos: 64 f = ctx.attr.well_known_protos.files.to_list()[0].dirname 65 if f != "external/com_google_protobuf/src/google/protobuf": 66 print("Error: Only @com_google_protobuf//:well_known_protos is supported") 67 else: 68 # f points to "external/com_google_protobuf/src/google/protobuf" 69 # add -I argument to protoc so it knows where to look for the proto files. 70 arguments += ["-I{0}".format(f + "/../..")] 71 well_known_proto_files = [f for f in ctx.attr.well_known_protos.files] 72 73 ctx.action( 74 inputs = protos + includes + additional_input + well_known_proto_files, 75 outputs = out_files, 76 executable = ctx.executable._protoc, 77 arguments = arguments, 78 ) 79 80 return struct(files=depset(out_files)) 81 82_generate_cc = rule( 83 attrs = { 84 "srcs": attr.label_list( 85 mandatory = True, 86 non_empty = True, 87 providers = ["proto"], 88 ), 89 "plugin": attr.label( 90 executable = True, 91 providers = ["files_to_run"], 92 cfg = "host", 93 ), 94 "flags": attr.string_list( 95 mandatory = False, 96 allow_empty = True, 97 ), 98 "well_known_protos" : attr.label( 99 mandatory = False, 100 ), 101 "generate_mocks" : attr.bool( 102 default = False, 103 mandatory = False, 104 ), 105 "_protoc": attr.label( 106 default = Label("//external:protocol_compiler"), 107 executable = True, 108 cfg = "host", 109 ), 110 }, 111 # We generate .h files, so we need to output to genfiles. 112 output_to_genfiles = True, 113 implementation = generate_cc_impl, 114) 115 116def generate_cc(well_known_protos, **kwargs): 117 if well_known_protos: 118 _generate_cc(well_known_protos="@com_google_protobuf//:well_known_protos", **kwargs) 119 else: 120 _generate_cc(**kwargs) 121