mirror of https://github.com/grpc/grpc.git
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
6.7 KiB
207 lines
6.7 KiB
# Copyright 2021 The 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. |
|
"""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("@rules_proto//proto:defs.bzl", "ProtoInfo") |
|
load( |
|
"//bazel: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. |
|
|
|
Args: |
|
ctx: The context object. |
|
Returns: |
|
The provider for the generated files. |
|
""" |
|
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.append("--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.append("--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_type_protos is supported", |
|
) # buildifier: disable=print |
|
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.append("-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, |
|
tools = tools, |
|
outputs = out_files, |
|
executable = ctx.executable._protoc, |
|
arguments = arguments, |
|
use_default_shell_env = True, |
|
) |
|
|
|
return struct(files = depset(out_files)) # buildifier: disable=rule-impl-return |
|
|
|
_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, |
|
), |
|
"well_known_protos": attr.label(mandatory = False), |
|
"generate_mocks": attr.bool( |
|
default = False, |
|
mandatory = False, |
|
), |
|
"_protoc": attr.label( |
|
default = Label("//external:protocol_compiler"), |
|
executable = True, |
|
cfg = "host", |
|
), |
|
}, |
|
# We generate .h files, so we need to output to genfiles. |
|
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_type_protos", |
|
**kwargs |
|
) |
|
else: |
|
_generate_cc(**kwargs)
|
|
|