|
|
@@ -1,12 +1,27 @@
|
|
|
-# -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED
|
|
|
-
|
|
|
def _GetPath(ctx, path):
|
|
|
if ctx.label.workspace_root:
|
|
|
return ctx.label.workspace_root + '/' + path
|
|
|
else:
|
|
|
return path
|
|
|
|
|
|
+def _IsNewExternal(ctx):
|
|
|
+ # Bazel 0.4.4 and older have genfiles paths that look like:
|
|
|
+ # bazel-out/local-fastbuild/genfiles/external/repo/foo
|
|
|
+ # After the exec root rearrangement, they look like:
|
|
|
+ # ../repo/bazel-out/local-fastbuild/genfiles/foo
|
|
|
+ return ctx.label.workspace_root.startswith("../")
|
|
|
+
|
|
|
def _GenDir(ctx):
|
|
|
+ if _IsNewExternal(ctx):
|
|
|
+ # We are using the fact that Bazel 0.4.4+ provides repository-relative paths
|
|
|
+ # for ctx.genfiles_dir.
|
|
|
+ return ctx.genfiles_dir.path + (
|
|
|
+ "/" + ctx.attr.includes[0] if ctx.attr.includes and ctx.attr.includes[0] else "")
|
|
|
+ # This means that we're either in the old version OR the new version in the local repo.
|
|
|
+ # Either way, appending the source path to the genfiles dir works.
|
|
|
+ return ctx.var["GENDIR"] + "/" + _SourceDir(ctx)
|
|
|
+
|
|
|
+def _SourceDir(ctx):
|
|
|
if not ctx.attr.includes:
|
|
|
return ctx.label.workspace_root
|
|
|
if not ctx.attr.includes[0]:
|
|
|
@@ -15,14 +30,21 @@ def _GenDir(ctx):
|
|
|
return _GetPath(ctx, ctx.attr.includes[0])
|
|
|
return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0])
|
|
|
|
|
|
-def _CcOuts(srcs, use_grpc_plugin=False):
|
|
|
- ret = [s[:-len(".proto")] + ".pb.h" for s in srcs] + \
|
|
|
- [s[:-len(".proto")] + ".pb.cc" for s in srcs]
|
|
|
+def _CcHdrs(srcs, use_grpc_plugin=False):
|
|
|
+ ret = [s[:-len(".proto")] + ".pb.h" for s in srcs]
|
|
|
if use_grpc_plugin:
|
|
|
- ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs] + \
|
|
|
- [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs]
|
|
|
+ ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs]
|
|
|
return ret
|
|
|
|
|
|
+def _CcSrcs(srcs, use_grpc_plugin=False):
|
|
|
+ ret = [s[:-len(".proto")] + ".pb.cc" for s in srcs]
|
|
|
+ if use_grpc_plugin:
|
|
|
+ ret += [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs]
|
|
|
+ return ret
|
|
|
+
|
|
|
+def _CcOuts(srcs, use_grpc_plugin=False):
|
|
|
+ return _CcHdrs(srcs, use_grpc_plugin) + _CcSrcs(srcs, use_grpc_plugin)
|
|
|
+
|
|
|
def _PyOuts(srcs):
|
|
|
return [s[:-len(".proto")] + "_pb2.py" for s in srcs]
|
|
|
|
|
|
@@ -46,9 +68,10 @@ def _proto_gen_impl(ctx):
|
|
|
srcs = ctx.files.srcs
|
|
|
deps = []
|
|
|
deps += ctx.files.srcs
|
|
|
+ source_dir = _SourceDir(ctx)
|
|
|
gen_dir = _GenDir(ctx)
|
|
|
- if gen_dir:
|
|
|
- import_flags = ["-I" + gen_dir, "-I" + ctx.var["GENDIR"] + "/" + gen_dir]
|
|
|
+ if source_dir:
|
|
|
+ import_flags = ["-I" + source_dir, "-I" + gen_dir]
|
|
|
else:
|
|
|
import_flags = ["-I."]
|
|
|
|
|
|
@@ -58,20 +81,33 @@ def _proto_gen_impl(ctx):
|
|
|
|
|
|
args = []
|
|
|
if ctx.attr.gen_cc:
|
|
|
- args += ["--cpp_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
|
|
|
+ args += ["--cpp_out=" + gen_dir]
|
|
|
if ctx.attr.gen_py:
|
|
|
- args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
|
|
|
-
|
|
|
- if ctx.executable.grpc_cpp_plugin:
|
|
|
- args += ["--plugin=protoc-gen-grpc=" + ctx.executable.grpc_cpp_plugin.path]
|
|
|
- args += ["--grpc_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
|
|
|
+ args += ["--python_out=" + gen_dir]
|
|
|
+
|
|
|
+ inputs = srcs + deps
|
|
|
+ if ctx.executable.plugin:
|
|
|
+ plugin = ctx.executable.plugin
|
|
|
+ lang = ctx.attr.plugin_language
|
|
|
+ if not lang and plugin.basename.startswith('protoc-gen-'):
|
|
|
+ lang = plugin.basename[len('protoc-gen-'):]
|
|
|
+ if not lang:
|
|
|
+ fail("cannot infer the target language of plugin", "plugin_language")
|
|
|
+
|
|
|
+ outdir = gen_dir
|
|
|
+ if ctx.attr.plugin_options:
|
|
|
+ outdir = ",".join(ctx.attr.plugin_options) + ":" + outdir
|
|
|
+ args += ["--plugin=protoc-gen-%s=%s" % (lang, plugin.path)]
|
|
|
+ args += ["--%s_out=%s" % (lang, outdir)]
|
|
|
+ inputs += [plugin]
|
|
|
|
|
|
if args:
|
|
|
ctx.action(
|
|
|
- inputs=srcs + deps,
|
|
|
+ inputs=inputs,
|
|
|
outputs=ctx.outputs.outs,
|
|
|
arguments=args + import_flags + [s.path for s in srcs],
|
|
|
executable=ctx.executable.protoc,
|
|
|
+ mnemonic="ProtoCompile",
|
|
|
)
|
|
|
|
|
|
return struct(
|
|
|
@@ -82,7 +118,7 @@ def _proto_gen_impl(ctx):
|
|
|
),
|
|
|
)
|
|
|
|
|
|
-_proto_gen = rule(
|
|
|
+proto_gen = rule(
|
|
|
attrs = {
|
|
|
"srcs": attr.label_list(allow_files = True),
|
|
|
"deps": attr.label_list(providers = ["proto"]),
|
|
|
@@ -93,11 +129,13 @@ _proto_gen = rule(
|
|
|
single_file = True,
|
|
|
mandatory = True,
|
|
|
),
|
|
|
- "grpc_cpp_plugin": attr.label(
|
|
|
+ "plugin": attr.label(
|
|
|
cfg = "host",
|
|
|
+ allow_files = True,
|
|
|
executable = True,
|
|
|
- single_file = True,
|
|
|
),
|
|
|
+ "plugin_language": attr.string(),
|
|
|
+ "plugin_options": attr.string_list(),
|
|
|
"gen_cc": attr.bool(),
|
|
|
"gen_py": attr.bool(),
|
|
|
"outs": attr.output_list(),
|
|
|
@@ -105,6 +143,26 @@ _proto_gen = rule(
|
|
|
output_to_genfiles = True,
|
|
|
implementation = _proto_gen_impl,
|
|
|
)
|
|
|
+"""Generates codes from Protocol Buffers definitions.
|
|
|
+
|
|
|
+This rule helps you to implement Skylark macros specific to the target
|
|
|
+language. You should prefer more specific `cc_proto_library `,
|
|
|
+`py_proto_library` and others unless you are adding such wrapper macros.
|
|
|
+
|
|
|
+Args:
|
|
|
+ srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
|
|
|
+ against.
|
|
|
+ deps: a list of dependency labels; must be other proto libraries.
|
|
|
+ includes: a list of include paths to .proto files.
|
|
|
+ protoc: the label of the protocol compiler to generate the sources.
|
|
|
+ plugin: the label of the protocol compiler plugin to be passed to the protocol
|
|
|
+ compiler.
|
|
|
+ plugin_language: the language of the generated sources
|
|
|
+ plugin_options: a list of options to be passed to the plugin
|
|
|
+ gen_cc: generates C++ sources in addition to the ones from the plugin.
|
|
|
+ gen_py: generates Python sources in addition to the ones from the plugin.
|
|
|
+ outs: a list of labels of the expected outputs from the protocol compiler.
|
|
|
+"""
|
|
|
|
|
|
def cc_proto_library(
|
|
|
name,
|
|
|
@@ -150,7 +208,7 @@ def cc_proto_library(
|
|
|
if internal_bootstrap_hack:
|
|
|
# For pre-checked-in generated files, we add the internal_bootstrap_hack
|
|
|
# which will skip the codegen action.
|
|
|
- _proto_gen(
|
|
|
+ proto_gen(
|
|
|
name=name + "_genproto",
|
|
|
srcs=srcs,
|
|
|
deps=[s + "_genproto" for s in deps],
|
|
|
@@ -168,15 +226,18 @@ def cc_proto_library(
|
|
|
if use_grpc_plugin:
|
|
|
grpc_cpp_plugin = "//external:grpc_cpp_plugin"
|
|
|
|
|
|
- outs = _CcOuts(srcs, use_grpc_plugin)
|
|
|
+ gen_srcs = _CcSrcs(srcs, use_grpc_plugin)
|
|
|
+ gen_hdrs = _CcHdrs(srcs, use_grpc_plugin)
|
|
|
+ outs = gen_srcs + gen_hdrs
|
|
|
|
|
|
- _proto_gen(
|
|
|
+ proto_gen(
|
|
|
name=name + "_genproto",
|
|
|
srcs=srcs,
|
|
|
deps=[s + "_genproto" for s in deps],
|
|
|
includes=includes,
|
|
|
protoc=protoc,
|
|
|
- grpc_cpp_plugin=grpc_cpp_plugin,
|
|
|
+ plugin=grpc_cpp_plugin,
|
|
|
+ plugin_language="grpc",
|
|
|
gen_cc=1,
|
|
|
outs=outs,
|
|
|
visibility=["//visibility:public"],
|
|
|
@@ -189,12 +250,12 @@ def cc_proto_library(
|
|
|
|
|
|
native.cc_library(
|
|
|
name=name,
|
|
|
- srcs=outs,
|
|
|
+ srcs=gen_srcs,
|
|
|
+ hdrs=gen_hdrs,
|
|
|
deps=cc_libs + deps,
|
|
|
includes=includes,
|
|
|
**kargs)
|
|
|
|
|
|
-
|
|
|
def internal_gen_well_known_protos_java(srcs):
|
|
|
"""Bazel rule to generate the gen_well_known_protos_java genrule
|
|
|
|
|
|
@@ -202,10 +263,11 @@ def internal_gen_well_known_protos_java(srcs):
|
|
|
srcs: the well known protos
|
|
|
"""
|
|
|
root = Label("%s//protobuf_java" % (REPOSITORY_NAME)).workspace_root
|
|
|
+ pkg = PACKAGE_NAME + "/" if PACKAGE_NAME else ""
|
|
|
if root == "":
|
|
|
- include = " -Isrc "
|
|
|
+ include = " -I%ssrc " % pkg
|
|
|
else:
|
|
|
- include = " -I%s/src " % root
|
|
|
+ include = " -I%s/%ssrc " % (root, pkg)
|
|
|
native.genrule(
|
|
|
name = "gen_well_known_protos_java",
|
|
|
srcs = srcs,
|
|
|
@@ -218,7 +280,6 @@ def internal_gen_well_known_protos_java(srcs):
|
|
|
tools = [":protoc"],
|
|
|
)
|
|
|
|
|
|
-
|
|
|
def internal_copied_filegroup(name, srcs, strip_prefix, dest, **kwargs):
|
|
|
"""Macro to copy files to a different directory and then create a filegroup.
|
|
|
|
|
|
@@ -248,7 +309,6 @@ def internal_copied_filegroup(name, srcs, strip_prefix, dest, **kwargs):
|
|
|
srcs = outs,
|
|
|
**kwargs)
|
|
|
|
|
|
-
|
|
|
def py_proto_library(
|
|
|
name,
|
|
|
srcs=[],
|
|
|
@@ -258,6 +318,7 @@ def py_proto_library(
|
|
|
include=None,
|
|
|
default_runtime="//:protobuf_python",
|
|
|
protoc="//:protoc",
|
|
|
+ use_grpc_plugin=False,
|
|
|
**kargs):
|
|
|
"""Bazel rule to create a Python protobuf library from proto source files
|
|
|
|
|
|
@@ -277,6 +338,8 @@ def py_proto_library(
|
|
|
default_runtime: the implicitly default runtime which will be depended on by
|
|
|
the generated py_library target.
|
|
|
protoc: the label of the protocol compiler to generate the sources.
|
|
|
+ use_grpc_plugin: a flag to indicate whether to call the Python C++ plugin
|
|
|
+ when processing the proto files.
|
|
|
**kargs: other keyword arguments that are passed to cc_library.
|
|
|
|
|
|
"""
|
|
|
@@ -286,7 +349,14 @@ def py_proto_library(
|
|
|
if include != None:
|
|
|
includes = [include]
|
|
|
|
|
|
- _proto_gen(
|
|
|
+ grpc_python_plugin = None
|
|
|
+ if use_grpc_plugin:
|
|
|
+ grpc_python_plugin = "//external:grpc_python_plugin"
|
|
|
+ # Note: Generated grpc code depends on Python grpc module. This dependency
|
|
|
+ # is not explicitly listed in py_libs. Instead, host system is assumed to
|
|
|
+ # have grpc installed.
|
|
|
+
|
|
|
+ proto_gen(
|
|
|
name=name + "_genproto",
|
|
|
srcs=srcs,
|
|
|
deps=[s + "_genproto" for s in deps],
|
|
|
@@ -295,6 +365,8 @@ def py_proto_library(
|
|
|
gen_py=1,
|
|
|
outs=outs,
|
|
|
visibility=["//visibility:public"],
|
|
|
+ plugin=grpc_python_plugin,
|
|
|
+ plugin_language="grpc"
|
|
|
)
|
|
|
|
|
|
if default_runtime and not default_runtime in py_libs + deps:
|