xref: /aosp_15_r20/external/bazelbuild-remote-apis/internal/cc_grpc_library.bzl (revision ae21b2b400d1606a797985382019aea74177085c)
1*ae21b2b4SYike Zhang"""Rule for running the gRPC C++ code generator.
2*ae21b2b4SYike Zhang
3*ae21b2b4SYike ZhangThis is a simplified and modernised version of the upstream gRPC
4*ae21b2b4SYike Zhang`bazel/cc_grpc_library.bzl` file, which as of release v1.45
5*ae21b2b4SYike Zhang(published 2022-03-19) does not support separating the `proto_library` and
6*ae21b2b4SYike Zhang`cc_proto_library` targets into separate packages or repositories.
7*ae21b2b4SYike Zhang
8*ae21b2b4SYike ZhangThe following logic should eventually find a home in upstream gRPC, rules_proto,
9*ae21b2b4SYike Zhangor rules_cc so that the Bazel Remote APIs repository can be further decoupled
10*ae21b2b4SYike Zhangfrom language-specific concerns.
11*ae21b2b4SYike Zhang"""
12*ae21b2b4SYike Zhang
13*ae21b2b4SYike Zhangload("@com_github_grpc_grpc//bazel:protobuf.bzl", "get_include_protoc_args")
14*ae21b2b4SYike Zhang
15*ae21b2b4SYike Zhang_EXT_PROTO = ".proto"
16*ae21b2b4SYike Zhang_EXT_PROTODEVEL = ".protodevel"
17*ae21b2b4SYike Zhang_EXT_GRPC_HDR = ".grpc.pb.h"
18*ae21b2b4SYike Zhang_EXT_GRPC_SRC = ".grpc.pb.cc"
19*ae21b2b4SYike Zhang
20*ae21b2b4SYike Zhangdef _drop_proto_ext(name):
21*ae21b2b4SYike Zhang    if name.endswith(_EXT_PROTO):
22*ae21b2b4SYike Zhang        return name[:-len(_EXT_PROTO)]
23*ae21b2b4SYike Zhang    if name.endswith(_EXT_PROTODEVEL):
24*ae21b2b4SYike Zhang        return name[:-len(_EXT_PROTODEVEL)]
25*ae21b2b4SYike Zhang    fail("{!r} does not end with {!r} or {!r}".format(
26*ae21b2b4SYike Zhang        name,
27*ae21b2b4SYike Zhang        _EXT_PROTO,
28*ae21b2b4SYike Zhang        _EXT_PROTODEVEL,
29*ae21b2b4SYike Zhang    ))
30*ae21b2b4SYike Zhang
31*ae21b2b4SYike Zhangdef _proto_srcname(file):
32*ae21b2b4SYike Zhang    """Return the Protobuf source name for a proto_library source file.
33*ae21b2b4SYike Zhang
34*ae21b2b4SYike Zhang    The source name is what the Protobuf compiler uses to identify a .proto
35*ae21b2b4SYike Zhang    source file. It is relative to the compiler's `--proto_path` flag.
36*ae21b2b4SYike Zhang    """
37*ae21b2b4SYike Zhang    ws_root = file.owner.workspace_root
38*ae21b2b4SYike Zhang    if ws_root != "" and file.path.startswith(ws_root):
39*ae21b2b4SYike Zhang        return file.path[len(ws_root) + 1:]
40*ae21b2b4SYike Zhang    return file.short_path
41*ae21b2b4SYike Zhang
42*ae21b2b4SYike Zhangdef _cc_grpc_codegen(ctx):
43*ae21b2b4SYike Zhang    """Run the gRPC C++ code generator to produce sources and headers"""
44*ae21b2b4SYike Zhang    proto = ctx.attr.proto[ProtoInfo]
45*ae21b2b4SYike Zhang    proto_srcs = proto.check_deps_sources.to_list()
46*ae21b2b4SYike Zhang    proto_imports = proto.transitive_imports.to_list()
47*ae21b2b4SYike Zhang
48*ae21b2b4SYike Zhang    protoc_out = ctx.actions.declare_directory(ctx.attr.name + "_protoc_out")
49*ae21b2b4SYike Zhang    protoc_outputs = [protoc_out]
50*ae21b2b4SYike Zhang    rule_outputs = []
51*ae21b2b4SYike Zhang
52*ae21b2b4SYike Zhang    for proto_src in proto_srcs:
53*ae21b2b4SYike Zhang        srcname = _drop_proto_ext(_proto_srcname(proto_src))
54*ae21b2b4SYike Zhang        basename = _drop_proto_ext(proto_src.basename)
55*ae21b2b4SYike Zhang
56*ae21b2b4SYike Zhang        out_hdr = ctx.actions.declare_file(basename + _EXT_GRPC_HDR)
57*ae21b2b4SYike Zhang        out_src = ctx.actions.declare_file(basename + _EXT_GRPC_SRC)
58*ae21b2b4SYike Zhang
59*ae21b2b4SYike Zhang        protoc_out_prefix = protoc_out.basename
60*ae21b2b4SYike Zhang        protoc_out_hdr = ctx.actions.declare_file(
61*ae21b2b4SYike Zhang            "{}/{}".format(protoc_out_prefix, srcname + _EXT_GRPC_HDR),
62*ae21b2b4SYike Zhang        )
63*ae21b2b4SYike Zhang        protoc_out_src = ctx.actions.declare_file(
64*ae21b2b4SYike Zhang            "{}/{}".format(protoc_out_prefix, srcname + _EXT_GRPC_SRC),
65*ae21b2b4SYike Zhang        )
66*ae21b2b4SYike Zhang
67*ae21b2b4SYike Zhang        rule_outputs.extend([out_hdr, out_src])
68*ae21b2b4SYike Zhang        protoc_outputs.extend([protoc_out_hdr, protoc_out_src])
69*ae21b2b4SYike Zhang
70*ae21b2b4SYike Zhang        ctx.actions.expand_template(
71*ae21b2b4SYike Zhang            template = protoc_out_hdr,
72*ae21b2b4SYike Zhang            output = out_hdr,
73*ae21b2b4SYike Zhang            substitutions = {},
74*ae21b2b4SYike Zhang        )
75*ae21b2b4SYike Zhang        ctx.actions.expand_template(
76*ae21b2b4SYike Zhang            template = protoc_out_src,
77*ae21b2b4SYike Zhang            output = out_src,
78*ae21b2b4SYike Zhang            substitutions = {},
79*ae21b2b4SYike Zhang        )
80*ae21b2b4SYike Zhang
81*ae21b2b4SYike Zhang    plugin = ctx.executable._protoc_gen_grpc
82*ae21b2b4SYike Zhang    protoc_args = ctx.actions.args()
83*ae21b2b4SYike Zhang    protoc_args.add("--plugin", "protoc-gen-grpc=" + plugin.path)
84*ae21b2b4SYike Zhang    protoc_args.add("--grpc_out", protoc_out.path)
85*ae21b2b4SYike Zhang
86*ae21b2b4SYike Zhang    protoc_args.add_all(get_include_protoc_args(proto_imports))
87*ae21b2b4SYike Zhang    protoc_args.add_all(proto_srcs, map_each = _proto_srcname)
88*ae21b2b4SYike Zhang
89*ae21b2b4SYike Zhang    ctx.actions.run(
90*ae21b2b4SYike Zhang        executable = ctx.executable._protoc,
91*ae21b2b4SYike Zhang        arguments = [protoc_args],
92*ae21b2b4SYike Zhang        inputs = proto_srcs + proto_imports,
93*ae21b2b4SYike Zhang        outputs = protoc_outputs,
94*ae21b2b4SYike Zhang        tools = [plugin],
95*ae21b2b4SYike Zhang    )
96*ae21b2b4SYike Zhang
97*ae21b2b4SYike Zhang    return DefaultInfo(files = depset(rule_outputs))
98*ae21b2b4SYike Zhang
99*ae21b2b4SYike Zhangcc_grpc_codegen = rule(
100*ae21b2b4SYike Zhang    implementation = _cc_grpc_codegen,
101*ae21b2b4SYike Zhang    attrs = {
102*ae21b2b4SYike Zhang        "proto": attr.label(
103*ae21b2b4SYike Zhang            mandatory = True,
104*ae21b2b4SYike Zhang            allow_single_file = True,
105*ae21b2b4SYike Zhang            providers = [ProtoInfo],
106*ae21b2b4SYike Zhang        ),
107*ae21b2b4SYike Zhang        "_protoc_gen_grpc": attr.label(
108*ae21b2b4SYike Zhang            default = Label("@com_github_grpc_grpc//src/compiler:grpc_cpp_plugin"),
109*ae21b2b4SYike Zhang            executable = True,
110*ae21b2b4SYike Zhang            cfg = "host",
111*ae21b2b4SYike Zhang        ),
112*ae21b2b4SYike Zhang        "_protoc": attr.label(
113*ae21b2b4SYike Zhang            default = Label("//external:protocol_compiler"),
114*ae21b2b4SYike Zhang            executable = True,
115*ae21b2b4SYike Zhang            cfg = "host",
116*ae21b2b4SYike Zhang        ),
117*ae21b2b4SYike Zhang    },
118*ae21b2b4SYike Zhang)
119