blob: 7c4a13fc32d428a545067930ad6e80bb1c61ac8d [file] [log] [blame]
Roger Chen7492b562018-10-29 21:58:47 -07001load("@bazel_skylib//lib:versions.bzl", "versions")
Mike Kruskal2c71df42022-10-10 11:14:32 -07002load("@rules_cc//cc:defs.bzl", "objc_library")
Yannic Bonenberger723a85f2020-02-15 13:26:56 +01003load("@rules_proto//proto:defs.bzl", "ProtoInfo")
Mike Kruskal2c71df42022-10-10 11:14:32 -07004load("@rules_python//python:defs.bzl", "py_library")
Jingwen Chenb2a19082018-01-12 18:42:22 -05005
Damien Martin-Guillerez76547e52016-01-15 14:01:37 +01006def _GetPath(ctx, path):
Paul Yangcecba292018-12-14 16:05:03 -08007 if ctx.label.workspace_root:
8 return ctx.label.workspace_root + "/" + path
9 else:
10 return path
Damien Martin-Guillerez76547e52016-01-15 14:01:37 +010011
Kristina Chodorow4e7ecde2017-01-25 14:10:56 -050012def _IsNewExternal(ctx):
Paul Yangcecba292018-12-14 16:05:03 -080013 # Bazel 0.4.4 and older have genfiles paths that look like:
14 # bazel-out/local-fastbuild/genfiles/external/repo/foo
15 # After the exec root rearrangement, they look like:
16 # ../repo/bazel-out/local-fastbuild/genfiles/foo
17 return ctx.label.workspace_root.startswith("../")
Kristina Chodorow4e7ecde2017-01-25 14:10:56 -050018
Jisi Liu993fb702015-10-19 17:19:49 -070019def _GenDir(ctx):
Paul Yangcecba292018-12-14 16:05:03 -080020 if _IsNewExternal(ctx):
21 # We are using the fact that Bazel 0.4.4+ provides repository-relative paths
22 # for ctx.genfiles_dir.
23 return ctx.genfiles_dir.path + (
24 "/" + ctx.attr.includes[0] if ctx.attr.includes and ctx.attr.includes[0] else ""
Fahrzin Hemmatid1403e52018-03-16 13:23:34 -070025 )
Jisi Liu39362b32015-10-14 17:12:11 -070026
Paul Yangcecba292018-12-14 16:05:03 -080027 # This means that we're either in the old version OR the new version in the local repo.
28 # Either way, appending the source path to the genfiles dir works.
29 return ctx.var["GENDIR"] + "/" + _SourceDir(ctx)
30
31def _SourceDir(ctx):
32 if not ctx.attr.includes:
33 return ctx.label.workspace_root
34 if not ctx.attr.includes[0]:
35 return _GetPath(ctx, ctx.label.package)
36 if not ctx.label.package:
37 return _GetPath(ctx, ctx.attr.includes[0])
38 return _GetPath(ctx, ctx.label.package + "/" + ctx.attr.includes[0])
39
Mike Kruskaled5c57a2022-08-10 22:51:29 -070040def _ObjcBase(srcs):
41 return [
42 "".join([token.capitalize() for token in src[:-len(".proto")].split("_")])
43 for src in srcs]
Paul Yangcecba292018-12-14 16:05:03 -080044
Mike Kruskaled5c57a2022-08-10 22:51:29 -070045def _ObjcHdrs(srcs):
46 return[src + ".pbobjc.h" for src in _ObjcBase(srcs)]
Paul Yangcecba292018-12-14 16:05:03 -080047
Mike Kruskaled5c57a2022-08-10 22:51:29 -070048def _ObjcSrcs(srcs):
49 return[src + ".pbobjc.m" for src in _ObjcBase(srcs)]
50
51def _ObjcOuts(srcs, out_type):
52 if out_type == "hdrs":
53 return _ObjcHdrs(srcs)
54 if out_type == "srcs":
55 return _ObjcSrcs(srcs)
56 return _ObjcHdrs(srcs) + _ObjcSrcs(srcs)
Paul Yangcecba292018-12-14 16:05:03 -080057
58def _PyOuts(srcs, use_grpc_plugin = False):
59 ret = [s[:-len(".proto")] + "_pb2.py" for s in srcs]
60 if use_grpc_plugin:
61 ret += [s[:-len(".proto")] + "_pb2_grpc.py" for s in srcs]
62 return ret
63
Mike Kruskaled5c57a2022-08-10 22:51:29 -070064def _RubyOuts(srcs):
65 return [s[:-len(".proto")] + "_pb.rb" for s in srcs]
66
67def _CsharpOuts(srcs):
68 return [
69 "".join([token.capitalize() for token in src[:-len(".proto")].split("_")]) + ".cs"
70 for src in srcs]
71
David L. Jonesd60c0d22022-05-11 19:13:56 -070072ProtoGenInfo = provider(
73 fields = ["srcs", "import_flags", "deps"],
74)
75
Paul Yangcecba292018-12-14 16:05:03 -080076def _proto_gen_impl(ctx):
77 """General implementation for generating protos"""
78 srcs = ctx.files.srcs
Mike Kruskaled5c57a2022-08-10 22:51:29 -070079 langs = ctx.attr.langs or []
80 out_type = ctx.attr.out_type
David L. Jonesd60c0d22022-05-11 19:13:56 -070081 deps = depset(direct = ctx.files.srcs)
Paul Yangcecba292018-12-14 16:05:03 -080082 source_dir = _SourceDir(ctx)
83 gen_dir = _GenDir(ctx).rstrip("/")
Derek Perezb55c8e42022-04-06 11:35:10 -070084 import_flags = []
David L. Jonesd60c0d22022-05-11 19:13:56 -070085
Paul Yangcecba292018-12-14 16:05:03 -080086 if source_dir:
Ivo List15add1a2022-01-29 01:44:42 +010087 has_sources = any([src.is_source for src in srcs])
Ivo List15add1a2022-01-29 01:44:42 +010088 if has_sources:
89 import_flags += ["-I" + source_dir]
Paul Yangcecba292018-12-14 16:05:03 -080090 else:
Derek Perezb55c8e42022-04-06 11:35:10 -070091 import_flags += ["-I."]
92
93 has_generated = any([not src.is_source for src in srcs])
94 if has_generated:
95 import_flags += ["-I" + gen_dir]
96
Mike Kruskaled5c57a2022-08-10 22:51:29 -070097 if ctx.attr.includes:
98 for include in ctx.attr.includes:
99 import_flags += ["-I"+_GetPath(ctx,include)]
100
David L. Jonesd60c0d22022-05-11 19:13:56 -0700101 import_flags = depset(direct = import_flags)
Paul Yangcecba292018-12-14 16:05:03 -0800102
103 for dep in ctx.attr.deps:
David L. Jonesd60c0d22022-05-11 19:13:56 -0700104 dep_proto = dep[ProtoGenInfo]
105 if type(dep_proto.import_flags) == "list":
106 import_flags = depset(
107 transitive = [import_flags],
108 direct = dep_proto.import_flags,
109 )
Harvey Tuche492e5a2020-05-26 14:27:56 -0400110 else:
David L. Jonesd60c0d22022-05-11 19:13:56 -0700111 import_flags = depset(
112 transitive = [import_flags, dep_proto.import_flags],
113 )
114 if type(dep_proto.deps) == "list":
115 deps = depset(transitive = [deps], direct = dep_proto.deps)
Harvey Tuche492e5a2020-05-26 14:27:56 -0400116 else:
David L. Jonesd60c0d22022-05-11 19:13:56 -0700117 deps = depset(transitive = [deps, dep_proto.deps])
Paul Yangcecba292018-12-14 16:05:03 -0800118
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700119 if not langs and not ctx.executable.plugin:
David L. Jonesd60c0d22022-05-11 19:13:56 -0700120 return [
121 ProtoGenInfo(
Paul Yangcecba292018-12-14 16:05:03 -0800122 srcs = srcs,
123 import_flags = import_flags,
124 deps = deps,
125 ),
David L. Jonesd60c0d22022-05-11 19:13:56 -0700126 ]
Paul Yangcecba292018-12-14 16:05:03 -0800127
David L. Jonesd60c0d22022-05-11 19:13:56 -0700128 generated_files = []
Paul Yangcecba292018-12-14 16:05:03 -0800129 for src in srcs:
130 args = []
131
132 in_gen_dir = src.root.path == gen_dir
133 if in_gen_dir:
134 import_flags_real = []
Harvey Tuch7cf3f7a2020-01-24 13:47:15 -0500135 for f in import_flags.to_list():
Paul Yangcecba292018-12-14 16:05:03 -0800136 path = f.replace("-I", "")
137 import_flags_real.append("-I$(realpath -s %s)" % path)
138
Paul Yangcecba292018-12-14 16:05:03 -0800139 use_grpc_plugin = (ctx.attr.plugin_language == "grpc" and ctx.attr.plugin)
140 path_tpl = "$(realpath %s)" if in_gen_dir else "%s"
Paul Yangcecba292018-12-14 16:05:03 -0800141
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700142 outs = []
143 for lang in langs:
144 if lang == "csharp":
145 outs.extend(_CsharpOuts([src.basename]))
146 elif lang == "objc":
147 outs.extend(_ObjcOuts([src.basename], out_type = out_type))
148 elif lang == "python":
149 outs.extend(_PyOuts([src.basename], use_grpc_plugin = use_grpc_plugin))
150 elif lang == "ruby":
151 outs.extend(_RubyOuts([src.basename]))
152 # Otherwise, rely on user-supplied outs.
153 args += [("--%s_out=" + path_tpl) % (lang, gen_dir)]
154
155 if ctx.attr.outs:
156 outs.extend(ctx.attr.outs)
Paul Yangcecba292018-12-14 16:05:03 -0800157 outs = [ctx.actions.declare_file(out, sibling = src) for out in outs]
David L. Jonesd60c0d22022-05-11 19:13:56 -0700158 generated_files.extend(outs)
159
Harvey Tuch7cf3f7a2020-01-24 13:47:15 -0500160 inputs = [src] + deps.to_list()
Benjamin Peterson6153f802019-06-03 08:56:33 -0700161 tools = [ctx.executable.protoc]
Paul Yangcecba292018-12-14 16:05:03 -0800162 if ctx.executable.plugin:
163 plugin = ctx.executable.plugin
164 lang = ctx.attr.plugin_language
165 if not lang and plugin.basename.startswith("protoc-gen-"):
166 lang = plugin.basename[len("protoc-gen-"):]
167 if not lang:
168 fail("cannot infer the target language of plugin", "plugin_language")
169
170 outdir = "." if in_gen_dir else gen_dir
171
172 if ctx.attr.plugin_options:
173 outdir = ",".join(ctx.attr.plugin_options) + ":" + outdir
174 args += [("--plugin=protoc-gen-%s=" + path_tpl) % (lang, plugin.path)]
175 args += ["--%s_out=%s" % (lang, outdir)]
Benjamin Peterson6153f802019-06-03 08:56:33 -0700176 tools.append(plugin)
Paul Yangcecba292018-12-14 16:05:03 -0800177
178 if not in_gen_dir:
179 ctx.actions.run(
180 inputs = inputs,
Benjamin Peterson6153f802019-06-03 08:56:33 -0700181 tools = tools,
Paul Yangcecba292018-12-14 16:05:03 -0800182 outputs = outs,
Harvey Tuch7cf3f7a2020-01-24 13:47:15 -0500183 arguments = args + import_flags.to_list() + [src.path],
Paul Yangcecba292018-12-14 16:05:03 -0800184 executable = ctx.executable.protoc,
185 mnemonic = "ProtoCompile",
186 use_default_shell_env = True,
187 )
188 else:
189 for out in outs:
190 orig_command = " ".join(
191 ["$(realpath %s)" % ctx.executable.protoc.path] + args +
Derek Perezb55c8e42022-04-06 11:35:10 -0700192 import_flags_real + [src.basename],
Paul Yangcecba292018-12-14 16:05:03 -0800193 )
194 command = ";".join([
195 'CMD="%s"' % orig_command,
196 "cd %s" % src.dirname,
197 "${CMD}",
198 "cd -",
199 ])
200 generated_out = "/".join([gen_dir, out.basename])
201 if generated_out != out.path:
202 command += ";mv %s %s" % (generated_out, out.path)
203 ctx.actions.run_shell(
Keith Smileyca3ead72019-05-21 17:31:34 -0700204 inputs = inputs,
Paul Yangcecba292018-12-14 16:05:03 -0800205 outputs = [out],
206 command = command,
207 mnemonic = "ProtoCompile",
Benjamin Peterson6153f802019-06-03 08:56:33 -0700208 tools = tools,
Paul Yangcecba292018-12-14 16:05:03 -0800209 use_default_shell_env = True,
210 )
211
David L. Jonesd60c0d22022-05-11 19:13:56 -0700212 return [
213 ProtoGenInfo(
Paul Yangcecba292018-12-14 16:05:03 -0800214 srcs = srcs,
215 import_flags = import_flags,
216 deps = deps,
217 ),
David L. Jonesd60c0d22022-05-11 19:13:56 -0700218 DefaultInfo(files = depset(generated_files)),
219 ]
Jisi Liu39362b32015-10-14 17:12:11 -0700220
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700221"""Generates codes from Protocol Buffers definitions.
222
223This rule helps you to implement Skylark macros specific to the target
224language. You should prefer more specific `cc_proto_library `,
225`py_proto_library` and others unless you are adding such wrapper macros.
226
227Args:
228 srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
229 against.
230 deps: a list of dependency labels; must be other proto libraries.
231 includes: a list of include paths to .proto files.
232 protoc: the label of the protocol compiler to generate the sources.
233 plugin: the label of the protocol compiler plugin to be passed to the protocol
234 compiler.
235 plugin_language: the language of the generated sources
236 plugin_options: a list of options to be passed to the plugin
237 langs: generates sources in addition to the ones from the plugin for each
238 specified language.
239 outs: a list of labels of the expected outputs from the protocol compiler.
240 out_type: only generated a single type of source file for languages that have
241 split sources (e.g. *.h and *.cc in C++)
242"""
243_proto_gen = rule(
Jisi Liu39362b32015-10-14 17:12:11 -0700244 attrs = {
Jisi Liuee8131a2015-10-14 17:20:05 -0700245 "srcs": attr.label_list(allow_files = True),
David L. Jonesd60c0d22022-05-11 19:13:56 -0700246 "deps": attr.label_list(providers = [ProtoGenInfo]),
Jisi Liu53a56be2015-10-20 15:18:20 -0700247 "includes": attr.string_list(),
Jisi Liuee8131a2015-10-14 17:20:05 -0700248 "protoc": attr.label(
Charles Mitaf1fe79d2021-05-19 20:11:13 +0200249 cfg = "exec",
Jisi Liuee8131a2015-10-14 17:20:05 -0700250 executable = True,
James Juddd5f0dac2018-08-14 21:55:35 -0600251 allow_single_file = True,
Jisi Liuee8131a2015-10-14 17:20:05 -0700252 mandatory = True,
253 ),
Yuki Yugui Sonoda5977fb02016-06-01 16:23:15 +0900254 "plugin": attr.label(
Charles Mitaf1fe79d2021-05-19 20:11:13 +0200255 cfg = "exec",
Yuki Yugui Sonoda5977fb02016-06-01 16:23:15 +0900256 allow_files = True,
Manjunath Kudlurf0966a72016-02-22 14:30:43 -0800257 executable = True,
Manjunath Kudlurf0966a72016-02-22 14:30:43 -0800258 ),
Yuki Yugui Sonoda5977fb02016-06-01 16:23:15 +0900259 "plugin_language": attr.string(),
260 "plugin_options": attr.string_list(),
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700261 "langs": attr.string_list(),
262 "outs": attr.string_list(),
263 "out_type": attr.string(
264 default = "all"
265 ),
Jisi Liuee8131a2015-10-14 17:20:05 -0700266 },
267 output_to_genfiles = True,
Jisi Liu9c7d9c02015-10-15 10:51:32 -0700268 implementation = _proto_gen_impl,
Jisi Liu39362b32015-10-14 17:12:11 -0700269)
Jisi Liu993fb702015-10-19 17:19:49 -0700270
Yannicf0cb9cd2020-02-13 22:04:14 +0100271def _internal_gen_well_known_protos_java_impl(ctx):
272 args = ctx.actions.args()
Steven Parkesea188662016-02-25 07:53:19 -0800273
Yannicf0cb9cd2020-02-13 22:04:14 +0100274 deps = [d[ProtoInfo] for d in ctx.attr.deps]
275
276 srcjar = ctx.actions.declare_file("{}.srcjar".format(ctx.attr.name))
Derek Perezbc45f922021-04-20 11:36:32 -0700277 if ctx.attr.javalite:
278 java_out = "lite:%s" % srcjar.path
279 else:
280 java_out = srcjar
281
282 args.add("--java_out", java_out)
Yannicf0cb9cd2020-02-13 22:04:14 +0100283
284 descriptors = depset(
285 transitive = [dep.transitive_descriptor_sets for dep in deps],
Paul Yangcecba292018-12-14 16:05:03 -0800286 )
Yannicf0cb9cd2020-02-13 22:04:14 +0100287 args.add_joined(
288 "--descriptor_set_in",
289 descriptors,
290 join_with = ctx.configuration.host_path_separator,
291 )
292
293 for dep in deps:
294 if "." == dep.proto_source_root:
295 args.add_all([src.path for src in dep.direct_sources])
296 else:
297 source_root = dep.proto_source_root
298 offset = len(source_root) + 1 # + '/'.
299 args.add_all([src.path[offset:] for src in dep.direct_sources])
300
301 ctx.actions.run(
302 executable = ctx.executable._protoc,
303 inputs = descriptors,
304 outputs = [srcjar],
305 arguments = [args],
Adam Yi88f3ef72020-07-29 16:49:52 +1000306 use_default_shell_env = True,
Yannicf0cb9cd2020-02-13 22:04:14 +0100307 )
308
309 return [
310 DefaultInfo(
311 files = depset([srcjar]),
312 ),
313 ]
314
315internal_gen_well_known_protos_java = rule(
316 implementation = _internal_gen_well_known_protos_java_impl,
317 attrs = {
318 "deps": attr.label_list(
319 mandatory = True,
320 providers = [ProtoInfo],
321 ),
Derek Perezbc45f922021-04-20 11:36:32 -0700322 "javalite": attr.bool(
323 default = False,
324 ),
Yannicf0cb9cd2020-02-13 22:04:14 +0100325 "_protoc": attr.label(
326 executable = True,
Charles Mitaf1fe79d2021-05-19 20:11:13 +0200327 cfg = "exec",
Adam Cozzettefaa42e92022-03-29 15:50:39 -0400328 default = "@com_google_protobuf//:protoc",
Yannicf0cb9cd2020-02-13 22:04:14 +0100329 ),
330 },
331)
Steven Parkesea188662016-02-25 07:53:19 -0800332
Deanna Garcia67b74dd2022-02-15 22:45:56 +0000333def _internal_gen_kt_protos(ctx):
334 args = ctx.actions.args()
335
336 deps = [d[ProtoInfo] for d in ctx.attr.deps]
337
338 srcjar = ctx.actions.declare_file("{}.srcjar".format(ctx.attr.name))
339 if ctx.attr.lite:
340 out = "lite:%s" % srcjar.path
341 else:
342 out = srcjar
343
344 args.add("--kotlin_out", out)
345
346 descriptors = depset(
347 transitive = [dep.transitive_descriptor_sets for dep in deps],
348 )
349 args.add_joined(
350 "--descriptor_set_in",
351 descriptors,
352 join_with = ctx.configuration.host_path_separator,
353 )
354
355 for dep in deps:
356 if "." == dep.proto_source_root:
357 args.add_all([src.path for src in dep.direct_sources])
358 else:
359 source_root = dep.proto_source_root
360 offset = len(source_root) + 1 # + '/'.
361 args.add_all([src.path[offset:] for src in dep.direct_sources])
362
363 ctx.actions.run(
364 executable = ctx.executable._protoc,
365 inputs = descriptors,
366 outputs = [srcjar],
367 arguments = [args],
368 use_default_shell_env = True,
369 )
370
371 return [
372 DefaultInfo(
373 files = depset([srcjar]),
374 ),
375 ]
376
377internal_gen_kt_protos = rule(
378 implementation = _internal_gen_kt_protos,
379 attrs = {
380 "deps": attr.label_list(
381 mandatory = True,
382 providers = [ProtoInfo],
383 ),
384 "lite": attr.bool(
385 default = False,
386 ),
387 "_protoc": attr.label(
388 executable = True,
389 cfg = "exec",
390 default = "//:protoc",
391 ),
392 },
393)
394
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700395def internal_objc_proto_library(
396 name,
397 srcs = [],
398 deps = [],
399 outs = [],
400 proto_deps = [],
401 includes = ["."],
402 default_runtime = "@com_google_protobuf//:protobuf_objc",
403 protoc = "@com_google_protobuf//:protoc",
404 testonly = None,
405 visibility = ["//visibility:public"],
406 **kwargs):
Mike Kruskal701dd832022-08-20 14:22:08 -0700407 """Bazel rule to create a Objective-C protobuf library from proto source
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700408 files
409
410 NOTE: the rule is only an internal workaround to generate protos. The
411 interface may change and the rule may be removed when bazel has introduced
412 the native rule.
413
414 Args:
415 name: the name of the objc_proto_library.
416 srcs: the .proto files to compile.
417 deps: a list of dependency labels; must be objc_proto_library.
418 outs: a list of expected output files.
419 proto_deps: a list of proto file dependencies that don't have a
420 objc_proto_library rule.
421 include: a string indicating the include path of the .proto files.
422 default_runtime: the Objective-C Protobuf runtime
423 protoc: the label of the protocol compiler to generate the sources.
424 testonly: common rule attribute (see:
425 https://bazel.build/reference/be/common-definitions#common-attributes)
426 visibility: the visibility of the generated files.
427 **kwargs: other keyword arguments that are passed to py_library.
428
429 """
430 full_deps = [d + "_genproto" for d in deps]
431
432 if proto_deps:
433 _proto_gen(
434 name = name + "_deps_genproto",
435 testonly = testonly,
436 srcs = proto_deps,
437 protoc = protoc,
438 includes = includes,
439 )
440 full_deps.append(":%s_deps_genproto" % name)
441
442 # Note: we need to run the protoc build twice to get separate targets for
443 # the generated header and the source files.
444 _proto_gen(
445 name = name + "_genproto_hdrs",
446 srcs = srcs,
447 deps = full_deps,
448 langs = ["objc"],
449 out_type = "hdrs",
450 includes = includes,
451 protoc = protoc,
452 testonly = testonly,
453 visibility = visibility,
454 tags = ["manual"],
455 )
456
457 _proto_gen(
458 name = name + "_genproto",
459 srcs = srcs,
460 deps = full_deps,
461 langs = ["objc"],
462 out_type = "srcs",
463 includes = includes,
464 protoc = protoc,
465 testonly = testonly,
466 visibility = visibility,
467 tags = ["manual"],
468 )
469
470 objc_library(
471 name = name,
472 hdrs = [name + "_genproto_hdrs"],
473 non_arc_srcs = [name + "_genproto"],
474 deps = [default_runtime],
475 includes = includes,
476 testonly = testonly,
477 visibility = visibility,
478 # Don't auto-expand these targets until target_compatible_with
479 # works. See https://github.com/bazelbuild/bazel/issues/12897.
480 tags = ["manual"],
481 target_compatible_with = ["@platforms//os:osx"],
482 **kwargs
483 )
484
485def internal_py_proto_library(
Jisi Liu993fb702015-10-19 17:19:49 -0700486 name,
Paul Yangcecba292018-12-14 16:05:03 -0800487 srcs = [],
488 deps = [],
489 py_libs = [],
490 py_extra_srcs = [],
491 include = None,
Adam Cozzettefaa42e92022-03-29 15:50:39 -0400492 default_runtime = "@com_google_protobuf//:protobuf_python",
493 protoc = "@com_google_protobuf//:protoc",
Paul Yangcecba292018-12-14 16:05:03 -0800494 use_grpc_plugin = False,
David L. Jones07303d62022-05-17 18:13:22 -0700495 testonly = None,
Jisi Liu993fb702015-10-19 17:19:49 -0700496 **kargs):
Paul Yangcecba292018-12-14 16:05:03 -0800497 """Bazel rule to create a Python protobuf library from proto source files
Jisi Liu7b948cc2015-10-19 17:56:27 -0700498
Paul Yangcecba292018-12-14 16:05:03 -0800499 NOTE: the rule is only an internal workaround to generate protos. The
500 interface may change and the rule may be removed when bazel has introduced
501 the native rule.
Jisi Liud4bef7d2015-11-02 12:24:32 -0800502
Paul Yangcecba292018-12-14 16:05:03 -0800503 Args:
504 name: the name of the py_proto_library.
505 srcs: the .proto files of the py_proto_library.
506 deps: a list of dependency labels; must be py_proto_library.
507 py_libs: a list of other py_library targets depended by the generated
508 py_library.
509 py_extra_srcs: extra source files that will be added to the output
510 py_library. This attribute is used for internal bootstrapping.
511 include: a string indicating the include path of the .proto files.
512 default_runtime: the implicitly default runtime which will be depended on by
513 the generated py_library target.
514 protoc: the label of the protocol compiler to generate the sources.
515 use_grpc_plugin: a flag to indicate whether to call the Python C++ plugin
516 when processing the proto files.
David L. Jones07303d62022-05-17 18:13:22 -0700517 testonly: common rule attribute (see:
518 https://bazel.build/reference/be/common-definitions#common-attributes)
Leo12236c62020-05-04 11:23:44 +0900519 **kargs: other keyword arguments that are passed to py_library.
Jisi Liu7b948cc2015-10-19 17:56:27 -0700520
Paul Yangcecba292018-12-14 16:05:03 -0800521 """
Paul Yangcecba292018-12-14 16:05:03 -0800522 includes = []
523 if include != None:
524 includes = [include]
Jisi Liu53a56be2015-10-20 15:18:20 -0700525
Paul Yangcecba292018-12-14 16:05:03 -0800526 grpc_python_plugin = None
527 if use_grpc_plugin:
528 grpc_python_plugin = "//external:grpc_python_plugin"
529 # Note: Generated grpc code depends on Python grpc module. This dependency
530 # is not explicitly listed in py_libs. Instead, host system is assumed to
531 # have grpc installed.
Wiktor Tomczak0fa31b22016-11-22 20:18:46 +0100532
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700533 _proto_gen(
Paul Yangcecba292018-12-14 16:05:03 -0800534 name = name + "_genproto",
David L. Jones07303d62022-05-17 18:13:22 -0700535 testonly = testonly,
Paul Yangcecba292018-12-14 16:05:03 -0800536 srcs = srcs,
537 deps = [s + "_genproto" for s in deps],
538 includes = includes,
539 protoc = protoc,
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700540 langs = ["python"],
Paul Yangcecba292018-12-14 16:05:03 -0800541 visibility = ["//visibility:public"],
542 plugin = grpc_python_plugin,
543 plugin_language = "grpc",
544 )
Jisi Liu993fb702015-10-19 17:19:49 -0700545
Paul Yangcecba292018-12-14 16:05:03 -0800546 if default_runtime and not default_runtime in py_libs + deps:
547 py_libs = py_libs + [default_runtime]
Yannic Bonenbergerd2d6ff52019-08-06 21:12:06 +0200548 py_library(
Paul Yangcecba292018-12-14 16:05:03 -0800549 name = name,
David L. Jones07303d62022-05-17 18:13:22 -0700550 testonly = testonly,
David L. Jonesd60c0d22022-05-11 19:13:56 -0700551 srcs = [name + "_genproto"] + py_extra_srcs,
Paul Yangcecba292018-12-14 16:05:03 -0800552 deps = py_libs + deps,
553 imports = includes,
554 **kargs
555 )
Jisi Liu993fb702015-10-19 17:19:49 -0700556
Mike Kruskald20e9a92022-09-07 11:20:17 -0700557def py_proto_library(
558 *args,
559 **kwargs):
560 """Deprecated alias for use before Bazel 5.3.
561
562 Args:
563 *args: the name of the py_proto_library.
564 **kwargs: other keyword arguments that are passed to py_library.
565
566 Deprecated:
567 This is provided for backwards compatibility only. Bazel 5.3 will
568 introduce support for py_proto_library, which should be used instead.
569 """
570 internal_py_proto_library(*args, **kwargs)
571
Mike Kruskaled5c57a2022-08-10 22:51:29 -0700572def _source_proto_library(
573 name,
574 srcs = [],
575 deps = [],
576 proto_deps = [],
577 outs = [],
578 lang = None,
579 includes = ["."],
580 protoc = "@com_google_protobuf//:protoc",
581 testonly = None,
582 visibility = ["//visibility:public"],
583 **kwargs):
584 """Bazel rule to create generated protobuf code from proto source files for
585 languages not well supported by Bazel yet. This will output the generated
586 code as-is without any compilation. This is most useful for interpreted
587 languages that don't require it.
588
589 NOTE: the rule is only an internal workaround to generate protos. The
590 interface may change and the rule may be removed when bazel has introduced
591 the native rule.
592
593 Args:
594 name: the name of the unsupported_proto_library.
595 srcs: the .proto files to compile. Note, that for languages where out
596 needs to be provided, only a single source file is allowed.
597 deps: a list of dependency labels; must be unsupported_proto_library.
598 proto_deps: a list of proto file dependencies that don't have a
599 unsupported_proto_library rule.
600 lang: the language to (optionally) generate code for.
601 outs: a list of expected output files. This is only required for
602 languages where we can't predict the outputs.
603 includes: strings indicating the include path of the .proto files.
604 protoc: the label of the protocol compiler to generate the sources.
605 testonly: common rule attribute (see:
606 https://bazel.build/reference/be/common-definitions#common-attributes)
607 visibility: the visibility of the generated files.
608 **kwargs: other keyword arguments that are passed to py_library.
609
610 """
611 if outs and len(srcs) != 1:
612 fail("Custom outputs only allowed for single proto targets.")
613
614 langs = []
615 if lang != None:
616 langs = [lang]
617
618 full_deps = [d + "_genproto" for d in deps]
619
620 if proto_deps:
621 _proto_gen(
622 name = name + "_deps_genproto",
623 testonly = testonly,
624 srcs = proto_deps,
625 protoc = protoc,
626 includes = includes,
627 )
628 full_deps.append(":%s_deps_genproto" % name)
629
630 _proto_gen(
631 name = name + "_genproto",
632 srcs = srcs,
633 deps = full_deps,
634 langs = langs,
635 outs = outs,
636 includes = includes,
637 protoc = protoc,
638 testonly = testonly,
639 visibility = visibility,
640 )
641
642 native.filegroup(
643 name = name,
644 srcs = [":%s_genproto"%name],
645 testonly = testonly,
646 visibility = visibility,
647 **kwargs
648 )
649
650def internal_csharp_proto_library(**kwargs):
651 """Bazel rule to create a C# protobuf library from proto source files
652
653 NOTE: the rule is only an internal workaround to generate protos. The
654 interface may change and the rule may be removed when bazel has introduced
655 the native rule.
656
657 Args:
658 **kwargs: arguments that are passed to unsupported_proto_library.
659
660 """
661
662 _source_proto_library(
663 lang = "csharp",
664 **kwargs
665 )
666
667def internal_php_proto_library(**kwargs):
668 """Bazel rule to create a PHP protobuf library from proto source files
669
670 NOTE: the rule is only an internal workaround to generate protos. The
671 interface may change and the rule may be removed when bazel has introduced
672 the native rule.
673
674 Args:
675 **kwargs: arguments that are passed to unsupported_proto_library.
676
677 """
678 if not kwargs.get("outs"):
679 fail("Unable to predict the outputs for php_proto_library. Please specify them via `outs`.")
680
681 _source_proto_library(
682 lang = "php",
683 **kwargs
684 )
685
686def internal_ruby_proto_library(**kwargs):
687 """Bazel rule to create a Ruby protobuf library from proto source files
688
689 NOTE: the rule is only an internal workaround to generate protos. The
690 interface may change and the rule may be removed when bazel has introduced
691 the native rule.
692
693 Args:
694 **kwargs: arguments that are passed to unsupported_proto_library.
695
696 """
697
698 _source_proto_library(
699 lang = "ruby",
700 **kwargs
701 )
702
Fahrzin Hemmati35119e32017-11-28 14:24:53 -0800703def check_protobuf_required_bazel_version():
Paul Yangcecba292018-12-14 16:05:03 -0800704 """For WORKSPACE files, to check the installed version of bazel.
Fahrzin Hemmati35119e32017-11-28 14:24:53 -0800705
Paul Yangcecba292018-12-14 16:05:03 -0800706 This ensures bazel supports our approach to proto_library() depending on a
707 copied filegroup. (Fixed in bazel 0.5.4)
708 """
709 versions.check(minimum_bazel_version = "0.5.4")