• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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