xref: /aosp_15_r20/external/tensorflow/third_party/systemlibs/grpc.bazel.protobuf.bzl (revision b6fb3261f9314811a0f4371741dbb8839866f948)
1*b6fb3261SAndroid Build Coastguard Worker"""Utility functions for generating protobuf code."""
2*b6fb3261SAndroid Build Coastguard Worker
3*b6fb3261SAndroid Build Coastguard Worker_PROTO_EXTENSION = ".proto"
4*b6fb3261SAndroid Build Coastguard Worker_VIRTUAL_IMPORTS = "/_virtual_imports/"
5*b6fb3261SAndroid Build Coastguard Worker
6*b6fb3261SAndroid Build Coastguard Workerdef well_known_proto_libs():
7*b6fb3261SAndroid Build Coastguard Worker    return [
8*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:any_proto",
9*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:api_proto",
10*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:compiler_plugin_proto",
11*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:descriptor_proto",
12*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:duration_proto",
13*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:empty_proto",
14*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:field_mask_proto",
15*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:source_context_proto",
16*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:struct_proto",
17*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:timestamp_proto",
18*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:type_proto",
19*b6fb3261SAndroid Build Coastguard Worker        "@com_google_protobuf//:wrappers_proto",
20*b6fb3261SAndroid Build Coastguard Worker    ]
21*b6fb3261SAndroid Build Coastguard Worker
22*b6fb3261SAndroid Build Coastguard Workerdef get_proto_root(workspace_root):
23*b6fb3261SAndroid Build Coastguard Worker    """Gets the root protobuf directory.
24*b6fb3261SAndroid Build Coastguard Worker
25*b6fb3261SAndroid Build Coastguard Worker    Args:
26*b6fb3261SAndroid Build Coastguard Worker      workspace_root: context.label.workspace_root
27*b6fb3261SAndroid Build Coastguard Worker
28*b6fb3261SAndroid Build Coastguard Worker    Returns:
29*b6fb3261SAndroid Build Coastguard Worker      The directory relative to which generated include paths should be.
30*b6fb3261SAndroid Build Coastguard Worker    """
31*b6fb3261SAndroid Build Coastguard Worker    if workspace_root:
32*b6fb3261SAndroid Build Coastguard Worker        return "/{}".format(workspace_root)
33*b6fb3261SAndroid Build Coastguard Worker    else:
34*b6fb3261SAndroid Build Coastguard Worker        return ""
35*b6fb3261SAndroid Build Coastguard Worker
36*b6fb3261SAndroid Build Coastguard Workerdef _strip_proto_extension(proto_filename):
37*b6fb3261SAndroid Build Coastguard Worker    if not proto_filename.endswith(_PROTO_EXTENSION):
38*b6fb3261SAndroid Build Coastguard Worker        fail('"{}" does not end with "{}"'.format(
39*b6fb3261SAndroid Build Coastguard Worker            proto_filename,
40*b6fb3261SAndroid Build Coastguard Worker            _PROTO_EXTENSION,
41*b6fb3261SAndroid Build Coastguard Worker        ))
42*b6fb3261SAndroid Build Coastguard Worker    return proto_filename[:-len(_PROTO_EXTENSION)]
43*b6fb3261SAndroid Build Coastguard Worker
44*b6fb3261SAndroid Build Coastguard Workerdef proto_path_to_generated_filename(proto_path, fmt_str):
45*b6fb3261SAndroid Build Coastguard Worker    """Calculates the name of a generated file for a protobuf path.
46*b6fb3261SAndroid Build Coastguard Worker
47*b6fb3261SAndroid Build Coastguard Worker    For example, "examples/protos/helloworld.proto" might map to
48*b6fb3261SAndroid Build Coastguard Worker      "helloworld.pb.h".
49*b6fb3261SAndroid Build Coastguard Worker
50*b6fb3261SAndroid Build Coastguard Worker    Args:
51*b6fb3261SAndroid Build Coastguard Worker      proto_path: The path to the .proto file.
52*b6fb3261SAndroid Build Coastguard Worker      fmt_str: A format string used to calculate the generated filename. For
53*b6fb3261SAndroid Build Coastguard Worker        example, "{}.pb.h" might be used to calculate a C++ header filename.
54*b6fb3261SAndroid Build Coastguard Worker
55*b6fb3261SAndroid Build Coastguard Worker    Returns:
56*b6fb3261SAndroid Build Coastguard Worker      The generated filename.
57*b6fb3261SAndroid Build Coastguard Worker    """
58*b6fb3261SAndroid Build Coastguard Worker    return fmt_str.format(_strip_proto_extension(proto_path))
59*b6fb3261SAndroid Build Coastguard Worker
60*b6fb3261SAndroid Build Coastguard Workerdef get_include_directory(source_file):
61*b6fb3261SAndroid Build Coastguard Worker    """Returns the include directory path for the source_file.
62*b6fb3261SAndroid Build Coastguard Worker
63*b6fb3261SAndroid Build Coastguard Worker    I.e. all of the include statements within the given source_file
64*b6fb3261SAndroid Build Coastguard Worker    are calculated relative to the directory returned by this method.
65*b6fb3261SAndroid Build Coastguard Worker
66*b6fb3261SAndroid Build Coastguard Worker    The returned directory path can be used as the "--proto_path=" argument
67*b6fb3261SAndroid Build Coastguard Worker    value.
68*b6fb3261SAndroid Build Coastguard Worker
69*b6fb3261SAndroid Build Coastguard Worker    Args:
70*b6fb3261SAndroid Build Coastguard Worker      source_file: A proto file.
71*b6fb3261SAndroid Build Coastguard Worker
72*b6fb3261SAndroid Build Coastguard Worker    Returns:
73*b6fb3261SAndroid Build Coastguard Worker      The include directory path for the source_file.
74*b6fb3261SAndroid Build Coastguard Worker    """
75*b6fb3261SAndroid Build Coastguard Worker    directory = source_file.path
76*b6fb3261SAndroid Build Coastguard Worker    prefix_len = 0
77*b6fb3261SAndroid Build Coastguard Worker
78*b6fb3261SAndroid Build Coastguard Worker    if is_in_virtual_imports(source_file):
79*b6fb3261SAndroid Build Coastguard Worker        root, relative = source_file.path.split(_VIRTUAL_IMPORTS, 2)
80*b6fb3261SAndroid Build Coastguard Worker        result = root + _VIRTUAL_IMPORTS + relative.split("/", 1)[0]
81*b6fb3261SAndroid Build Coastguard Worker        return result
82*b6fb3261SAndroid Build Coastguard Worker
83*b6fb3261SAndroid Build Coastguard Worker    if not source_file.is_source and directory.startswith(source_file.root.path):
84*b6fb3261SAndroid Build Coastguard Worker        prefix_len = len(source_file.root.path) + 1
85*b6fb3261SAndroid Build Coastguard Worker
86*b6fb3261SAndroid Build Coastguard Worker    if directory.startswith("external", prefix_len):
87*b6fb3261SAndroid Build Coastguard Worker        external_separator = directory.find("/", prefix_len)
88*b6fb3261SAndroid Build Coastguard Worker        repository_separator = directory.find("/", external_separator + 1)
89*b6fb3261SAndroid Build Coastguard Worker        return directory[:repository_separator]
90*b6fb3261SAndroid Build Coastguard Worker    else:
91*b6fb3261SAndroid Build Coastguard Worker        return source_file.root.path if source_file.root.path else "."
92*b6fb3261SAndroid Build Coastguard Worker
93*b6fb3261SAndroid Build Coastguard Workerdef get_plugin_args(
94*b6fb3261SAndroid Build Coastguard Worker        plugin,
95*b6fb3261SAndroid Build Coastguard Worker        flags,
96*b6fb3261SAndroid Build Coastguard Worker        dir_out,
97*b6fb3261SAndroid Build Coastguard Worker        generate_mocks,
98*b6fb3261SAndroid Build Coastguard Worker        plugin_name = "PLUGIN"):
99*b6fb3261SAndroid Build Coastguard Worker    """Returns arguments configuring protoc to use a plugin for a language.
100*b6fb3261SAndroid Build Coastguard Worker
101*b6fb3261SAndroid Build Coastguard Worker    Args:
102*b6fb3261SAndroid Build Coastguard Worker      plugin: An executable file to run as the protoc plugin.
103*b6fb3261SAndroid Build Coastguard Worker      flags: The plugin flags to be passed to protoc.
104*b6fb3261SAndroid Build Coastguard Worker      dir_out: The output directory for the plugin.
105*b6fb3261SAndroid Build Coastguard Worker      generate_mocks: A bool indicating whether to generate mocks.
106*b6fb3261SAndroid Build Coastguard Worker      plugin_name: A name of the plugin, it is required to be unique when there
107*b6fb3261SAndroid Build Coastguard Worker      are more than one plugin used in a single protoc command.
108*b6fb3261SAndroid Build Coastguard Worker    Returns:
109*b6fb3261SAndroid Build Coastguard Worker      A list of protoc arguments configuring the plugin.
110*b6fb3261SAndroid Build Coastguard Worker    """
111*b6fb3261SAndroid Build Coastguard Worker    augmented_flags = list(flags)
112*b6fb3261SAndroid Build Coastguard Worker    if generate_mocks:
113*b6fb3261SAndroid Build Coastguard Worker        augmented_flags.append("generate_mock_code=true")
114*b6fb3261SAndroid Build Coastguard Worker
115*b6fb3261SAndroid Build Coastguard Worker    augmented_dir_out = dir_out
116*b6fb3261SAndroid Build Coastguard Worker    if augmented_flags:
117*b6fb3261SAndroid Build Coastguard Worker        augmented_dir_out = ",".join(augmented_flags) + ":" + dir_out
118*b6fb3261SAndroid Build Coastguard Worker
119*b6fb3261SAndroid Build Coastguard Worker    return [
120*b6fb3261SAndroid Build Coastguard Worker        "--plugin=protoc-gen-{plugin_name}={plugin_path}".format(
121*b6fb3261SAndroid Build Coastguard Worker            plugin_name = plugin_name,
122*b6fb3261SAndroid Build Coastguard Worker            plugin_path = plugin.path,
123*b6fb3261SAndroid Build Coastguard Worker        ),
124*b6fb3261SAndroid Build Coastguard Worker        "--{plugin_name}_out={dir_out}".format(
125*b6fb3261SAndroid Build Coastguard Worker            plugin_name = plugin_name,
126*b6fb3261SAndroid Build Coastguard Worker            dir_out = augmented_dir_out,
127*b6fb3261SAndroid Build Coastguard Worker        ),
128*b6fb3261SAndroid Build Coastguard Worker    ]
129*b6fb3261SAndroid Build Coastguard Worker
130*b6fb3261SAndroid Build Coastguard Workerdef _get_staged_proto_file(context, source_file):
131*b6fb3261SAndroid Build Coastguard Worker    if (source_file.dirname == context.label.package or
132*b6fb3261SAndroid Build Coastguard Worker        is_in_virtual_imports(source_file)):
133*b6fb3261SAndroid Build Coastguard Worker        return source_file
134*b6fb3261SAndroid Build Coastguard Worker    else:
135*b6fb3261SAndroid Build Coastguard Worker        copied_proto = context.actions.declare_file(source_file.basename)
136*b6fb3261SAndroid Build Coastguard Worker        context.actions.run_shell(
137*b6fb3261SAndroid Build Coastguard Worker            inputs = [source_file],
138*b6fb3261SAndroid Build Coastguard Worker            outputs = [copied_proto],
139*b6fb3261SAndroid Build Coastguard Worker            command = "cp {} {}".format(source_file.path, copied_proto.path),
140*b6fb3261SAndroid Build Coastguard Worker            mnemonic = "CopySourceProto",
141*b6fb3261SAndroid Build Coastguard Worker        )
142*b6fb3261SAndroid Build Coastguard Worker        return copied_proto
143*b6fb3261SAndroid Build Coastguard Worker
144*b6fb3261SAndroid Build Coastguard Workerdef protos_from_context(context):
145*b6fb3261SAndroid Build Coastguard Worker    """Copies proto files to the appropriate location.
146*b6fb3261SAndroid Build Coastguard Worker
147*b6fb3261SAndroid Build Coastguard Worker    Args:
148*b6fb3261SAndroid Build Coastguard Worker      context: The ctx object for the rule.
149*b6fb3261SAndroid Build Coastguard Worker
150*b6fb3261SAndroid Build Coastguard Worker    Returns:
151*b6fb3261SAndroid Build Coastguard Worker      A list of the protos.
152*b6fb3261SAndroid Build Coastguard Worker    """
153*b6fb3261SAndroid Build Coastguard Worker    protos = []
154*b6fb3261SAndroid Build Coastguard Worker    for src in context.attr.deps:
155*b6fb3261SAndroid Build Coastguard Worker        for file in src[ProtoInfo].direct_sources:
156*b6fb3261SAndroid Build Coastguard Worker            protos.append(_get_staged_proto_file(context, file))
157*b6fb3261SAndroid Build Coastguard Worker    return protos
158*b6fb3261SAndroid Build Coastguard Worker
159*b6fb3261SAndroid Build Coastguard Workerdef includes_from_deps(deps):
160*b6fb3261SAndroid Build Coastguard Worker    """Get includes from rule dependencies."""
161*b6fb3261SAndroid Build Coastguard Worker    return [
162*b6fb3261SAndroid Build Coastguard Worker        file
163*b6fb3261SAndroid Build Coastguard Worker        for src in deps
164*b6fb3261SAndroid Build Coastguard Worker        for file in src[ProtoInfo].transitive_imports.to_list()
165*b6fb3261SAndroid Build Coastguard Worker    ]
166*b6fb3261SAndroid Build Coastguard Worker
167*b6fb3261SAndroid Build Coastguard Workerdef get_proto_arguments(protos, genfiles_dir_path):
168*b6fb3261SAndroid Build Coastguard Worker    """Get the protoc arguments specifying which protos to compile."""
169*b6fb3261SAndroid Build Coastguard Worker    arguments = []
170*b6fb3261SAndroid Build Coastguard Worker    for proto in protos:
171*b6fb3261SAndroid Build Coastguard Worker        strip_prefix_len = 0
172*b6fb3261SAndroid Build Coastguard Worker        if is_in_virtual_imports(proto):
173*b6fb3261SAndroid Build Coastguard Worker            incl_directory = get_include_directory(proto)
174*b6fb3261SAndroid Build Coastguard Worker            if proto.path.startswith(incl_directory):
175*b6fb3261SAndroid Build Coastguard Worker                strip_prefix_len = len(incl_directory) + 1
176*b6fb3261SAndroid Build Coastguard Worker        elif proto.path.startswith(genfiles_dir_path):
177*b6fb3261SAndroid Build Coastguard Worker            strip_prefix_len = len(genfiles_dir_path) + 1
178*b6fb3261SAndroid Build Coastguard Worker
179*b6fb3261SAndroid Build Coastguard Worker        arguments.append(proto.path[strip_prefix_len:])
180*b6fb3261SAndroid Build Coastguard Worker
181*b6fb3261SAndroid Build Coastguard Worker    return arguments
182*b6fb3261SAndroid Build Coastguard Worker
183*b6fb3261SAndroid Build Coastguard Workerdef declare_out_files(protos, context, generated_file_format):
184*b6fb3261SAndroid Build Coastguard Worker    """Declares and returns the files to be generated."""
185*b6fb3261SAndroid Build Coastguard Worker
186*b6fb3261SAndroid Build Coastguard Worker    out_file_paths = []
187*b6fb3261SAndroid Build Coastguard Worker    for proto in protos:
188*b6fb3261SAndroid Build Coastguard Worker        if not is_in_virtual_imports(proto):
189*b6fb3261SAndroid Build Coastguard Worker            out_file_paths.append(proto.basename)
190*b6fb3261SAndroid Build Coastguard Worker        else:
191*b6fb3261SAndroid Build Coastguard Worker            path = proto.path[proto.path.index(_VIRTUAL_IMPORTS) + 1:]
192*b6fb3261SAndroid Build Coastguard Worker            out_file_paths.append(path)
193*b6fb3261SAndroid Build Coastguard Worker
194*b6fb3261SAndroid Build Coastguard Worker    return [
195*b6fb3261SAndroid Build Coastguard Worker        context.actions.declare_file(
196*b6fb3261SAndroid Build Coastguard Worker            proto_path_to_generated_filename(
197*b6fb3261SAndroid Build Coastguard Worker                out_file_path,
198*b6fb3261SAndroid Build Coastguard Worker                generated_file_format,
199*b6fb3261SAndroid Build Coastguard Worker            ),
200*b6fb3261SAndroid Build Coastguard Worker        )
201*b6fb3261SAndroid Build Coastguard Worker        for out_file_path in out_file_paths
202*b6fb3261SAndroid Build Coastguard Worker    ]
203*b6fb3261SAndroid Build Coastguard Worker
204*b6fb3261SAndroid Build Coastguard Workerdef get_out_dir(protos, context):
205*b6fb3261SAndroid Build Coastguard Worker    """ Returns the calculated value for --<lang>_out= protoc argument based on
206*b6fb3261SAndroid Build Coastguard Worker    the input source proto files and current context.
207*b6fb3261SAndroid Build Coastguard Worker
208*b6fb3261SAndroid Build Coastguard Worker    Args:
209*b6fb3261SAndroid Build Coastguard Worker        protos: A list of protos to be used as source files in protoc command
210*b6fb3261SAndroid Build Coastguard Worker        context: A ctx object for the rule.
211*b6fb3261SAndroid Build Coastguard Worker    Returns:
212*b6fb3261SAndroid Build Coastguard Worker        The value of --<lang>_out= argument.
213*b6fb3261SAndroid Build Coastguard Worker    """
214*b6fb3261SAndroid Build Coastguard Worker    at_least_one_virtual = 0
215*b6fb3261SAndroid Build Coastguard Worker    for proto in protos:
216*b6fb3261SAndroid Build Coastguard Worker        if is_in_virtual_imports(proto):
217*b6fb3261SAndroid Build Coastguard Worker            at_least_one_virtual = True
218*b6fb3261SAndroid Build Coastguard Worker        elif at_least_one_virtual:
219*b6fb3261SAndroid Build Coastguard Worker            fail("Proto sources must be either all virtual imports or all real")
220*b6fb3261SAndroid Build Coastguard Worker    if at_least_one_virtual:
221*b6fb3261SAndroid Build Coastguard Worker        out_dir = get_include_directory(protos[0])
222*b6fb3261SAndroid Build Coastguard Worker        ws_root = protos[0].owner.workspace_root
223*b6fb3261SAndroid Build Coastguard Worker        if ws_root and out_dir.find(ws_root) >= 0:
224*b6fb3261SAndroid Build Coastguard Worker            out_dir = "".join(out_dir.rsplit(ws_root, 1))
225*b6fb3261SAndroid Build Coastguard Worker        return struct(
226*b6fb3261SAndroid Build Coastguard Worker            path = out_dir,
227*b6fb3261SAndroid Build Coastguard Worker            import_path = out_dir[out_dir.find(_VIRTUAL_IMPORTS) + 1:],
228*b6fb3261SAndroid Build Coastguard Worker        )
229*b6fb3261SAndroid Build Coastguard Worker    return struct(path = context.genfiles_dir.path, import_path = None)
230*b6fb3261SAndroid Build Coastguard Worker
231*b6fb3261SAndroid Build Coastguard Workerdef is_in_virtual_imports(source_file, virtual_folder = _VIRTUAL_IMPORTS):
232*b6fb3261SAndroid Build Coastguard Worker    """Determines if source_file is virtual (is placed in _virtual_imports
233*b6fb3261SAndroid Build Coastguard Worker    subdirectory). The output of all proto_library targets which use
234*b6fb3261SAndroid Build Coastguard Worker    import_prefix  and/or strip_import_prefix arguments is placed under
235*b6fb3261SAndroid Build Coastguard Worker    _virtual_imports directory.
236*b6fb3261SAndroid Build Coastguard Worker
237*b6fb3261SAndroid Build Coastguard Worker    Args:
238*b6fb3261SAndroid Build Coastguard Worker        source_file: A proto file.
239*b6fb3261SAndroid Build Coastguard Worker        virtual_folder: The virtual folder name (is set to "_virtual_imports"
240*b6fb3261SAndroid Build Coastguard Worker            by default)
241*b6fb3261SAndroid Build Coastguard Worker    Returns:
242*b6fb3261SAndroid Build Coastguard Worker        True if source_file is located under _virtual_imports, False otherwise.
243*b6fb3261SAndroid Build Coastguard Worker    """
244*b6fb3261SAndroid Build Coastguard Worker    return not source_file.is_source and virtual_folder in source_file.path
245