blob: ae747aa42ca0ab2d97d32ae7c8356e639d55d891 [file] [log] [blame]
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +02001"""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):
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +02008 """Implementation of the generate_cc rule."""
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +02009 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 = []
Makarand Dharmapurikarc872a992017-04-17 16:36:00 -070012 # label_len is length of the path from WORKSPACE root to the location of this build file
Ian Sturdyec27b282018-03-07 11:27:59 -080013 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
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +020023 if ctx.executable.plugin:
Makarand Dharmapurikarc872a992017-04-17 16:36:00 -070024 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]
yang-g502ba742018-03-21 14:46:44 -070026 if ctx.attr.generate_mocks:
Makarand Dharmapurikar28079512017-04-25 09:39:33 -070027 outs += [proto.path[label_len:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos]
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +020028 else:
Makarand Dharmapurikarc872a992017-04-17 16:36:00 -070029 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]
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020031 out_files = [ctx.new_file(out) for out in outs]
Ian Sturdyec27b282018-03-07 11:27:59 -080032 dir_out = str(ctx.genfiles_dir.path + proto_root)
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020033
34 arguments = []
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +020035 if ctx.executable.plugin:
36 arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
Mahak Mukhi459da912017-04-16 20:44:04 -070037 flags = list(ctx.attr.flags)
yang-g502ba742018-03-21 14:46:44 -070038 if ctx.attr.generate_mocks:
Mahak Mukhi459da912017-04-16 20:44:04 -070039 flags.append("generate_mock_code=true")
40 arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out]
Nicolas "Pixel" Noble24263c32017-01-11 01:03:09 +010041 additional_input = [ctx.executable.plugin]
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +020042 else:
43 arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
Nicolas "Pixel" Noble24263c32017-01-11 01:03:09 +010044 additional_input = []
Ian Sturdye6dfa9c2018-03-19 16:12:45 -070045
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.
Ian Sturdyec27b282018-03-07 11:27:59 -080058 arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020059 arguments += [proto.path for proto in protos]
60
Makarand Dharmapurikare3e3b2a2017-03-07 16:12:56 -080061 # 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
Vijay Paif74eaa62017-04-14 17:19:52 -070065 if f != "external/com_google_protobuf/src/google/protobuf":
66 print("Error: Only @com_google_protobuf//:well_known_protos is supported")
Makarand Dharmapurikare3e3b2a2017-03-07 16:12:56 -080067 else:
Vijay Paif74eaa62017-04-14 17:19:52 -070068 # f points to "external/com_google_protobuf/src/google/protobuf"
Makarand Dharmapurikare3e3b2a2017-03-07 16:12:56 -080069 # 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
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020073 ctx.action(
Makarand Dharmapurikare3e3b2a2017-03-07 16:12:56 -080074 inputs = protos + includes + additional_input + well_known_proto_files,
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020075 outputs = out_files,
76 executable = ctx.executable._protoc,
77 arguments = arguments,
78 )
79
Vladimir Moskva759c7022017-09-14 15:40:27 +020080 return struct(files=depset(out_files))
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020081
Craig Tillera7533712017-05-16 13:09:33 -070082_generate_cc = rule(
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020083 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"],
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +020092 cfg = "host",
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020093 ),
94 "flags": attr.string_list(
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +020095 mandatory = False,
96 allow_empty = True,
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +020097 ),
Makarand Dharmapurikare3e3b2a2017-03-07 16:12:56 -080098 "well_known_protos" : attr.label(
99 mandatory = False,
100 ),
yang-g502ba742018-03-21 14:46:44 -0700101 "generate_mocks" : attr.bool(
Mahak Mukhi443a75d2017-04-14 15:33:55 -0700102 default = False,
103 mandatory = False,
104 ),
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +0200105 "_protoc": attr.label(
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +0200106 default = Label("//external:protocol_compiler"),
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +0200107 executable = True,
Nicolas "Pixel" Noble799bd5e2016-10-21 01:54:32 +0200108 cfg = "host",
Nicolas "Pixel" Noble4dc64312016-10-20 23:07:37 +0200109 ),
110 },
111 # We generate .h files, so we need to output to genfiles.
112 output_to_genfiles = True,
113 implementation = generate_cc_impl,
114)
Craig Tillera7533712017-05-16 13:09:33 -0700115
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)