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