1 """Generates C++ grpc stubs from proto_library rules.
3 This is an internal rule used by cc_grpc_library, and shouldn't be used
8 "//bazel:protobuf.bzl",
9 "get_include_protoc_args",
12 "proto_path_to_generated_filename",
15 _GRPC_PROTO_HEADER_FMT = "{}.grpc.pb.h"
16 _GRPC_PROTO_SRC_FMT = "{}.grpc.pb.cc"
17 _GRPC_PROTO_MOCK_HEADER_FMT = "{}_mock.grpc.pb.h"
18 _PROTO_HEADER_FMT = "{}.pb.h"
19 _PROTO_SRC_FMT = "{}.pb.cc"
21 def _strip_package_from_path(label_package, file):
23 if not file.is_source and file.path.startswith(file.root.path):
24 prefix_len = len(file.root.path) + 1
27 if len(label_package) == 0:
29 if not path.startswith(label_package + "/", prefix_len):
30 fail("'{}' does not lie within '{}'.".format(path, label_package))
31 return path[prefix_len + len(label_package + "/"):]
33 def _get_srcs_file_path(file):
34 if not file.is_source and file.path.startswith(file.root.path):
35 return file.path[len(file.root.path) + 1:]
38 def _join_directories(directories):
39 massaged_directories = [directory for directory in directories if len(directory) != 0]
40 return "/".join(massaged_directories)
42 def generate_cc_impl(ctx):
43 """Implementation of the generate_cc rule."""
44 protos = [f for src in ctx.attr.srcs for f in src.proto.check_deps_sources]
47 for src in ctx.attr.srcs
48 for f in src.proto.transitive_imports
51 proto_root = get_proto_root(
52 ctx.label.workspace_root,
55 label_package = _join_directories([ctx.label.workspace_root, ctx.label.package])
56 if ctx.executable.plugin:
58 proto_path_to_generated_filename(
59 _strip_package_from_path(label_package, proto),
60 _GRPC_PROTO_HEADER_FMT,
65 proto_path_to_generated_filename(
66 _strip_package_from_path(label_package, proto),
71 if ctx.attr.generate_mocks:
73 proto_path_to_generated_filename(
74 _strip_package_from_path(label_package, proto),
75 _GRPC_PROTO_MOCK_HEADER_FMT,
81 proto_path_to_generated_filename(
82 _strip_package_from_path(label_package, proto),
88 proto_path_to_generated_filename(
89 _strip_package_from_path(label_package, proto),
94 out_files = [ctx.actions.declare_file(out) for out in outs]
95 dir_out = str(ctx.genfiles_dir.path + proto_root)
98 if ctx.executable.plugin:
99 arguments += get_plugin_args(
100 ctx.executable.plugin,
103 ctx.attr.generate_mocks,
105 tools = [ctx.executable.plugin]
107 arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
110 arguments += get_include_protoc_args(includes)
112 # Include the output directory so that protoc puts the generated code in the
114 arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
115 arguments += [_get_srcs_file_path(proto) for proto in protos]
117 # create a list of well known proto files if the argument is non-None
118 well_known_proto_files = []
119 if ctx.attr.well_known_protos:
120 f = ctx.attr.well_known_protos.files.to_list()[0].dirname
121 if f != "external/com_google_protobuf/src/google/protobuf":
123 "Error: Only @com_google_protobuf//:well_known_protos is supported",
126 # f points to "external/com_google_protobuf/src/google/protobuf"
127 # add -I argument to protoc so it knows where to look for the proto files.
128 arguments += ["-I{0}".format(f + "/../..")]
129 well_known_proto_files = [
131 for f in ctx.attr.well_known_protos.files
135 inputs = protos + includes + well_known_proto_files,
138 executable = ctx.executable._protoc,
139 arguments = arguments,
142 return struct(files = depset(out_files))
146 "srcs": attr.label_list(
149 providers = ["proto"],
151 "plugin": attr.label(
153 providers = ["files_to_run"],
156 "flags": attr.string_list(
160 "well_known_protos": attr.label(mandatory = False),
161 "generate_mocks": attr.bool(
165 "_protoc": attr.label(
166 default = Label("//external:protocol_compiler"),
171 # We generate .h files, so we need to output to genfiles.
172 output_to_genfiles = True,
173 implementation = generate_cc_impl,
176 def generate_cc(well_known_protos, **kwargs):
177 if well_known_protos:
179 well_known_protos = "@com_google_protobuf//:well_known_protos",
183 _generate_cc(**kwargs)