blob: 95897506c3da258a63b02614b15fa3227f5f2dc9 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001def _GetPath(ctx, path):
Austin Schuhf9724442018-10-28 20:30:21 -07002 if ctx.label.workspace_root:
3 return ctx.label.workspace_root + '/' + path
4 else:
5 return path
6
7def _IsNewExternal(ctx):
8 # Bazel 0.4.4 and older have genfiles paths that look like:
9 # bazel-out/local-fastbuild/genfiles/external/repo/foo
10 # After the exec root rearrangement, they look like:
11 # ../repo/bazel-out/local-fastbuild/genfiles/foo
12 return ctx.label.workspace_root.startswith("../")
Brian Silverman9c614bc2016-02-15 20:20:02 -050013
14def _GenDir(ctx):
Austin Schuhf9724442018-10-28 20:30:21 -070015 if _IsNewExternal(ctx):
16 # We are using the fact that Bazel 0.4.4+ provides repository-relative paths
17 # for ctx.genfiles_dir.
18 return ctx.genfiles_dir.path + (
19 "/" + ctx.attr.includes[0] if ctx.attr.includes and ctx.attr.includes[0] else "")
20 # This means that we're either in the old version OR the new version in the local repo.
21 # Either way, appending the source path to the genfiles dir works.
22 return ctx.var["GENDIR"] + "/" + _SourceDir(ctx)
23
24def _SourceDir(ctx):
Brian Silverman9c614bc2016-02-15 20:20:02 -050025 if not ctx.attr.includes:
Austin Schuhf9724442018-10-28 20:30:21 -070026 return ctx.label.workspace_root
Brian Silverman9c614bc2016-02-15 20:20:02 -050027 if not ctx.attr.includes[0]:
28 return _GetPath(ctx, ctx.label.package)
29 if not ctx.label.package:
30 return _GetPath(ctx, ctx.attr.includes[0])
31 return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0])
32
Austin Schuhf9724442018-10-28 20:30:21 -070033def _CcHdrs(srcs, use_grpc_plugin=False):
34 ret = [s[:-len(".proto")] + ".pb.h" for s in srcs]
35 if use_grpc_plugin:
36 ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs]
37 return ret
Brian Silverman9c614bc2016-02-15 20:20:02 -050038
Austin Schuhf9724442018-10-28 20:30:21 -070039def _CcSrcs(srcs, use_grpc_plugin=False):
40 ret = [s[:-len(".proto")] + ".pb.cc" for s in srcs]
41 if use_grpc_plugin:
42 ret += [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs]
43 return ret
Brian Silverman9c614bc2016-02-15 20:20:02 -050044
Austin Schuhf9724442018-10-28 20:30:21 -070045def _CcOuts(srcs, use_grpc_plugin=False):
46 return _CcHdrs(srcs, use_grpc_plugin) + _CcSrcs(srcs, use_grpc_plugin)
47
48def _PyOuts(srcs, use_grpc_plugin=False):
49 ret = [s[:-len(".proto")] + "_pb2.py" for s in srcs]
50 if use_grpc_plugin:
51 ret += [s[:-len(".proto")] + "_pb2_grpc.py" for s in srcs]
52 return ret
53
54def _RelativeOutputPath(path, include, dest=""):
Brian Silverman9c614bc2016-02-15 20:20:02 -050055 if include == None:
56 return path
57
58 if not path.startswith(include):
59 fail("Include path %s isn't part of the path %s." % (include, path))
60
61 if include and include[-1] != '/':
62 include = include + '/'
Austin Schuhf9724442018-10-28 20:30:21 -070063 if dest and dest[-1] != '/':
64 dest = dest + '/'
Brian Silverman9c614bc2016-02-15 20:20:02 -050065
66 path = path[len(include):]
Austin Schuhf9724442018-10-28 20:30:21 -070067 return dest + path
Brian Silverman9c614bc2016-02-15 20:20:02 -050068
69def _proto_gen_impl(ctx):
70 """General implementation for generating protos"""
71 srcs = ctx.files.srcs
72 deps = []
73 deps += ctx.files.srcs
Austin Schuhf9724442018-10-28 20:30:21 -070074 source_dir = _SourceDir(ctx)
Brian Silverman9c614bc2016-02-15 20:20:02 -050075 gen_dir = _GenDir(ctx)
Austin Schuhf9724442018-10-28 20:30:21 -070076 if source_dir:
77 import_flags = ["-I" + source_dir, "-I" + gen_dir]
Brian Silverman9c614bc2016-02-15 20:20:02 -050078 else:
79 import_flags = ["-I."]
80
81 for dep in ctx.attr.deps:
82 import_flags += dep.proto.import_flags
83 deps += dep.proto.deps
84
85 args = []
86 if ctx.attr.gen_cc:
Austin Schuhf9724442018-10-28 20:30:21 -070087 args += ["--cpp_out=" + gen_dir]
Brian Silverman9c614bc2016-02-15 20:20:02 -050088 if ctx.attr.gen_py:
Austin Schuhf9724442018-10-28 20:30:21 -070089 args += ["--python_out=" + gen_dir]
90
91 inputs = srcs + deps
92 if ctx.executable.plugin:
93 plugin = ctx.executable.plugin
94 lang = ctx.attr.plugin_language
95 if not lang and plugin.basename.startswith('protoc-gen-'):
96 lang = plugin.basename[len('protoc-gen-'):]
97 if not lang:
98 fail("cannot infer the target language of plugin", "plugin_language")
99
100 outdir = gen_dir
101 if ctx.attr.plugin_options:
102 outdir = ",".join(ctx.attr.plugin_options) + ":" + outdir
103 args += ["--plugin=protoc-gen-%s=%s" % (lang, plugin.path)]
104 args += ["--%s_out=%s" % (lang, outdir)]
105 inputs += [plugin]
Brian Silverman9c614bc2016-02-15 20:20:02 -0500106
107 if args:
108 ctx.action(
Austin Schuhf9724442018-10-28 20:30:21 -0700109 inputs=inputs,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500110 outputs=ctx.outputs.outs,
111 arguments=args + import_flags + [s.path for s in srcs],
112 executable=ctx.executable.protoc,
Austin Schuhf9724442018-10-28 20:30:21 -0700113 mnemonic="ProtoCompile",
114 use_default_shell_env=True,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500115 )
116
117 return struct(
118 proto=struct(
119 srcs=srcs,
120 import_flags=import_flags,
121 deps=deps,
122 ),
123 )
124
Austin Schuhf9724442018-10-28 20:30:21 -0700125proto_gen = rule(
Brian Silverman9c614bc2016-02-15 20:20:02 -0500126 attrs = {
127 "srcs": attr.label_list(allow_files = True),
128 "deps": attr.label_list(providers = ["proto"]),
129 "includes": attr.string_list(),
130 "protoc": attr.label(
Brian Silverman7b8899e2018-06-30 19:19:24 -0700131 cfg = "host",
Brian Silverman9c614bc2016-02-15 20:20:02 -0500132 executable = True,
133 single_file = True,
134 mandatory = True,
135 ),
Austin Schuhf9724442018-10-28 20:30:21 -0700136 "plugin": attr.label(
137 cfg = "host",
138 allow_files = True,
139 executable = True,
140 ),
141 "plugin_language": attr.string(),
142 "plugin_options": attr.string_list(),
Brian Silverman9c614bc2016-02-15 20:20:02 -0500143 "gen_cc": attr.bool(),
144 "gen_py": attr.bool(),
145 "outs": attr.output_list(),
146 },
147 output_to_genfiles = True,
148 implementation = _proto_gen_impl,
149)
Austin Schuhf9724442018-10-28 20:30:21 -0700150"""Generates codes from Protocol Buffers definitions.
151
152This rule helps you to implement Skylark macros specific to the target
153language. You should prefer more specific `cc_proto_library `,
154`py_proto_library` and others unless you are adding such wrapper macros.
155
156Args:
157 srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
158 against.
159 deps: a list of dependency labels; must be other proto libraries.
160 includes: a list of include paths to .proto files.
161 protoc: the label of the protocol compiler to generate the sources.
162 plugin: the label of the protocol compiler plugin to be passed to the protocol
163 compiler.
164 plugin_language: the language of the generated sources
165 plugin_options: a list of options to be passed to the plugin
166 gen_cc: generates C++ sources in addition to the ones from the plugin.
167 gen_py: generates Python sources in addition to the ones from the plugin.
168 outs: a list of labels of the expected outputs from the protocol compiler.
169"""
170
171MSVC_COPTS = [
172 "/DHAVE_PTHREAD",
173 "/wd4018", # -Wno-sign-compare
174 "/wd4514", # -Wno-unused-function
175]
176
177load("@//tools/build_rules:select.bzl", "compiler_select")
178
179COPTS = [
180 "-DHAVE_PTHREAD",
181 "-DGOOGLE_THIRD_PARTY_PROTOBUF",
182 "-Wall",
183 "-Wwrite-strings",
184 "-Woverloaded-virtual",
185 "-Wno-sign-compare",
186 "-Wno-unused-function",
187 "-Wno-unused-parameter",
188 "-Wno-format-nonliteral",
189 "-Wno-switch-enum",
190 "-Wno-missing-field-initializers",
191 "-Wno-ignored-qualifiers",
192 ] + compiler_select({
193 "gcc": [
194 "-Wno-error=cast-align",
195 ],
196 "clang": [
197 "-Wno-unused-const-variable",
198 "-Wno-unused-private-field",
199 ],
200 })
Brian Silverman9c614bc2016-02-15 20:20:02 -0500201
202def cc_proto_library(
203 name,
204 srcs=[],
205 deps=[],
206 cc_libs=[],
207 include=None,
Austin Schuhf9724442018-10-28 20:30:21 -0700208 protoc="@com_google_protobuf//:protoc",
Brian Silverman9c614bc2016-02-15 20:20:02 -0500209 internal_bootstrap_hack=False,
Austin Schuhf9724442018-10-28 20:30:21 -0700210 use_grpc_plugin=False,
211 default_runtime="@com_google_protobuf//:protobuf",
212 compatible_with = None,
213 copts = [],
Brian Silverman9c614bc2016-02-15 20:20:02 -0500214 **kargs):
215 """Bazel rule to create a C++ protobuf library from proto source files
216
217 NOTE: the rule is only an internal workaround to generate protos. The
218 interface may change and the rule may be removed when bazel has introduced
219 the native rule.
220
221 Args:
222 name: the name of the cc_proto_library.
223 srcs: the .proto files of the cc_proto_library.
224 deps: a list of dependency labels; must be cc_proto_library.
225 cc_libs: a list of other cc_library targets depended by the generated
226 cc_library.
227 include: a string indicating the include path of the .proto files.
228 protoc: the label of the protocol compiler to generate the sources.
229 internal_bootstrap_hack: a flag indicate the cc_proto_library is used only
230 for bootstraping. When it is set to True, no files will be generated.
231 The rule will simply be a provider for .proto files, so that other
232 cc_proto_library can depend on it.
Austin Schuhf9724442018-10-28 20:30:21 -0700233 use_grpc_plugin: a flag to indicate whether to call the grpc C++ plugin
234 when processing the proto files.
Brian Silverman9c614bc2016-02-15 20:20:02 -0500235 default_runtime: the implicitly default runtime which will be depended on by
236 the generated cc_library target.
237 **kargs: other keyword arguments that are passed to cc_library.
238
239 """
240
241 includes = []
242 if include != None:
243 includes = [include]
244
245 if internal_bootstrap_hack:
246 # For pre-checked-in generated files, we add the internal_bootstrap_hack
247 # which will skip the codegen action.
Austin Schuhf9724442018-10-28 20:30:21 -0700248 proto_gen(
Brian Silverman9c614bc2016-02-15 20:20:02 -0500249 name=name + "_genproto",
250 srcs=srcs,
251 deps=[s + "_genproto" for s in deps],
252 includes=includes,
253 protoc=protoc,
254 visibility=["//visibility:public"],
255 )
256 # An empty cc_library to make rule dependency consistent.
257 native.cc_library(
258 name=name,
259 **kargs)
260 return
261
Austin Schuhf9724442018-10-28 20:30:21 -0700262 grpc_cpp_plugin = None
263 if use_grpc_plugin:
264 grpc_cpp_plugin = "//external:grpc_cpp_plugin"
265
266 gen_srcs = _CcSrcs(srcs, use_grpc_plugin)
267 gen_hdrs = _CcHdrs(srcs, use_grpc_plugin)
268 outs = gen_srcs + gen_hdrs
269
270 proto_gen(
Brian Silverman9c614bc2016-02-15 20:20:02 -0500271 name=name + "_genproto",
272 srcs=srcs,
273 deps=[s + "_genproto" for s in deps],
274 includes=includes,
275 protoc=protoc,
Austin Schuhf9724442018-10-28 20:30:21 -0700276 plugin=grpc_cpp_plugin,
277 plugin_language="grpc",
Brian Silverman9c614bc2016-02-15 20:20:02 -0500278 gen_cc=1,
279 outs=outs,
Austin Schuhf9724442018-10-28 20:30:21 -0700280 compatible_with = compatible_with,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500281 visibility=["//visibility:public"],
282 )
283
284 if default_runtime and not default_runtime in cc_libs:
Austin Schuhbe8c9b12017-11-25 15:53:12 -0800285 cc_libs = cc_libs + [default_runtime]
Austin Schuhf9724442018-10-28 20:30:21 -0700286 if use_grpc_plugin:
287 cc_libs = cc_libs + ["//external:grpc_lib"]
Brian Silverman9c614bc2016-02-15 20:20:02 -0500288
289 native.cc_library(
290 name=name,
Austin Schuhf9724442018-10-28 20:30:21 -0700291 srcs=gen_srcs,
292 hdrs=gen_hdrs,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500293 deps=cc_libs + deps,
294 includes=includes,
Austin Schuhf9724442018-10-28 20:30:21 -0700295 copts = COPTS + copts,
296 compatible_with = compatible_with,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500297 **kargs)
298
Austin Schuhf9724442018-10-28 20:30:21 -0700299def internal_gen_well_known_protos_java(srcs):
300 """Bazel rule to generate the gen_well_known_protos_java genrule
Brian Silverman9c614bc2016-02-15 20:20:02 -0500301
302 Args:
Austin Schuhf9724442018-10-28 20:30:21 -0700303 srcs: the well known protos
Brian Silverman9c614bc2016-02-15 20:20:02 -0500304 """
Austin Schuhf9724442018-10-28 20:30:21 -0700305 root = Label("%s//protobuf_java" % (REPOSITORY_NAME)).workspace_root
306 pkg = PACKAGE_NAME + "/" if PACKAGE_NAME else ""
307 if root == "":
308 include = " -I%ssrc " % pkg
309 else:
310 include = " -I%s/%ssrc " % (root, pkg)
311 native.genrule(
312 name = "gen_well_known_protos_java",
313 srcs = srcs,
314 outs = [
315 "wellknown.srcjar",
316 ],
317 cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" +
318 " %s $(SRCS) " % include +
319 " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar",
320 tools = [":protoc"],
321 )
322
323def internal_copied_filegroup(name, srcs, strip_prefix, dest, **kwargs):
324 """Macro to copy files to a different directory and then create a filegroup.
325
326 This is used by the //:protobuf_python py_proto_library target to work around
327 an issue caused by Python source files that are part of the same Python
328 package being in separate directories.
329
330 Args:
331 srcs: The source files to copy and add to the filegroup.
332 strip_prefix: Path to the root of the files to copy.
333 dest: The directory to copy the source files into.
334 **kwargs: extra arguments that will be passesd to the filegroup.
335 """
336 outs = [_RelativeOutputPath(s, strip_prefix, dest) for s in srcs]
Brian Silverman9c614bc2016-02-15 20:20:02 -0500337
338 native.genrule(
Austin Schuhf9724442018-10-28 20:30:21 -0700339 name = name + "_genrule",
340 srcs = srcs,
341 outs = outs,
342 cmd = " && ".join(
343 ["cp $(location %s) $(location %s)" %
344 (s, _RelativeOutputPath(s, strip_prefix, dest)) for s in srcs]),
345 )
Brian Silverman9c614bc2016-02-15 20:20:02 -0500346
347 native.filegroup(
Austin Schuhf9724442018-10-28 20:30:21 -0700348 name = name,
349 srcs = outs,
350 **kwargs)
Brian Silverman9c614bc2016-02-15 20:20:02 -0500351
Brian Silverman9c614bc2016-02-15 20:20:02 -0500352def py_proto_library(
353 name,
354 srcs=[],
355 deps=[],
356 py_libs=[],
357 py_extra_srcs=[],
Brian Silverman7b8899e2018-06-30 19:19:24 -0700358 py_imports=[],
Brian Silverman9c614bc2016-02-15 20:20:02 -0500359 include=None,
Austin Schuhf9724442018-10-28 20:30:21 -0700360 default_runtime="@com_google_protobuf//:protobuf_python",
361 protoc="@com_google_protobuf//:protoc",
362 use_grpc_plugin=False,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500363 **kargs):
364 """Bazel rule to create a Python protobuf library from proto source files
365
366 NOTE: the rule is only an internal workaround to generate protos. The
367 interface may change and the rule may be removed when bazel has introduced
368 the native rule.
369
370 Args:
371 name: the name of the py_proto_library.
372 srcs: the .proto files of the py_proto_library.
373 deps: a list of dependency labels; must be py_proto_library.
374 py_libs: a list of other py_library targets depended by the generated
375 py_library.
376 py_extra_srcs: extra source files that will be added to the output
377 py_library. This attribute is used for internal bootstrapping.
378 include: a string indicating the include path of the .proto files.
379 default_runtime: the implicitly default runtime which will be depended on by
380 the generated py_library target.
381 protoc: the label of the protocol compiler to generate the sources.
Austin Schuhf9724442018-10-28 20:30:21 -0700382 use_grpc_plugin: a flag to indicate whether to call the Python C++ plugin
383 when processing the proto files.
Brian Silverman9c614bc2016-02-15 20:20:02 -0500384 **kargs: other keyword arguments that are passed to cc_library.
385
386 """
Austin Schuhf9724442018-10-28 20:30:21 -0700387 outs = _PyOuts(srcs, use_grpc_plugin)
Brian Silverman9c614bc2016-02-15 20:20:02 -0500388
389 includes = []
390 if include != None:
391 includes = [include]
392
Austin Schuhf9724442018-10-28 20:30:21 -0700393 grpc_python_plugin = None
394 if use_grpc_plugin:
395 grpc_python_plugin = "//external:grpc_python_plugin"
396 # Note: Generated grpc code depends on Python grpc module. This dependency
397 # is not explicitly listed in py_libs. Instead, host system is assumed to
398 # have grpc installed.
399
400 proto_gen(
Brian Silverman9c614bc2016-02-15 20:20:02 -0500401 name=name + "_genproto",
402 srcs=srcs,
403 deps=[s + "_genproto" for s in deps],
404 includes=includes,
405 protoc=protoc,
406 gen_py=1,
407 outs=outs,
408 visibility=["//visibility:public"],
Austin Schuhf9724442018-10-28 20:30:21 -0700409 plugin=grpc_python_plugin,
410 plugin_language="grpc"
Brian Silverman9c614bc2016-02-15 20:20:02 -0500411 )
412
Brian Silverman9c614bc2016-02-15 20:20:02 -0500413 if default_runtime and not default_runtime in py_libs + deps:
Austin Schuhbe8c9b12017-11-25 15:53:12 -0800414 py_libs = py_libs + [default_runtime]
Brian Silverman9c614bc2016-02-15 20:20:02 -0500415
416 native.py_library(
417 name=name,
418 srcs=outs+py_extra_srcs,
419 deps=py_libs+deps,
Austin Schuhf9724442018-10-28 20:30:21 -0700420 imports=includes,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500421 **kargs)
422
423def internal_protobuf_py_tests(
424 name,
425 modules=[],
426 **kargs):
427 """Bazel rules to create batch tests for protobuf internal.
428
429 Args:
430 name: the name of the rule.
431 modules: a list of modules for tests. The macro will create a py_test for
432 each of the parameter with the source "google/protobuf/%s.py"
433 kargs: extra parameters that will be passed into the py_test.
434
435 """
436 for m in modules:
Austin Schuhf9724442018-10-28 20:30:21 -0700437 s = "python/google/protobuf/internal/%s.py" % m
Brian Silverman9c614bc2016-02-15 20:20:02 -0500438 native.py_test(
439 name="py_%s" % m,
440 srcs=[s],
441 main=s,
442 **kargs)
Austin Schuhf9724442018-10-28 20:30:21 -0700443
444
445def check_protobuf_required_bazel_version():
446 """For WORKSPACE files, to check the installed version of bazel.
447
448 This ensures bazel supports our approach to proto_library() depending on a
449 copied filegroup. (Fixed in bazel 0.5.4)
450 """
451 expected = apple_common.dotted_version("0.5.4")
452 current = apple_common.dotted_version(native.bazel_version)
453 if current.compare_to(expected) < 0:
454 fail("Bazel must be newer than 0.5.4")