xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/idl.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
1*9e965d6fSRomain Jobredeaux# Copyright 2018 The Bazel Authors. All rights reserved.
2*9e965d6fSRomain Jobredeaux#
3*9e965d6fSRomain Jobredeaux# Licensed under the Apache License, Version 2.0 (the "License");
4*9e965d6fSRomain Jobredeaux# you may not use this file except in compliance with the License.
5*9e965d6fSRomain Jobredeaux# You may obtain a copy of the License at
6*9e965d6fSRomain Jobredeaux#
7*9e965d6fSRomain Jobredeaux#    http://www.apache.org/licenses/LICENSE-2.0
8*9e965d6fSRomain Jobredeaux#
9*9e965d6fSRomain Jobredeaux# Unless required by applicable law or agreed to in writing, software
10*9e965d6fSRomain Jobredeaux# distributed under the License is distributed on an "AS IS" BASIS,
11*9e965d6fSRomain Jobredeaux# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e965d6fSRomain Jobredeaux# See the License for the specific language governing permissions and
13*9e965d6fSRomain Jobredeaux# limitations under the License.
14*9e965d6fSRomain Jobredeaux
15*9e965d6fSRomain Jobredeaux"""Bazel Android IDL library for the Android rules."""
16*9e965d6fSRomain Jobredeaux
17*9e965d6fSRomain Jobredeauxload(":java.bzl", _java = "java")
18*9e965d6fSRomain Jobredeauxload(":path.bzl", _path = "path")
19*9e965d6fSRomain Jobredeauxload(":utils.bzl", "ANDROID_TOOLCHAIN_TYPE", _log = "log")
20*9e965d6fSRomain Jobredeaux
21*9e965d6fSRomain Jobredeaux_AIDL_TOOLCHAIN_MISSING_ERROR = (
22*9e965d6fSRomain Jobredeaux    "IDL sources provided without the Android IDL toolchain."
23*9e965d6fSRomain Jobredeaux)
24*9e965d6fSRomain Jobredeaux
25*9e965d6fSRomain Jobredeaux_AIDL_JAVA_ROOT_UNDETERMINABLE_ERROR = (
26*9e965d6fSRomain Jobredeaux    "Cannot determine java/javatests root for import %s."
27*9e965d6fSRomain Jobredeaux)
28*9e965d6fSRomain Jobredeaux
29*9e965d6fSRomain JobredeauxIDLContextInfo = provider(
30*9e965d6fSRomain Jobredeaux    doc = "Contains data from processing Android IDL.",
31*9e965d6fSRomain Jobredeaux    fields = dict(
32*9e965d6fSRomain Jobredeaux        idl_srcs = "List of IDL sources",
33*9e965d6fSRomain Jobredeaux        idl_import_root = "IDL import root",
34*9e965d6fSRomain Jobredeaux        idl_java_srcs = "List of IDL Java sources",
35*9e965d6fSRomain Jobredeaux        idl_deps =
36*9e965d6fSRomain Jobredeaux            "List of IDL targets required for Java compilation, Proguard, etc.",
37*9e965d6fSRomain Jobredeaux        providers = "The list of all providers to propagate.",
38*9e965d6fSRomain Jobredeaux    ),
39*9e965d6fSRomain Jobredeaux)
40*9e965d6fSRomain Jobredeaux
41*9e965d6fSRomain Jobredeauxdef _gen_java_from_idl(
42*9e965d6fSRomain Jobredeaux        ctx,
43*9e965d6fSRomain Jobredeaux        out_idl_java_src = None,
44*9e965d6fSRomain Jobredeaux        idl_src = None,
45*9e965d6fSRomain Jobredeaux        transitive_idl_import_roots = [],
46*9e965d6fSRomain Jobredeaux        transitive_idl_imports = [],
47*9e965d6fSRomain Jobredeaux        transitive_idl_preprocessed = [],
48*9e965d6fSRomain Jobredeaux        aidl = None,
49*9e965d6fSRomain Jobredeaux        aidl_lib = None,
50*9e965d6fSRomain Jobredeaux        aidl_framework = None,
51*9e965d6fSRomain Jobredeaux        uses_aosp_compiler = False,
52*9e965d6fSRomain Jobredeaux        idlopts = []):
53*9e965d6fSRomain Jobredeaux    args = ctx.actions.args()
54*9e965d6fSRomain Jobredeaux
55*9e965d6fSRomain Jobredeaux    # Note: at the moment (2022/11/07), the flags that the AOSP compiler accepts is a superset of
56*9e965d6fSRomain Jobredeaux    # the Google3 compiler, but that might not be true in the future.
57*9e965d6fSRomain Jobredeaux    if uses_aosp_compiler:
58*9e965d6fSRomain Jobredeaux        args.add("--use-aosp-compiler")
59*9e965d6fSRomain Jobredeaux
60*9e965d6fSRomain Jobredeaux    for opt in idlopts:
61*9e965d6fSRomain Jobredeaux        args.add(opt)
62*9e965d6fSRomain Jobredeaux
63*9e965d6fSRomain Jobredeaux    args.add("-b")  # fail on parcelable
64*9e965d6fSRomain Jobredeaux    args.add_all(transitive_idl_import_roots, format_each = "-I%s")
65*9e965d6fSRomain Jobredeaux    args.add(aidl_framework, format = "-p%s")
66*9e965d6fSRomain Jobredeaux    args.add_all(transitive_idl_preprocessed, format_each = "-p%s")
67*9e965d6fSRomain Jobredeaux    args.add(idl_src)
68*9e965d6fSRomain Jobredeaux    args.add(out_idl_java_src)
69*9e965d6fSRomain Jobredeaux
70*9e965d6fSRomain Jobredeaux    aidl_lib_files = [aidl_lib.files] if aidl_lib else []
71*9e965d6fSRomain Jobredeaux
72*9e965d6fSRomain Jobredeaux    ctx.actions.run(
73*9e965d6fSRomain Jobredeaux        executable = aidl,
74*9e965d6fSRomain Jobredeaux        arguments = [args],
75*9e965d6fSRomain Jobredeaux        inputs = depset(
76*9e965d6fSRomain Jobredeaux            [aidl_framework],
77*9e965d6fSRomain Jobredeaux            transitive = aidl_lib_files + [
78*9e965d6fSRomain Jobredeaux                transitive_idl_imports,
79*9e965d6fSRomain Jobredeaux                transitive_idl_preprocessed,
80*9e965d6fSRomain Jobredeaux            ],
81*9e965d6fSRomain Jobredeaux        ),
82*9e965d6fSRomain Jobredeaux        outputs = [out_idl_java_src],
83*9e965d6fSRomain Jobredeaux        mnemonic = "AndroidIDLGenerate",
84*9e965d6fSRomain Jobredeaux        progress_message = "Android IDL generation %s" % idl_src.path,
85*9e965d6fSRomain Jobredeaux        toolchain = ANDROID_TOOLCHAIN_TYPE,
86*9e965d6fSRomain Jobredeaux    )
87*9e965d6fSRomain Jobredeaux
88*9e965d6fSRomain Jobredeauxdef _get_idl_import_root_path(
89*9e965d6fSRomain Jobredeaux        package,
90*9e965d6fSRomain Jobredeaux        idl_import_root,
91*9e965d6fSRomain Jobredeaux        idl_file_root_path):
92*9e965d6fSRomain Jobredeaux    package_path = _path.relative(
93*9e965d6fSRomain Jobredeaux        idl_file_root_path,
94*9e965d6fSRomain Jobredeaux        package,
95*9e965d6fSRomain Jobredeaux    )
96*9e965d6fSRomain Jobredeaux    return _path.relative(
97*9e965d6fSRomain Jobredeaux        package_path,
98*9e965d6fSRomain Jobredeaux        idl_import_root,
99*9e965d6fSRomain Jobredeaux    )
100*9e965d6fSRomain Jobredeaux
101*9e965d6fSRomain Jobredeauxdef _collect_unique_idl_import_root_paths(
102*9e965d6fSRomain Jobredeaux        package,
103*9e965d6fSRomain Jobredeaux        idl_import_root,
104*9e965d6fSRomain Jobredeaux        idl_imports):
105*9e965d6fSRomain Jobredeaux    idl_import_roots = dict()
106*9e965d6fSRomain Jobredeaux    for idl_import in idl_imports:
107*9e965d6fSRomain Jobredeaux        idl_import_roots[_get_idl_import_root_path(
108*9e965d6fSRomain Jobredeaux            package,
109*9e965d6fSRomain Jobredeaux            idl_import_root,
110*9e965d6fSRomain Jobredeaux            idl_import.root.path,
111*9e965d6fSRomain Jobredeaux        )] = True
112*9e965d6fSRomain Jobredeaux    return sorted(idl_import_roots.keys())
113*9e965d6fSRomain Jobredeaux
114*9e965d6fSRomain Jobredeauxdef _collect_unique_java_roots(idl_imports):
115*9e965d6fSRomain Jobredeaux    idl_import_roots = dict()
116*9e965d6fSRomain Jobredeaux    for idl_import in idl_imports:
117*9e965d6fSRomain Jobredeaux        java_root = _java.root(idl_import.path)
118*9e965d6fSRomain Jobredeaux        if not java_root:
119*9e965d6fSRomain Jobredeaux            _log.error(_AIDL_JAVA_ROOT_UNDETERMINABLE_ERROR % idl_import.path)
120*9e965d6fSRomain Jobredeaux        idl_import_roots[java_root] = True
121*9e965d6fSRomain Jobredeaux    return sorted(idl_import_roots.keys())
122*9e965d6fSRomain Jobredeaux
123*9e965d6fSRomain Jobredeauxdef _determine_idl_import_roots(
124*9e965d6fSRomain Jobredeaux        package,
125*9e965d6fSRomain Jobredeaux        idl_import_root = None,
126*9e965d6fSRomain Jobredeaux        idl_imports = []):
127*9e965d6fSRomain Jobredeaux    if idl_import_root == None:
128*9e965d6fSRomain Jobredeaux        return _collect_unique_java_roots(idl_imports)
129*9e965d6fSRomain Jobredeaux    return _collect_unique_idl_import_root_paths(
130*9e965d6fSRomain Jobredeaux        package,
131*9e965d6fSRomain Jobredeaux        idl_import_root,
132*9e965d6fSRomain Jobredeaux        idl_imports,
133*9e965d6fSRomain Jobredeaux    )
134*9e965d6fSRomain Jobredeaux
135*9e965d6fSRomain Jobredeauxdef _process(
136*9e965d6fSRomain Jobredeaux        ctx,
137*9e965d6fSRomain Jobredeaux        idl_srcs = [],
138*9e965d6fSRomain Jobredeaux        idl_parcelables = [],
139*9e965d6fSRomain Jobredeaux        idl_import_root = None,
140*9e965d6fSRomain Jobredeaux        idl_preprocessed = [],
141*9e965d6fSRomain Jobredeaux        deps = [],
142*9e965d6fSRomain Jobredeaux        exports = [],
143*9e965d6fSRomain Jobredeaux        aidl = None,
144*9e965d6fSRomain Jobredeaux        aidl_lib = None,
145*9e965d6fSRomain Jobredeaux        aidl_framework = None,
146*9e965d6fSRomain Jobredeaux        uses_aosp_compiler = False,
147*9e965d6fSRomain Jobredeaux        idlopts = []):
148*9e965d6fSRomain Jobredeaux    """Processes Android IDL.
149*9e965d6fSRomain Jobredeaux
150*9e965d6fSRomain Jobredeaux    Args:
151*9e965d6fSRomain Jobredeaux      ctx: The context.
152*9e965d6fSRomain Jobredeaux      idl_srcs: sequence of Files. A list of the aidl source files to be
153*9e965d6fSRomain Jobredeaux        processed into Java source files and then compiled. Optional.
154*9e965d6fSRomain Jobredeaux      idl_parcelables: sequence of Files. A list of Android IDL definitions to
155*9e965d6fSRomain Jobredeaux        supply as imports. These files will be made available as imports for any
156*9e965d6fSRomain Jobredeaux        android_library target that depends on this library, directly or via its
157*9e965d6fSRomain Jobredeaux        transitive closure, but will not be translated to Java or compiled.
158*9e965d6fSRomain Jobredeaux
159*9e965d6fSRomain Jobredeaux        Only .aidl files that correspond directly to .java sources in this library
160*9e965d6fSRomain Jobredeaux        should be included (e.g. custom implementations of Parcelable), otherwise
161*9e965d6fSRomain Jobredeaux        idl_srcs should be used.
162*9e965d6fSRomain Jobredeaux
163*9e965d6fSRomain Jobredeaux        These files must be placed appropriately for the aidl compiler to find
164*9e965d6fSRomain Jobredeaux        them. See the description of idl_import_root for information about what
165*9e965d6fSRomain Jobredeaux        this means. Optional.
166*9e965d6fSRomain Jobredeaux      idl_import_root: string. Package-relative path to the root of the java
167*9e965d6fSRomain Jobredeaux        package tree containing idl sources included in this library. This path
168*9e965d6fSRomain Jobredeaux        will be used as the import root when processing idl sources that depend on
169*9e965d6fSRomain Jobredeaux        this library.
170*9e965d6fSRomain Jobredeaux
171*9e965d6fSRomain Jobredeaux        When idl_import_root is specified, both idl_parcelables and idl_srcs must
172*9e965d6fSRomain Jobredeaux        be at the path specified by the java package of the object they represent
173*9e965d6fSRomain Jobredeaux        under idl_import_root. When idl_import_root is not specified, both
174*9e965d6fSRomain Jobredeaux        idl_parcelables and idl_srcs must be at the path specified by their
175*9e965d6fSRomain Jobredeaux        package under a Java root. Optional.
176*9e965d6fSRomain Jobredeaux      idl_preprocessed: sequence of Files. A list of preprocessed Android IDL
177*9e965d6fSRomain Jobredeaux        definitions to supply as imports. These files will be made available as
178*9e965d6fSRomain Jobredeaux        imports for any android_library target that depends on this library,
179*9e965d6fSRomain Jobredeaux        directly or via its transitive closure, but will not be translated to
180*9e965d6fSRomain Jobredeaux        Java or compiled.
181*9e965d6fSRomain Jobredeaux
182*9e965d6fSRomain Jobredeaux        Only preprocessed .aidl files that correspond directly to .java sources
183*9e965d6fSRomain Jobredeaux        in this library should be included (e.g. custom implementations of
184*9e965d6fSRomain Jobredeaux        Parcelable), otherwise use idl_srcs for Android IDL definitions that
185*9e965d6fSRomain Jobredeaux        need to be translated to Java interfaces and use idl_parcelable for
186*9e965d6fSRomain Jobredeaux        non-preprcessed AIDL files. Optional.
187*9e965d6fSRomain Jobredeaux      deps: sequence of Targets. A list of dependencies. Optional.
188*9e965d6fSRomain Jobredeaux      exports: sequence of Targets. A list of exports. Optional.
189*9e965d6fSRomain Jobredeaux      aidl: Target. A target pointing to the aidl executable to be used for
190*9e965d6fSRomain Jobredeaux        Java code generation from *.idl source files. Optional, unless idl_srcs
191*9e965d6fSRomain Jobredeaux        are supplied.
192*9e965d6fSRomain Jobredeaux      aidl_lib: Target. A target pointing to the aidl_lib library required
193*9e965d6fSRomain Jobredeaux        during Java compilation when Java code is generated from idl sources.
194*9e965d6fSRomain Jobredeaux        Optional.
195*9e965d6fSRomain Jobredeaux      aidl_framework: Target. A target pointing to the aidl framework. Optional,
196*9e965d6fSRomain Jobredeaux        unless idl_srcs are supplied.
197*9e965d6fSRomain Jobredeaux      uses_aosp_compiler: boolean. If True, the upstream AOSP AIDL compiler is
198*9e965d6fSRomain Jobredeaux        used instead of the Google3-only AIDL compiler. This allows wider range
199*9e965d6fSRomain Jobredeaux        of AIDL language features including the structured parcelable, enum,
200*9e965d6fSRomain Jobredeaux        union, and many more. On the other hand, using this may cause noticeable
201*9e965d6fSRomain Jobredeaux        regression in terms of code size and performance as the compiler doesn't
202*9e965d6fSRomain Jobredeaux        implement several optimization techniques that the Google3 compiler has.
203*9e965d6fSRomain Jobredeaux      idlopts: list of string. Additional flags to add to the AOSP AIDL compiler
204*9e965d6fSRomain Jobredeaux        invocation.
205*9e965d6fSRomain Jobredeaux
206*9e965d6fSRomain Jobredeaux    Returns:
207*9e965d6fSRomain Jobredeaux      A IDLContextInfo provider.
208*9e965d6fSRomain Jobredeaux    """
209*9e965d6fSRomain Jobredeaux    if idl_srcs and not (aidl and aidl_framework):
210*9e965d6fSRomain Jobredeaux        _log.error(_AIDL_TOOLCHAIN_MISSING_ERROR)
211*9e965d6fSRomain Jobredeaux
212*9e965d6fSRomain Jobredeaux    transitive_idl_import_roots = []
213*9e965d6fSRomain Jobredeaux    transitive_idl_imports = []
214*9e965d6fSRomain Jobredeaux    transitive_idl_preprocessed = []
215*9e965d6fSRomain Jobredeaux    for dep in deps + exports:
216*9e965d6fSRomain Jobredeaux        transitive_idl_import_roots.append(dep.transitive_idl_import_roots)
217*9e965d6fSRomain Jobredeaux        transitive_idl_imports.append(dep.transitive_idl_imports)
218*9e965d6fSRomain Jobredeaux        transitive_idl_preprocessed.append(dep.transitive_idl_preprocessed)
219*9e965d6fSRomain Jobredeaux
220*9e965d6fSRomain Jobredeaux    idl_java_srcs = []
221*9e965d6fSRomain Jobredeaux    for idl_src in idl_srcs:
222*9e965d6fSRomain Jobredeaux        idl_java_src = ctx.actions.declare_file(
223*9e965d6fSRomain Jobredeaux            ctx.label.name + "_aidl/" + idl_src.path.replace(".aidl", ".java"),
224*9e965d6fSRomain Jobredeaux        )
225*9e965d6fSRomain Jobredeaux        idl_java_srcs.append(idl_java_src)
226*9e965d6fSRomain Jobredeaux        _gen_java_from_idl(
227*9e965d6fSRomain Jobredeaux            ctx,
228*9e965d6fSRomain Jobredeaux            out_idl_java_src = idl_java_src,
229*9e965d6fSRomain Jobredeaux            idl_src = idl_src,
230*9e965d6fSRomain Jobredeaux            transitive_idl_import_roots = depset(
231*9e965d6fSRomain Jobredeaux                _determine_idl_import_roots(
232*9e965d6fSRomain Jobredeaux                    ctx.label.package,
233*9e965d6fSRomain Jobredeaux                    idl_import_root,
234*9e965d6fSRomain Jobredeaux                    idl_parcelables + idl_srcs,
235*9e965d6fSRomain Jobredeaux                ),
236*9e965d6fSRomain Jobredeaux                transitive = transitive_idl_import_roots,
237*9e965d6fSRomain Jobredeaux                order = "preorder",
238*9e965d6fSRomain Jobredeaux            ),
239*9e965d6fSRomain Jobredeaux            transitive_idl_imports = depset(
240*9e965d6fSRomain Jobredeaux                idl_parcelables + idl_srcs,
241*9e965d6fSRomain Jobredeaux                transitive = transitive_idl_imports,
242*9e965d6fSRomain Jobredeaux                order = "preorder",
243*9e965d6fSRomain Jobredeaux            ),
244*9e965d6fSRomain Jobredeaux            transitive_idl_preprocessed = depset(
245*9e965d6fSRomain Jobredeaux                transitive = transitive_idl_preprocessed,
246*9e965d6fSRomain Jobredeaux            ),
247*9e965d6fSRomain Jobredeaux            aidl = aidl,
248*9e965d6fSRomain Jobredeaux            aidl_lib = aidl_lib,
249*9e965d6fSRomain Jobredeaux            aidl_framework = aidl_framework,
250*9e965d6fSRomain Jobredeaux            uses_aosp_compiler = uses_aosp_compiler,
251*9e965d6fSRomain Jobredeaux            idlopts = idlopts,
252*9e965d6fSRomain Jobredeaux        )
253*9e965d6fSRomain Jobredeaux
254*9e965d6fSRomain Jobredeaux    return IDLContextInfo(
255*9e965d6fSRomain Jobredeaux        idl_srcs = idl_srcs,
256*9e965d6fSRomain Jobredeaux        idl_import_root = idl_import_root,
257*9e965d6fSRomain Jobredeaux        idl_java_srcs = idl_java_srcs,
258*9e965d6fSRomain Jobredeaux        idl_deps = [aidl_lib] if (idl_java_srcs and aidl_lib) else [],
259*9e965d6fSRomain Jobredeaux        providers = [
260*9e965d6fSRomain Jobredeaux            # TODO(b/146216105): Make this a Starlark provider.
261*9e965d6fSRomain Jobredeaux            AndroidIdlInfo(
262*9e965d6fSRomain Jobredeaux                depset(
263*9e965d6fSRomain Jobredeaux                    _determine_idl_import_roots(
264*9e965d6fSRomain Jobredeaux                        ctx.label.package,
265*9e965d6fSRomain Jobredeaux                        idl_import_root,
266*9e965d6fSRomain Jobredeaux                        idl_parcelables + idl_srcs + idl_preprocessed,
267*9e965d6fSRomain Jobredeaux                    ),
268*9e965d6fSRomain Jobredeaux                    transitive = transitive_idl_import_roots,
269*9e965d6fSRomain Jobredeaux                    order = "preorder",
270*9e965d6fSRomain Jobredeaux                ),
271*9e965d6fSRomain Jobredeaux                depset(
272*9e965d6fSRomain Jobredeaux                    idl_parcelables + idl_srcs + idl_preprocessed,
273*9e965d6fSRomain Jobredeaux                    transitive = transitive_idl_imports,
274*9e965d6fSRomain Jobredeaux                    order = "preorder",
275*9e965d6fSRomain Jobredeaux                ),
276*9e965d6fSRomain Jobredeaux                depset(),  # TODO(b/146216105): Delete this field once in Starlark.
277*9e965d6fSRomain Jobredeaux                depset(idl_preprocessed, transitive = transitive_idl_preprocessed),
278*9e965d6fSRomain Jobredeaux            ),
279*9e965d6fSRomain Jobredeaux        ],
280*9e965d6fSRomain Jobredeaux    )
281*9e965d6fSRomain Jobredeaux
282*9e965d6fSRomain Jobredeauxidl = struct(
283*9e965d6fSRomain Jobredeaux    process = _process,
284*9e965d6fSRomain Jobredeaux)
285*9e965d6fSRomain Jobredeaux
286*9e965d6fSRomain Jobredeaux# Visible for testing.
287*9e965d6fSRomain Jobredeauxtesting = struct(
288*9e965d6fSRomain Jobredeaux    get_idl_import_root_path = _get_idl_import_root_path,
289*9e965d6fSRomain Jobredeaux)
290