"""Generates C++ grpc stubs from proto_library rules. This is an internal rule used by cc_grpc_library, and shouldn't be used directly. """ def generate_cc_impl(ctx): """Implementation of the generate_cc rule.""" protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources] includes = [f for src in ctx.attr.srcs for f in src.proto.transitive_imports] outs = [] # label_len is length of the path from WORKSPACE root to the location of this build file label_len = 0 # proto_root is the directory relative to which generated include paths should be proto_root = "" if ctx.label.package: # The +1 is for the trailing slash. label_len += len(ctx.label.package) + 1 if ctx.label.workspace_root: label_len += len(ctx.label.workspace_root) + 1 proto_root = "/" + ctx.label.workspace_root if ctx.executable.plugin: outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.h" for proto in protos] outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.cc" for proto in protos] if ctx.attr.generate_mocks: outs += [proto.path[label_len:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos] else: outs += [proto.path[label_len:-len(".proto")] + ".pb.h" for proto in protos] outs += [proto.path[label_len:-len(".proto")] + ".pb.cc" for proto in protos] out_files = [ctx.actions.declare_file(out) for out in outs] dir_out = str(ctx.genfiles_dir.path + proto_root) arguments = [] if ctx.executable.plugin: arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path] flags = list(ctx.attr.flags) if ctx.attr.generate_mocks: flags.append("generate_mock_code=true") arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out] tools = [ctx.executable.plugin] else: arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] tools = [] # Import protos relative to their workspace root so that protoc prints the # right include paths. for include in includes: directory = include.path if directory.startswith("external"): external_sep = directory.find("/") repository_sep = directory.find("/", external_sep + 1) arguments += ["--proto_path=" + directory[:repository_sep]] else: arguments += ["--proto_path=."] # Include the output directory so that protoc puts the generated code in the # right directory. arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)] arguments += [proto.path for proto in protos] # create a list of well known proto files if the argument is non-None well_known_proto_files = [] if ctx.attr.well_known_protos: f = ctx.attr.well_known_protos.files.to_list()[0].dirname if f != "external/com_google_protobuf/src/google/protobuf": print("Error: Only @com_google_protobuf//:well_known_protos is supported") else: # f points to "external/com_google_protobuf/src/google/protobuf" # add -I argument to protoc so it knows where to look for the proto files. arguments += ["-I{0}".format(f + "/../..")] well_known_proto_files = [f for f in ctx.attr.well_known_protos.files] ctx.actions.run( inputs = protos + includes + well_known_proto_files, tools = tools, outputs = out_files, executable = ctx.executable._protoc, arguments = arguments, ) return struct(files=depset(out_files)) _generate_cc = rule( attrs = { "srcs": attr.label_list( mandatory = True, allow_empty = False, providers = ["proto"], ), "plugin": attr.label( executable = True, providers = ["files_to_run"], cfg = "host", ), "flags": attr.string_list( mandatory = False, allow_empty = True, ), "well_known_protos" : attr.label( mandatory = False, ), "generate_mocks" : attr.bool( default = False, mandatory = False, ), "_protoc": attr.label( default = Label("//external:protocol_compiler"), executable = True, cfg = "host", ), }, # We generate .h files, so we need to output to genfiles. output_to_genfiles = True, implementation = generate_cc_impl, ) def generate_cc(well_known_protos, **kwargs): if well_known_protos: _generate_cc(well_known_protos="@com_google_protobuf//:well_known_protos", **kwargs) else: _generate_cc(**kwargs)