Add gRPC's cc_grpc_library to //third_party/grpc/bazel
This adds a simplified version of gRPC's cc_grpc_library to
//third_party/grpc/bazel. I intend to replace the hacky cc_grpc_library
implemented in //tools/build_rules:genproto.bzl and used by
//src/main/protobuf:command_server_cc_proto with this one.
Aside from a general cleanup, this version of the macro supports proto
files/rules with dependencies. Future work with fine-grained failure
reporting will add dependencies to command_server.proto.
The added files, all BUILD/bzl, are taken from gRPC's v1.26.0
(commithash 'de893acb', see https://github.com/grpc/grpc/tree/v1.26.0).
Because these resources are independent of Bazel's other imports from
gRPC, there are no conflicts with the current imported version of gRPC's
C++ sources.
This includes a patch file, bazel.patch, which adapts gRPC's BUILD/bzl
sources for use by Bazel.
This simplifies the cc_grpc_library macro and its deps:
* removes cc_grpc_library's grpc_only parameter (now always true)
* removes its proto_only, well_known_protos parameters (now always
false)
* removes its use_external parameter (it was previously unused)
* adds to it an extra_cc_library_kwargs parameter (forwarded to its
generated cc_library rule)
* removes "well_known_proto" functionality from generate_cc.bzl and
protobuf.bzl
* changes generate_cc's _protoc attribute to protoc
* sets cc_grpc_library's generate_cc call's plugin and protoc arguments
to Bazel's targets ("//third_party/grpc:cpp_plugin" and
"//third_party/protobuf:protoc", respectively)
* relativizes load statements throughout
* adds "srcs" filegroup to the package's BUILD file and includes it in
//third_party/grpc:srcs
This also deletes the obsolete grpc.patch file.
diff --git a/third_party/grpc/BUILD b/third_party/grpc/BUILD
index 974b854..a7dbc1e 100644
--- a/third_party/grpc/BUILD
+++ b/third_party/grpc/BUILD
@@ -33,7 +33,9 @@
filegroup(
name = "srcs",
- srcs = glob(["**"]),
+ srcs = glob(["**"]) + [
+ "//third_party/grpc/bazel:srcs",
+ ],
)
config_setting(
diff --git a/third_party/grpc/README.bazel.md b/third_party/grpc/README.bazel.md
index 812dd7d..650bd0e 100644
--- a/third_party/grpc/README.bazel.md
+++ b/third_party/grpc/README.bazel.md
@@ -8,10 +8,19 @@
6. `rm -rf third_party/grpc/src/core/tsi/test_creds`
7. Update BUILD files by copying the rules from the BUILD file of gRPC;
fix macros in third_party/grpc/build_defs.bzl if necessary
-8. Apply local patches if necessary: `patch -p3 < netinet_tcp_h.patch`,
- `patch -p1 < grpc-gettid.patch`
+8. In the `third_party/grpc` directory, apply local patches if necessary:
+ `patch -p3 < netinet_tcp_h.patch`, `patch -p1 < grpc-gettid.patch`
9. Update //third_party/nanopb if necessary
+# How to update the BUILD/bzl sources of gRPC:
+
+1. Unless you've done so while updating C++ sources,
+ `git clone http://github.com/grpc/grpc.git` in a convenient directory
+2. `git checkout <tag>` (current is `v1.26.0`, commithash `de893acb`)
+3. `mkdir -p third_party/grpc/bazel`
+4. `cp <gRPC git tree>/bazel/{BUILD,cc_grpc_library.bzl,generate_cc.bzl,protobuf.bzl} third_party/grpc/bazel`
+5. In the `third_party/grpc` directory, apply local patches:
+ `patch -p3 < bazel.patch`
# How to update the Java plugin:
diff --git a/third_party/grpc/bazel.patch b/third_party/grpc/bazel.patch
new file mode 100644
index 0000000..3fc089d
--- /dev/null
+++ b/third_party/grpc/bazel.patch
@@ -0,0 +1,302 @@
+From 6eb4a396945bbe89831ce1d205106c1348f376e3 Mon Sep 17 00:00:00 2001
+From: Mark Schaller <mschaller@google.com>
+Date: Thu, 9 Jan 2020 19:50:57 -0500
+Subject: [PATCH] Adapt gRPC bazel files for use in Bazel
+
+This simplifies the cc_grpc_library macro and its deps:
+* removes cc_grpc_library's grpc_only parameter (now always true)
+* removes its proto_only, well_known_protos parameters (now always
+ false)
+* removes its use_external parameter (it was previously unused)
+* adds to it an extra_cc_library_kwargs parameter (forwarded to its
+ generated cc_library rule)
+* removes "well_known_proto" functionality from generate_cc.bzl and
+ protobuf.bzl
+* changes generate_cc's _protoc attribute to protoc
+* sets cc_grpc_library's generate_cc call's plugin and protoc arguments
+ to Bazel's targets ("//third_party/grpc:cpp_plugin" and
+ "//third_party/protobuf:protoc", respectively)
+* relativizes load statements throughout
+* adds "srcs" filegroup to the package's BUILD file and includes it in
+ //third_party/grpc:srcs
+
+---
+ third_party/grpc/bazel/BUILD | 5 +
+ third_party/grpc/bazel/cc_grpc_library.bzl | 127 +++++++--------------
+ third_party/grpc/bazel/generate_cc.bzl | 39 +------
+ third_party/grpc/bazel/protobuf.bzl | 16 ---
+ 4 files changed, 51 insertions(+), 136 deletions(-)
+
+diff --git a/third_party/grpc/bazel/BUILD b/third_party/grpc/bazel/BUILD
+index c3c82c9c0c..6f451a6f24 100644
+--- a/third_party/grpc/bazel/BUILD
++++ b/third_party/grpc/bazel/BUILD
+@@ -17,3 +17,8 @@ licenses(["notice"]) # Apache v2
+ package(default_visibility = ["//:__subpackages__"])
+
+ load(":cc_grpc_library.bzl", "cc_grpc_library")
++
++filegroup(
++ name = "srcs",
++ srcs = glob(["**"]),
++)
+diff --git a/third_party/grpc/bazel/cc_grpc_library.bzl b/third_party/grpc/bazel/cc_grpc_library.bzl
+index dea493eaf2..0470a294fc 100644
+--- a/third_party/grpc/bazel/cc_grpc_library.bzl
++++ b/third_party/grpc/bazel/cc_grpc_library.bzl
+@@ -1,105 +1,58 @@
+ """Generates and compiles C++ grpc stubs from proto_library rules."""
+
+-load("//bazel:generate_cc.bzl", "generate_cc")
+-load("//bazel:protobuf.bzl", "well_known_proto_libs")
++load(":generate_cc.bzl", "generate_cc")
+
++# Simplified version of gRPC upstream's cc_grpc_library.
+ def cc_grpc_library(
+ name,
+ srcs,
+ deps,
+- proto_only = False,
+- well_known_protos = False,
+ generate_mocks = False,
+- use_external = False,
+- grpc_only = False,
++ extra_cc_library_kwargs = {},
+ **kwargs):
+- """Generates C++ grpc classes for services defined in a proto file.
++ """Generates C++ grpc classes for services defined in proto_library rules.
+
+- If grpc_only is True, this rule is compatible with proto_library and
+- cc_proto_library native rules such that it expects proto_library target
+- as srcs argument and generates only grpc library classes, expecting
+- protobuf messages classes library (cc_proto_library target) to be passed in
+- deps argument. By default grpc_only is False which makes this rule to behave
+- in a backwards-compatible mode (trying to generate both proto and grpc
+- classes).
++ This rule expects a singleton list containing a proto_library target for its
++ srcs argument, and expects a list (of arbitrary size) of cc_proto_library
++ targets for its deps argument.
++
++ It generates only grpc library classes.
+
+ Assumes the generated classes will be used in cc_api_version = 2.
+
+ Args:
+ name (str): Name of rule.
+- srcs (list): A single .proto file which contains services definitions,
+- or if grpc_only parameter is True, a single proto_library which
+- contains services descriptors.
+- deps (list): A list of C++ proto_library (or cc_proto_library) which
+- provides the compiled code of any message that the services depend on.
+- proto_only (bool): If True, create only C++ proto classes library,
+- avoid creating C++ grpc classes library (expect it in deps).
+- Deprecated, use native cc_proto_library instead. False by default.
+- well_known_protos (bool): Should this library additionally depend on
+- well known protos. Deprecated, the well known protos should be
+- specified as explicit dependencies of the proto_library target
+- (passed in srcs parameter) instead. False by default.
++ srcs (list): A single proto_library which contains services descriptors.
++ deps (list): A list of cc_proto_library targets which
++ provide the compiled code of any message that the services depend on.
+ generate_mocks (bool): when True, Google Mock code for client stub is
+ generated. False by default.
+- use_external (bool): Not used.
+- grpc_only (bool): if True, generate only grpc library, expecting
+- protobuf messages library (cc_proto_library target) to be passed as
+- deps. False by default (will become True by default eventually).
+- **kwargs: rest of arguments, e.g., compatible_with and visibility
++ extra_cc_library_kwargs (map): extra arguments to pass to the cc_library
++ rule
++ **kwargs: extra arguments to pass to all rules instantiated by this
++ macro. Must be common to all build rules. See
++ https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes
+ """
+- if len(srcs) > 1:
+- fail("Only one srcs value supported", "srcs")
+- if grpc_only and proto_only:
+- fail("A mutualy exclusive configuration is specified: grpc_only = True and proto_only = True")
+-
+- extra_deps = []
+- proto_targets = []
+-
+- if not grpc_only:
+- proto_target = "_" + name + "_only"
+- cc_proto_target = name if proto_only else "_" + name + "_cc_proto"
+-
+- proto_deps = ["_" + dep + "_only" for dep in deps if dep.find(":") == -1]
+- proto_deps += [dep.split(":")[0] + ":" + "_" + dep.split(":")[1] + "_only" for dep in deps if dep.find(":") != -1]
+- if well_known_protos:
+- proto_deps += well_known_proto_libs()
+-
+- native.proto_library(
+- name = proto_target,
+- srcs = srcs,
+- deps = proto_deps,
+- **kwargs
+- )
+-
+- native.cc_proto_library(
+- name = cc_proto_target,
+- deps = [":" + proto_target],
+- **kwargs
+- )
+- extra_deps.append(":" + cc_proto_target)
+- proto_targets.append(proto_target)
+- else:
+- if not srcs:
+- fail("srcs cannot be empty", "srcs")
+- proto_targets += srcs
+-
+- if not proto_only:
+- codegen_grpc_target = "_" + name + "_grpc_codegen"
+- generate_cc(
+- name = codegen_grpc_target,
+- srcs = proto_targets,
+- plugin = "@com_github_grpc_grpc//src/compiler:grpc_cpp_plugin",
+- well_known_protos = well_known_protos,
+- generate_mocks = generate_mocks,
+- **kwargs
+- )
+-
+- native.cc_library(
+- name = name,
+- srcs = [":" + codegen_grpc_target],
+- hdrs = [":" + codegen_grpc_target],
+- deps = deps +
+- extra_deps +
+- ["@com_github_grpc_grpc//:grpc++_codegen_proto"],
+- **kwargs
+- )
++ if len(srcs) != 1:
++ fail("The srcs attribute must be a singleton list but was " + str(srcs),
++ "srcs")
++
++ codegen_grpc_target = "_" + name + "_grpc_codegen"
++ generate_cc(
++ name = codegen_grpc_target,
++ srcs = srcs,
++ plugin = "//third_party/grpc:cpp_plugin",
++ generate_mocks = generate_mocks,
++ protoc = "//third_party/protobuf:protoc",
++ **kwargs
++ )
++
++ cc_library_kwargs = dict(**extra_cc_library_kwargs)
++ cc_library_kwargs.update(**kwargs)
++ native.cc_library(
++ name = name,
++ srcs = [":" + codegen_grpc_target],
++ hdrs = [":" + codegen_grpc_target],
++ deps = deps + ["//third_party/grpc:grpc++_codegen_proto"],
++ **cc_library_kwargs
++ )
+diff --git a/third_party/grpc/bazel/generate_cc.bzl b/third_party/grpc/bazel/generate_cc.bzl
+index 484959ebb7..38a5b460f9 100644
+--- a/third_party/grpc/bazel/generate_cc.bzl
++++ b/third_party/grpc/bazel/generate_cc.bzl
+@@ -5,7 +5,7 @@ directly.
+ """
+
+ load(
+- "//bazel:protobuf.bzl",
++ ":protobuf.bzl",
+ "get_include_directory",
+ "get_plugin_args",
+ "get_proto_root",
+@@ -117,34 +117,17 @@ def generate_cc_impl(ctx):
+ arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
+ arguments += [_get_srcs_file_path(proto) for proto in protos]
+
+- # create a list of well known proto files if the argument is non-None
+- well_known_proto_files = []
+- if ctx.attr.well_known_protos:
+- f = ctx.attr.well_known_protos.files.to_list()[0].dirname
+- if f != "external/com_google_protobuf/src/google/protobuf":
+- print(
+- "Error: Only @com_google_protobuf//:well_known_protos is supported",
+- )
+- else:
+- # f points to "external/com_google_protobuf/src/google/protobuf"
+- # add -I argument to protoc so it knows where to look for the proto files.
+- arguments += ["-I{0}".format(f + "/../..")]
+- well_known_proto_files = [
+- f
+- for f in ctx.attr.well_known_protos.files.to_list()
+- ]
+-
+ ctx.actions.run(
+- inputs = protos + includes + well_known_proto_files,
++ inputs = protos + includes,
+ tools = tools,
+ outputs = out_files,
+- executable = ctx.executable._protoc,
++ executable = ctx.executable.protoc,
+ arguments = arguments,
+ )
+
+ return struct(files = depset(out_files))
+
+-_generate_cc = rule(
++generate_cc = rule(
+ attrs = {
+ "srcs": attr.label_list(
+ mandatory = True,
+@@ -160,13 +143,12 @@ _generate_cc = rule(
+ mandatory = False,
+ allow_empty = True,
+ ),
+- "well_known_protos": attr.label(mandatory = False),
+ "generate_mocks": attr.bool(
+ default = False,
+ mandatory = False,
+ ),
+- "_protoc": attr.label(
+- default = Label("//external:protocol_compiler"),
++ "protoc": attr.label(
++ mandatory = True,
+ executable = True,
+ cfg = "host",
+ ),
+@@ -175,12 +157,3 @@ _generate_cc = rule(
+ output_to_genfiles = True,
+ implementation = generate_cc_impl,
+ )
+-
+-def generate_cc(well_known_protos, **kwargs):
+- if well_known_protos:
+- _generate_cc(
+- well_known_protos = "@com_google_protobuf//:well_known_protos",
+- **kwargs
+- )
+- else:
+- _generate_cc(**kwargs)
+diff --git a/third_party/grpc/bazel/protobuf.bzl b/third_party/grpc/bazel/protobuf.bzl
+index 7af27a8b30..0d6a4135f0 100644
+--- a/third_party/grpc/bazel/protobuf.bzl
++++ b/third_party/grpc/bazel/protobuf.bzl
+@@ -3,22 +3,6 @@
+ _PROTO_EXTENSION = ".proto"
+ _VIRTUAL_IMPORTS = "/_virtual_imports/"
+
+-def well_known_proto_libs():
+- return [
+- "@com_google_protobuf//:any_proto",
+- "@com_google_protobuf//:api_proto",
+- "@com_google_protobuf//:compiler_plugin_proto",
+- "@com_google_protobuf//:descriptor_proto",
+- "@com_google_protobuf//:duration_proto",
+- "@com_google_protobuf//:empty_proto",
+- "@com_google_protobuf//:field_mask_proto",
+- "@com_google_protobuf//:source_context_proto",
+- "@com_google_protobuf//:struct_proto",
+- "@com_google_protobuf//:timestamp_proto",
+- "@com_google_protobuf//:type_proto",
+- "@com_google_protobuf//:wrappers_proto",
+- ]
+-
+ def get_proto_root(workspace_root):
+ """Gets the root protobuf directory.
+
+--
+2.25.0.rc1.283.g88dfdc4193-goog
+
diff --git a/third_party/grpc/bazel/BUILD b/third_party/grpc/bazel/BUILD
new file mode 100644
index 0000000..6f451a6
--- /dev/null
+++ b/third_party/grpc/bazel/BUILD
@@ -0,0 +1,24 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"]) # Apache v2
+
+package(default_visibility = ["//:__subpackages__"])
+
+load(":cc_grpc_library.bzl", "cc_grpc_library")
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
diff --git a/third_party/grpc/bazel/cc_grpc_library.bzl b/third_party/grpc/bazel/cc_grpc_library.bzl
new file mode 100644
index 0000000..0470a29
--- /dev/null
+++ b/third_party/grpc/bazel/cc_grpc_library.bzl
@@ -0,0 +1,58 @@
+"""Generates and compiles C++ grpc stubs from proto_library rules."""
+
+load(":generate_cc.bzl", "generate_cc")
+
+# Simplified version of gRPC upstream's cc_grpc_library.
+def cc_grpc_library(
+ name,
+ srcs,
+ deps,
+ generate_mocks = False,
+ extra_cc_library_kwargs = {},
+ **kwargs):
+ """Generates C++ grpc classes for services defined in proto_library rules.
+
+ This rule expects a singleton list containing a proto_library target for its
+ srcs argument, and expects a list (of arbitrary size) of cc_proto_library
+ targets for its deps argument.
+
+ It generates only grpc library classes.
+
+ Assumes the generated classes will be used in cc_api_version = 2.
+
+ Args:
+ name (str): Name of rule.
+ srcs (list): A single proto_library which contains services descriptors.
+ deps (list): A list of cc_proto_library targets which
+ provide the compiled code of any message that the services depend on.
+ generate_mocks (bool): when True, Google Mock code for client stub is
+ generated. False by default.
+ extra_cc_library_kwargs (map): extra arguments to pass to the cc_library
+ rule
+ **kwargs: extra arguments to pass to all rules instantiated by this
+ macro. Must be common to all build rules. See
+ https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes
+ """
+ if len(srcs) != 1:
+ fail("The srcs attribute must be a singleton list but was " + str(srcs),
+ "srcs")
+
+ codegen_grpc_target = "_" + name + "_grpc_codegen"
+ generate_cc(
+ name = codegen_grpc_target,
+ srcs = srcs,
+ plugin = "//third_party/grpc:cpp_plugin",
+ generate_mocks = generate_mocks,
+ protoc = "//third_party/protobuf:protoc",
+ **kwargs
+ )
+
+ cc_library_kwargs = dict(**extra_cc_library_kwargs)
+ cc_library_kwargs.update(**kwargs)
+ native.cc_library(
+ name = name,
+ srcs = [":" + codegen_grpc_target],
+ hdrs = [":" + codegen_grpc_target],
+ deps = deps + ["//third_party/grpc:grpc++_codegen_proto"],
+ **cc_library_kwargs
+ )
diff --git a/third_party/grpc/bazel/generate_cc.bzl b/third_party/grpc/bazel/generate_cc.bzl
new file mode 100644
index 0000000..38a5b46
--- /dev/null
+++ b/third_party/grpc/bazel/generate_cc.bzl
@@ -0,0 +1,159 @@
+"""Generates C++ grpc stubs from proto_library rules.
+
+This is an internal rule used by cc_grpc_library, and shouldn't be used
+directly.
+"""
+
+load(
+ ":protobuf.bzl",
+ "get_include_directory",
+ "get_plugin_args",
+ "get_proto_root",
+ "proto_path_to_generated_filename",
+)
+
+_GRPC_PROTO_HEADER_FMT = "{}.grpc.pb.h"
+_GRPC_PROTO_SRC_FMT = "{}.grpc.pb.cc"
+_GRPC_PROTO_MOCK_HEADER_FMT = "{}_mock.grpc.pb.h"
+_PROTO_HEADER_FMT = "{}.pb.h"
+_PROTO_SRC_FMT = "{}.pb.cc"
+
+def _strip_package_from_path(label_package, file):
+ prefix_len = 0
+ if not file.is_source and file.path.startswith(file.root.path):
+ prefix_len = len(file.root.path) + 1
+
+ path = file.path
+ if len(label_package) == 0:
+ return path
+ if not path.startswith(label_package + "/", prefix_len):
+ fail("'{}' does not lie within '{}'.".format(path, label_package))
+ return path[prefix_len + len(label_package + "/"):]
+
+def _get_srcs_file_path(file):
+ if not file.is_source and file.path.startswith(file.root.path):
+ return file.path[len(file.root.path) + 1:]
+ return file.path
+
+def _join_directories(directories):
+ massaged_directories = [directory for directory in directories if len(directory) != 0]
+ return "/".join(massaged_directories)
+
+def generate_cc_impl(ctx):
+ """Implementation of the generate_cc rule."""
+ protos = [f for src in ctx.attr.srcs for f in src[ProtoInfo].check_deps_sources.to_list()]
+ includes = [
+ f
+ for src in ctx.attr.srcs
+ for f in src[ProtoInfo].transitive_imports.to_list()
+ ]
+ outs = []
+ proto_root = get_proto_root(
+ ctx.label.workspace_root,
+ )
+
+ label_package = _join_directories([ctx.label.workspace_root, ctx.label.package])
+ if ctx.executable.plugin:
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _GRPC_PROTO_HEADER_FMT,
+ )
+ for proto in protos
+ ]
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _GRPC_PROTO_SRC_FMT,
+ )
+ for proto in protos
+ ]
+ if ctx.attr.generate_mocks:
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _GRPC_PROTO_MOCK_HEADER_FMT,
+ )
+ for proto in protos
+ ]
+ else:
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _PROTO_HEADER_FMT,
+ )
+ for proto in protos
+ ]
+ outs += [
+ proto_path_to_generated_filename(
+ _strip_package_from_path(label_package, proto),
+ _PROTO_SRC_FMT,
+ )
+ for proto in protos
+ ]
+ out_files = [ctx.actions.declare_file(out) for out in outs]
+ dir_out = str(ctx.genfiles_dir.path + proto_root)
+
+ arguments = []
+ if ctx.executable.plugin:
+ arguments += get_plugin_args(
+ ctx.executable.plugin,
+ ctx.attr.flags,
+ dir_out,
+ ctx.attr.generate_mocks,
+ )
+ tools = [ctx.executable.plugin]
+ else:
+ arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
+ tools = []
+
+ arguments += [
+ "--proto_path={}".format(get_include_directory(i))
+ for i in includes
+ ]
+
+ # Include the output directory so that protoc puts the generated code in the
+ # right directory.
+ arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
+ arguments += [_get_srcs_file_path(proto) for proto in protos]
+
+ ctx.actions.run(
+ inputs = protos + includes,
+ tools = tools,
+ outputs = out_files,
+ executable = ctx.executable.protoc,
+ arguments = arguments,
+ )
+
+ return struct(files = depset(out_files))
+
+generate_cc = rule(
+ attrs = {
+ "srcs": attr.label_list(
+ mandatory = True,
+ allow_empty = False,
+ providers = [ProtoInfo],
+ ),
+ "plugin": attr.label(
+ executable = True,
+ providers = ["files_to_run"],
+ cfg = "host",
+ ),
+ "flags": attr.string_list(
+ mandatory = False,
+ allow_empty = True,
+ ),
+ "generate_mocks": attr.bool(
+ default = False,
+ mandatory = False,
+ ),
+ "protoc": attr.label(
+ mandatory = True,
+ executable = True,
+ cfg = "host",
+ ),
+ },
+ # We generate .h files, so we need to output to genfiles.
+ output_to_genfiles = True,
+ implementation = generate_cc_impl,
+)
diff --git a/third_party/grpc/bazel/protobuf.bzl b/third_party/grpc/bazel/protobuf.bzl
new file mode 100644
index 0000000..0d6a413
--- /dev/null
+++ b/third_party/grpc/bazel/protobuf.bzl
@@ -0,0 +1,230 @@
+"""Utility functions for generating protobuf code."""
+
+_PROTO_EXTENSION = ".proto"
+_VIRTUAL_IMPORTS = "/_virtual_imports/"
+
+def get_proto_root(workspace_root):
+ """Gets the root protobuf directory.
+
+ Args:
+ workspace_root: context.label.workspace_root
+
+ Returns:
+ The directory relative to which generated include paths should be.
+ """
+ if workspace_root:
+ return "/{}".format(workspace_root)
+ else:
+ return ""
+
+def _strip_proto_extension(proto_filename):
+ if not proto_filename.endswith(_PROTO_EXTENSION):
+ fail('"{}" does not end with "{}"'.format(
+ proto_filename,
+ _PROTO_EXTENSION,
+ ))
+ return proto_filename[:-len(_PROTO_EXTENSION)]
+
+def proto_path_to_generated_filename(proto_path, fmt_str):
+ """Calculates the name of a generated file for a protobuf path.
+
+ For example, "examples/protos/helloworld.proto" might map to
+ "helloworld.pb.h".
+
+ Args:
+ proto_path: The path to the .proto file.
+ fmt_str: A format string used to calculate the generated filename. For
+ example, "{}.pb.h" might be used to calculate a C++ header filename.
+
+ Returns:
+ The generated filename.
+ """
+ return fmt_str.format(_strip_proto_extension(proto_path))
+
+def get_include_directory(source_file):
+ """Returns the include directory path for the source_file. I.e. all of the
+ include statements within the given source_file are calculated relative to
+ the directory returned by this method.
+
+ The returned directory path can be used as the "--proto_path=" argument
+ value.
+
+ Args:
+ source_file: A proto file.
+
+ Returns:
+ The include directory path for the source_file.
+ """
+ directory = source_file.path
+ prefix_len = 0
+
+ if is_in_virtual_imports(source_file):
+ root, relative = source_file.path.split(_VIRTUAL_IMPORTS, 2)
+ result = root + _VIRTUAL_IMPORTS + relative.split("/", 1)[0]
+ return result
+
+ if not source_file.is_source and directory.startswith(source_file.root.path):
+ prefix_len = len(source_file.root.path) + 1
+
+ if directory.startswith("external", prefix_len):
+ external_separator = directory.find("/", prefix_len)
+ repository_separator = directory.find("/", external_separator + 1)
+ return directory[:repository_separator]
+ else:
+ return source_file.root.path if source_file.root.path else "."
+
+def get_plugin_args(
+ plugin,
+ flags,
+ dir_out,
+ generate_mocks,
+ plugin_name = "PLUGIN"):
+ """Returns arguments configuring protoc to use a plugin for a language.
+
+ Args:
+ plugin: An executable file to run as the protoc plugin.
+ flags: The plugin flags to be passed to protoc.
+ dir_out: The output directory for the plugin.
+ generate_mocks: A bool indicating whether to generate mocks.
+ plugin_name: A name of the plugin, it is required to be unique when there
+ are more than one plugin used in a single protoc command.
+ Returns:
+ A list of protoc arguments configuring the plugin.
+ """
+ augmented_flags = list(flags)
+ if generate_mocks:
+ augmented_flags.append("generate_mock_code=true")
+
+ augmented_dir_out = dir_out
+ if augmented_flags:
+ augmented_dir_out = ",".join(augmented_flags) + ":" + dir_out
+
+ return [
+ "--plugin=protoc-gen-{plugin_name}={plugin_path}".format(
+ plugin_name = plugin_name,
+ plugin_path = plugin.path,
+ ),
+ "--{plugin_name}_out={dir_out}".format(
+ plugin_name = plugin_name,
+ dir_out = augmented_dir_out,
+ ),
+ ]
+
+def _get_staged_proto_file(context, source_file):
+ if source_file.dirname == context.label.package or \
+ is_in_virtual_imports(source_file):
+ # Current target and source_file are in same package
+ return source_file
+ else:
+ # Current target and source_file are in different packages (most
+ # probably even in different repositories)
+ copied_proto = context.actions.declare_file(source_file.basename)
+ context.actions.run_shell(
+ inputs = [source_file],
+ outputs = [copied_proto],
+ command = "cp {} {}".format(source_file.path, copied_proto.path),
+ mnemonic = "CopySourceProto",
+ )
+ return copied_proto
+
+def protos_from_context(context):
+ """Copies proto files to the appropriate location.
+
+ Args:
+ context: The ctx object for the rule.
+
+ Returns:
+ A list of the protos.
+ """
+ protos = []
+ for src in context.attr.deps:
+ for file in src[ProtoInfo].direct_sources:
+ protos.append(_get_staged_proto_file(context, file))
+ return protos
+
+def includes_from_deps(deps):
+ """Get includes from rule dependencies."""
+ return [
+ file
+ for src in deps
+ for file in src[ProtoInfo].transitive_imports.to_list()
+ ]
+
+def get_proto_arguments(protos, genfiles_dir_path):
+ """Get the protoc arguments specifying which protos to compile."""
+ arguments = []
+ for proto in protos:
+ strip_prefix_len = 0
+ if is_in_virtual_imports(proto):
+ incl_directory = get_include_directory(proto)
+ if proto.path.startswith(incl_directory):
+ strip_prefix_len = len(incl_directory) + 1
+ elif proto.path.startswith(genfiles_dir_path):
+ strip_prefix_len = len(genfiles_dir_path) + 1
+
+ arguments.append(proto.path[strip_prefix_len:])
+
+ return arguments
+
+def declare_out_files(protos, context, generated_file_format):
+ """Declares and returns the files to be generated."""
+
+ out_file_paths = []
+ for proto in protos:
+ if not is_in_virtual_imports(proto):
+ out_file_paths.append(proto.basename)
+ else:
+ path = proto.path[proto.path.index(_VIRTUAL_IMPORTS) + 1:]
+ out_file_paths.append(path)
+
+ return [
+ context.actions.declare_file(
+ proto_path_to_generated_filename(
+ out_file_path,
+ generated_file_format,
+ ),
+ )
+ for out_file_path in out_file_paths
+ ]
+
+def get_out_dir(protos, context):
+ """ Returns the calculated value for --<lang>_out= protoc argument based on
+ the input source proto files and current context.
+
+ Args:
+ protos: A list of protos to be used as source files in protoc command
+ context: A ctx object for the rule.
+ Returns:
+ The value of --<lang>_out= argument.
+ """
+ at_least_one_virtual = 0
+ for proto in protos:
+ if is_in_virtual_imports(proto):
+ at_least_one_virtual = True
+ elif at_least_one_virtual:
+ fail("Proto sources must be either all virtual imports or all real")
+ if at_least_one_virtual:
+ out_dir = get_include_directory(protos[0])
+ ws_root = protos[0].owner.workspace_root
+ if ws_root and out_dir.find(ws_root) >= 0:
+ out_dir = "".join(out_dir.rsplit(ws_root, 1))
+ return struct(
+ path = out_dir,
+ import_path = out_dir[out_dir.find(_VIRTUAL_IMPORTS) + 1:],
+ )
+ return struct(path = context.genfiles_dir.path, import_path = None)
+
+def is_in_virtual_imports(source_file, virtual_folder = _VIRTUAL_IMPORTS):
+ """Determines if source_file is virtual (is placed in _virtual_imports
+ subdirectory). The output of all proto_library targets which use
+ import_prefix and/or strip_import_prefix arguments is placed under
+ _virtual_imports directory.
+
+ Args:
+ source_file: A proto file.
+ virtual_folder: The virtual folder name (is set to "_virtual_imports"
+ by default)
+ Returns:
+ True if source_file is located under _virtual_imports, False otherwise.
+ """
+ return not source_file.is_source and virtual_folder in source_file.path
diff --git a/third_party/grpc/grpc.patch b/third_party/grpc/grpc.patch
deleted file mode 100644
index 0ce4923..0000000
--- a/third_party/grpc/grpc.patch
+++ /dev/null
@@ -1,102 +0,0 @@
-diff --git a/tools/build_rules/genproto.bzl b/tools/build_rules/genproto.bzl
-index 62284a3..bc76cd1 100644
---- a/tools/build_rules/genproto.bzl
-+++ b/tools/build_rules/genproto.bzl
-@@ -25,6 +25,8 @@ def gensrcjar_impl(ctx):
- "JAR='%s'" % ctx.executable._jar.path,
- "OUTPUT='%s'" % out.path,
- "PROTO_COMPILER='%s'" % ctx.executable._proto_compiler.path,
-+ "GRPC_JAVA_PLUGIN='%s'" % ctx.executable.grpc_java_plugin.path if \
-+ ctx.executable.grpc_java_plugin else "",
- "SOURCE='%s'" % ctx.file.src.path,
- ctx.executable._gensrcjar.path,
- ]),
-@@ -43,14 +45,19 @@ gensrcjar = rule(
- allow_files = proto_filetype,
- single_file = True,
- ),
-+ "grpc_java_plugin": attr.label(
-+ cfg = "host",
-+ executable = True,
-+ single_file = True,
-+ ),
- "_gensrcjar": attr.label(
-- default = Label("@bazel_tools//tools/build_rules:gensrcjar"),
-+ default = Label("//tools/build_rules:gensrcjar"),
- executable = True,
- ),
- # TODO(bazel-team): this should be a hidden attribute with a default
- # value, but Skylark needs to support select first.
- "_proto_compiler": attr.label(
-- default = Label("@bazel_tools//third_party/protobuf:protoc"),
-+ default = Label("//third_party/protobuf:protoc"),
- allow_files = True,
- executable = True,
- single_file = True,
-@@ -73,13 +80,42 @@ gensrcjar = rule(
- outputs = {"srcjar": "lib%{name}.srcjar"},
- )
-
-+def cc_grpc_library(name, src):
-+ basename = src[:-len(".proto")]
-+
-+ native.genrule(
-+ name = name + "_codegen",
-+ srcs = [src],
-+ tools = ["//third_party/protobuf:protoc", "//third_party/grpc:cpp_plugin"],
-+ cmd = "\\\n".join([
-+ "$(location //third_party/protobuf:protoc)",
-+ " --plugin=protoc-gen-grpc=$(location //third_party/grpc:cpp_plugin)",
-+ " --cpp_out=$(GENDIR)",
-+ " --grpc_out=$(GENDIR)",
-+ " $(location " + src + ")"]),
-+ outs = [basename + ".grpc.pb.h", basename + ".grpc.pb.cc", basename + ".pb.cc", basename + ".pb.h"])
-+
-+ native.cc_library(
-+ name = name,
-+ srcs = [basename + ".grpc.pb.cc", basename + ".pb.cc"],
-+ hdrs = [basename + ".grpc.pb.h", basename + ".pb.h"],
-+ deps = ["//third_party/grpc:grpc++"],
-+ includes = ["."])
-+
- # TODO(bazel-team): support proto => proto dependencies too
--def java_proto_library(name, src):
-- gensrcjar(name=name + "_srcjar", src=src)
-+def java_proto_library(name, src, use_grpc_plugin=False):
-+ grpc_java_plugin = None
-+ if use_grpc_plugin:
-+ grpc_java_plugin = "//third_party/grpc:grpc-java-plugin"
-+
-+ gensrcjar(name=name + "_srcjar", src=src, grpc_java_plugin=grpc_java_plugin)
-+ deps = ["//third_party/protobuf"]
-+ if use_grpc_plugin:
-+ deps += ["//third_party/grpc:grpc-jar", "//third_party:guava"]
- native.java_library(
- name=name,
- srcs=[name + "_srcjar"],
-- deps=["@bazel_tools//third_party/protobuf"],
-+ deps=deps,
- # The generated code has lots of 'rawtypes' warnings.
- javacopts=["-Xlint:-rawtypes"],
- )
-diff --git a/tools/build_rules/gensrcjar.sh b/tools/build_rules/gensrcjar.sh
-index b94408a..c1674a3 100755
---- a/tools/build_rules/gensrcjar.sh
-+++ b/tools/build_rules/gensrcjar.sh
-@@ -65,8 +65,14 @@ main() {
- "${PREPROCESSOR}" <"${SOURCE}" >"${processed_source}" \
- || err "Preprocessor ${PREPROCESSOR} failed"
-
-- "${PROTO_COMPILER}" --java_out="${proto_output}" "${processed_source}" \
-- || err "proto_compiler failed"
-+ if [ -n "${GRPC_JAVA_PLUGIN}" ]; then
-+ "${PROTO_COMPILER}" --plugin=protoc-gen-grpc="${GRPC_JAVA_PLUGIN}" \
-+ --grpc_out="${proto_output}" --java_out="${proto_output}" "${processed_source}" \
-+ || err "proto_compiler failed"
-+ else
-+ "${PROTO_COMPILER}" --java_out="${proto_output}" "${processed_source}" \
-+ || err "proto_compiler failed"
-+ fi
- find "${proto_output}" -exec touch -t "${TIMESTAMP}" '{}' \; \
- || err "Failed to reset timestamps"
- "${JAR}" cMf "${OUTPUT}.tmp" -C "${proto_output}" . \