xref: /aosp_15_r20/build/bazel/rules/proto_file_utils.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1*7594170eSAndroid Build Coastguard Worker# Copyright (C) 2021 The Android Open Source Project
2*7594170eSAndroid Build Coastguard Worker#
3*7594170eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*7594170eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*7594170eSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*7594170eSAndroid Build Coastguard Worker#
7*7594170eSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*7594170eSAndroid Build Coastguard Worker#
9*7594170eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*7594170eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*7594170eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*7594170eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*7594170eSAndroid Build Coastguard Worker# limitations under the License.
14*7594170eSAndroid Build Coastguard Worker
15*7594170eSAndroid Build Coastguard Workerload("@bazel_skylib//lib:paths.bzl", "paths")
16*7594170eSAndroid Build Coastguard Workerload("@bazel_skylib//lib:sets.bzl", "sets")
17*7594170eSAndroid Build Coastguard Worker
18*7594170eSAndroid Build Coastguard Workerdef _generate_and_declare_output_files(
19*7594170eSAndroid Build Coastguard Worker        ctx,
20*7594170eSAndroid Build Coastguard Worker        proto_rel_paths,
21*7594170eSAndroid Build Coastguard Worker        type_dictionary):
22*7594170eSAndroid Build Coastguard Worker    ret = {}
23*7594170eSAndroid Build Coastguard Worker    for typ in type_dictionary:
24*7594170eSAndroid Build Coastguard Worker        ret[typ] = []
25*7594170eSAndroid Build Coastguard Worker
26*7594170eSAndroid Build Coastguard Worker    for proto_rel_path in proto_rel_paths:
27*7594170eSAndroid Build Coastguard Worker        for typ, ext in type_dictionary.items():
28*7594170eSAndroid Build Coastguard Worker            # prefix with label.name to prevent collisions between targets
29*7594170eSAndroid Build Coastguard Worker            # if proto compliation becomes an aspect, can prefix with output
30*7594170eSAndroid Build Coastguard Worker            # information instead to allow reuse, e.g. multiple cc `lite`
31*7594170eSAndroid Build Coastguard Worker            # libraries containing the same proto file
32*7594170eSAndroid Build Coastguard Worker            out_name = paths.join(ctx.label.name, paths.replace_extension(proto_rel_path, ext))
33*7594170eSAndroid Build Coastguard Worker            declared = ctx.actions.declare_file(out_name)
34*7594170eSAndroid Build Coastguard Worker            ret[typ].append(declared)
35*7594170eSAndroid Build Coastguard Worker
36*7594170eSAndroid Build Coastguard Worker    return ret
37*7594170eSAndroid Build Coastguard Worker
38*7594170eSAndroid Build Coastguard Workerdef _generate_jar_proto_action(
39*7594170eSAndroid Build Coastguard Worker        proto_infos,
40*7594170eSAndroid Build Coastguard Worker        protoc,
41*7594170eSAndroid Build Coastguard Worker        ctx,
42*7594170eSAndroid Build Coastguard Worker        out_flags = [],
43*7594170eSAndroid Build Coastguard Worker        plugin_executable = None,
44*7594170eSAndroid Build Coastguard Worker        out_arg = None,
45*7594170eSAndroid Build Coastguard Worker        mnemonic = "ProtoGen",
46*7594170eSAndroid Build Coastguard Worker        transitive_proto_infos = []):
47*7594170eSAndroid Build Coastguard Worker    jar_basename = ctx.label.name + "-proto_gen"
48*7594170eSAndroid Build Coastguard Worker    jar_name = jar_basename + "-src.jar"
49*7594170eSAndroid Build Coastguard Worker    jar_file = ctx.actions.declare_file(jar_name)
50*7594170eSAndroid Build Coastguard Worker
51*7594170eSAndroid Build Coastguard Worker    _generate_proto_action(
52*7594170eSAndroid Build Coastguard Worker        proto_infos = proto_infos,
53*7594170eSAndroid Build Coastguard Worker        protoc = protoc,
54*7594170eSAndroid Build Coastguard Worker        ctx = ctx,
55*7594170eSAndroid Build Coastguard Worker        out_flags = out_flags,
56*7594170eSAndroid Build Coastguard Worker        plugin_executable = plugin_executable,
57*7594170eSAndroid Build Coastguard Worker        out_arg = out_arg,
58*7594170eSAndroid Build Coastguard Worker        mnemonic = mnemonic,
59*7594170eSAndroid Build Coastguard Worker        output_file = jar_file,
60*7594170eSAndroid Build Coastguard Worker        transitive_proto_infos = transitive_proto_infos,
61*7594170eSAndroid Build Coastguard Worker    )
62*7594170eSAndroid Build Coastguard Worker
63*7594170eSAndroid Build Coastguard Worker    srcjar_name = jar_basename + ".srcjar"
64*7594170eSAndroid Build Coastguard Worker    srcjar_file = ctx.actions.declare_file(srcjar_name)
65*7594170eSAndroid Build Coastguard Worker    ctx.actions.symlink(
66*7594170eSAndroid Build Coastguard Worker        output = srcjar_file,
67*7594170eSAndroid Build Coastguard Worker        target_file = jar_file,
68*7594170eSAndroid Build Coastguard Worker    )
69*7594170eSAndroid Build Coastguard Worker
70*7594170eSAndroid Build Coastguard Worker    return srcjar_file
71*7594170eSAndroid Build Coastguard Worker
72*7594170eSAndroid Build Coastguard Workerdef _generate_proto_action(
73*7594170eSAndroid Build Coastguard Worker        proto_infos,
74*7594170eSAndroid Build Coastguard Worker        protoc,
75*7594170eSAndroid Build Coastguard Worker        ctx,
76*7594170eSAndroid Build Coastguard Worker        type_dictionary = None,
77*7594170eSAndroid Build Coastguard Worker        out_flags = [],
78*7594170eSAndroid Build Coastguard Worker        plugin_executable = None,
79*7594170eSAndroid Build Coastguard Worker        out_arg = None,
80*7594170eSAndroid Build Coastguard Worker        mnemonic = "ProtoGen",
81*7594170eSAndroid Build Coastguard Worker        output_file = None,
82*7594170eSAndroid Build Coastguard Worker        transitive_proto_infos = []):
83*7594170eSAndroid Build Coastguard Worker    """ Utility function for creating proto_compiler action.
84*7594170eSAndroid Build Coastguard Worker
85*7594170eSAndroid Build Coastguard Worker    Args:
86*7594170eSAndroid Build Coastguard Worker      proto_infos: A list of ProtoInfo.
87*7594170eSAndroid Build Coastguard Worker      protoc: proto compiler executable.
88*7594170eSAndroid Build Coastguard Worker      ctx: context, used for declaring new files only.
89*7594170eSAndroid Build Coastguard Worker      type_dictionary: a dictionary of types to output extensions
90*7594170eSAndroid Build Coastguard Worker      out_flags: protoc output flags
91*7594170eSAndroid Build Coastguard Worker      plugin_executable: plugin executable file
92*7594170eSAndroid Build Coastguard Worker      out_arg: as appropriate, if plugin_executable and out_arg are both supplied, plugin_executable is preferred
93*7594170eSAndroid Build Coastguard Worker      mnemonic: (optional) a string to describe the proto compilation action
94*7594170eSAndroid Build Coastguard Worker      output_file: (optional) File, used to specify a specific file for protoc output (typically a JAR file)
95*7594170eSAndroid Build Coastguard Worker
96*7594170eSAndroid Build Coastguard Worker    Returns:
97*7594170eSAndroid Build Coastguard Worker      Dictionary with declared files grouped by type from the type_dictionary.
98*7594170eSAndroid Build Coastguard Worker    """
99*7594170eSAndroid Build Coastguard Worker
100*7594170eSAndroid Build Coastguard Worker    # TODO(B/245629074): Don't build external/protobuf if it is provided in
101*7594170eSAndroid Build Coastguard Worker    #  toolchain already.
102*7594170eSAndroid Build Coastguard Worker    proto_srcs = []
103*7594170eSAndroid Build Coastguard Worker    proto_rel_srcs = []
104*7594170eSAndroid Build Coastguard Worker    proto_source_root_list = sets.make()
105*7594170eSAndroid Build Coastguard Worker    transitive_proto_srcs_list = []
106*7594170eSAndroid Build Coastguard Worker    transitive_proto_path_list = sets.make()
107*7594170eSAndroid Build Coastguard Worker
108*7594170eSAndroid Build Coastguard Worker    for proto_info in proto_infos:
109*7594170eSAndroid Build Coastguard Worker        sets.insert(proto_source_root_list, proto_info.proto_source_root)
110*7594170eSAndroid Build Coastguard Worker        proto_srcs.extend(proto_info.direct_sources)
111*7594170eSAndroid Build Coastguard Worker        proto_rel_srcs.extend([paths.relativize(p.path, proto_info.proto_source_root) for p in proto_info.direct_sources])
112*7594170eSAndroid Build Coastguard Worker        transitive_proto_srcs_list.append(proto_info.transitive_imports)
113*7594170eSAndroid Build Coastguard Worker        for p in proto_info.transitive_proto_path.to_list():
114*7594170eSAndroid Build Coastguard Worker            sets.insert(transitive_proto_path_list, p)
115*7594170eSAndroid Build Coastguard Worker
116*7594170eSAndroid Build Coastguard Worker    for transitive_proto_info in transitive_proto_infos:
117*7594170eSAndroid Build Coastguard Worker        sets.insert(transitive_proto_path_list, transitive_proto_info.proto_source_root)
118*7594170eSAndroid Build Coastguard Worker        transitive_proto_srcs_list.append(depset(transitive_proto_info.direct_sources))
119*7594170eSAndroid Build Coastguard Worker
120*7594170eSAndroid Build Coastguard Worker    protoc_out_name = paths.join(ctx.bin_dir.path, ctx.label.package)
121*7594170eSAndroid Build Coastguard Worker
122*7594170eSAndroid Build Coastguard Worker    if output_file:
123*7594170eSAndroid Build Coastguard Worker        protoc_out_name = paths.join(protoc_out_name, output_file.basename)
124*7594170eSAndroid Build Coastguard Worker        out_files = {
125*7594170eSAndroid Build Coastguard Worker            "out": [output_file],
126*7594170eSAndroid Build Coastguard Worker        }
127*7594170eSAndroid Build Coastguard Worker    else:
128*7594170eSAndroid Build Coastguard Worker        protoc_out_name = paths.join(protoc_out_name, ctx.label.name)
129*7594170eSAndroid Build Coastguard Worker        out_files = _generate_and_declare_output_files(
130*7594170eSAndroid Build Coastguard Worker            ctx,
131*7594170eSAndroid Build Coastguard Worker            proto_rel_srcs,
132*7594170eSAndroid Build Coastguard Worker            type_dictionary,
133*7594170eSAndroid Build Coastguard Worker        )
134*7594170eSAndroid Build Coastguard Worker
135*7594170eSAndroid Build Coastguard Worker    tools = []
136*7594170eSAndroid Build Coastguard Worker    args = ctx.actions.args()
137*7594170eSAndroid Build Coastguard Worker    if plugin_executable:
138*7594170eSAndroid Build Coastguard Worker        tools.append(plugin_executable)
139*7594170eSAndroid Build Coastguard Worker        args.add("--plugin=protoc-gen-PLUGIN=" + plugin_executable.path)
140*7594170eSAndroid Build Coastguard Worker        args.add("--PLUGIN_out=" + ",".join(out_flags) + ":" + protoc_out_name)
141*7594170eSAndroid Build Coastguard Worker    else:
142*7594170eSAndroid Build Coastguard Worker        args.add("{}={}:{}".format(out_arg, ",".join(out_flags), protoc_out_name))
143*7594170eSAndroid Build Coastguard Worker
144*7594170eSAndroid Build Coastguard Worker    # the order matters so we add the source roots first
145*7594170eSAndroid Build Coastguard Worker    args.add_all(["-I" + p for p in sets.to_list(proto_source_root_list)])
146*7594170eSAndroid Build Coastguard Worker    args.add_all(["-I" + p for p in sets.to_list(transitive_proto_path_list)])
147*7594170eSAndroid Build Coastguard Worker    args.add_all(["-I{0}={1}".format(f.short_path, f.path) for t in transitive_proto_srcs_list for f in t.to_list()])
148*7594170eSAndroid Build Coastguard Worker
149*7594170eSAndroid Build Coastguard Worker    args.add_all([f.path for f in proto_srcs])
150*7594170eSAndroid Build Coastguard Worker
151*7594170eSAndroid Build Coastguard Worker    inputs = depset(
152*7594170eSAndroid Build Coastguard Worker        direct = proto_srcs,
153*7594170eSAndroid Build Coastguard Worker        transitive = transitive_proto_srcs_list,
154*7594170eSAndroid Build Coastguard Worker    )
155*7594170eSAndroid Build Coastguard Worker
156*7594170eSAndroid Build Coastguard Worker    outputs = []
157*7594170eSAndroid Build Coastguard Worker    for outs in out_files.values():
158*7594170eSAndroid Build Coastguard Worker        outputs.extend(outs)
159*7594170eSAndroid Build Coastguard Worker
160*7594170eSAndroid Build Coastguard Worker    ctx.actions.run(
161*7594170eSAndroid Build Coastguard Worker        inputs = inputs,
162*7594170eSAndroid Build Coastguard Worker        executable = protoc,
163*7594170eSAndroid Build Coastguard Worker        tools = tools,
164*7594170eSAndroid Build Coastguard Worker        outputs = outputs,
165*7594170eSAndroid Build Coastguard Worker        arguments = [args],
166*7594170eSAndroid Build Coastguard Worker        mnemonic = mnemonic,
167*7594170eSAndroid Build Coastguard Worker    )
168*7594170eSAndroid Build Coastguard Worker    return out_files
169*7594170eSAndroid Build Coastguard Worker
170*7594170eSAndroid Build Coastguard Workerproto_file_utils = struct(
171*7594170eSAndroid Build Coastguard Worker    generate_proto_action = _generate_proto_action,
172*7594170eSAndroid Build Coastguard Worker    generate_jar_proto_action = _generate_jar_proto_action,
173*7594170eSAndroid Build Coastguard Worker)
174