directly.
"""
+load(
+ "//bazel:protobuf.bzl",
+ "get_include_protoc_args",
+ "get_plugin_args",
+ "get_proto_root",
+ "proto_path_to_generated_filename",
+)
+
+_GRPC_PROTO_HEADER_FMT = "{}.grpc.pb.h"
+_GRPC_PROTO_SRC_FMT = "{}.grpc.pb.cc"
+_GRPC_PROTO_MOCK_HEADER_FMT = "{}_mock.grpc.pb.h"
+_PROTO_HEADER_FMT = "{}.pb.h"
+_PROTO_SRC_FMT = "{}.pb.cc"
+
+def _strip_package_from_path(label_package, file):
+ prefix_len = 0
+ if not file.is_source and file.path.startswith(file.root.path):
+ prefix_len = len(file.root.path) + 1
+
+ path = file.path
+ if len(label_package) == 0:
+ return path
+ if not path.startswith(label_package + "/", prefix_len):
+ fail("'{}' does not lie within '{}'.".format(path, label_package))
+ return path[prefix_len + len(label_package + "/"):]
+
+def _get_srcs_file_path(file):
+ if not file.is_source and file.path.startswith(file.root.path):
+ return file.path[len(file.root.path) + 1:]
+ return file.path
+
+def _join_directories(directories):
+ massaged_directories = [directory for directory in directories if len(directory) != 0]
+ return "/".join(massaged_directories)
+
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.new_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]
- additional_input = [ctx.executable.plugin]
- else:
- arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
- additional_input = []
-
- # 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]]
+ """Implementation of the generate_cc rule."""
+ protos = [f for src in ctx.attr.srcs for f in src.proto.check_deps_sources.to_list()]
+ includes = [
+ f
+ for src in ctx.attr.srcs
+ for f in src.proto.transitive_imports.to_list()
+ ]
+ outs = []
+ proto_root = get_proto_root(
+ ctx.label.workspace_root,
+ )
+
+ label_package = _join_directories([ctx.label.workspace_root, ctx.label.package])
+ if ctx.executable.plugin:
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _GRPC_PROTO_HEADER_FMT,
+ )
+ for proto in protos
+ ]
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _GRPC_PROTO_SRC_FMT,
+ )
+ for proto in protos
+ ]
+ if ctx.attr.generate_mocks:
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _GRPC_PROTO_MOCK_HEADER_FMT,
+ )
+ for proto in protos
+ ]
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")
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _PROTO_HEADER_FMT,
+ )
+ for proto in protos
+ ]
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _PROTO_SRC_FMT,
+ )
+ 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 += get_plugin_args(
+ ctx.executable.plugin,
+ ctx.attr.flags,
+ dir_out,
+ ctx.attr.generate_mocks,
+ )
+ tools = [ctx.executable.plugin]
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]
+ arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
+ tools = []
+
+ arguments += get_include_protoc_args(includes)
+
+ # 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 += [_get_srcs_file_path(proto) 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.to_list()
+ ]
- ctx.action(
- inputs = protos + includes + additional_input + well_known_proto_files,
- outputs = out_files,
- executable = ctx.executable._protoc,
- arguments = arguments,
- )
+ 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))
+ return struct(files = depset(out_files))
_generate_cc = rule(
attrs = {
mandatory = False,
allow_empty = True,
),
- "well_known_protos" : attr.label(
- mandatory = False,
- ),
- "generate_mocks" : attr.bool(
+ "well_known_protos": attr.label(mandatory = False),
+ "generate_mocks": attr.bool(
default = False,
mandatory = False,
),
)
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)
+ if well_known_protos:
+ _generate_cc(
+ well_known_protos = "@com_google_protobuf//:well_known_protos",
+ **kwargs
+ )
+ else:
+ _generate_cc(**kwargs)