xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/android_library/rule.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
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"""android_library rule."""
16
17load("//rules:acls.bzl", "acls")
18load(":attrs.bzl", _ATTRS = "ATTRS")
19load(":impl.bzl", _impl = "impl")
20load(
21    "//rules:attrs.bzl",
22    _attrs = "attrs",
23)
24
25_RULE_DOC = """
26#### Examples
27
28The following example shows how to use android libraries with resources.
29
30```starlark
31android_library(
32    name = "hellobazellib",
33    srcs = glob(["*.java"]),
34    resource_files = glob(["res/**/*"]),
35    manifest = "AndroidManifest.xml",
36    deps = [
37        "//java/bazel/hellobazellib/activities",
38        "//java/bazel/hellobazellib/common",
39        "//java/bazel/hellobazellib/math",
40        "//java/bazel/hellobazellib/service",
41    ],
42)
43```
44
45The following example shows how to set `idl_import_root`. Let `//java/bazel/helloandroid/BUILD` contain:
46
47```starlark
48android_library(
49    name = "parcelable",
50    srcs = ["MyParcelable.java"], # bazel.helloandroid.MyParcelable
51    # MyParcelable.aidl will be used as import for other .aidl
52    # files that depend on it, but will not be compiled.
53    idl_parcelables = ["MyParcelable.aidl"] # bazel.helloandroid.MyParcelable
54    # We don't need to specify idl_import_root since the aidl file
55    # which declares bazel.helloandroid.MyParcelable
56    # is present at java/bazel/helloandroid/MyParcelable.aidl
57    # underneath a java root (java/).
58)
59
60android_library(
61    name = "foreign_parcelable",
62    srcs = ["src/android/helloandroid/OtherParcelable.java"], # android.helloandroid.OtherParcelable
63    idl_parcelables = [
64        "src/android/helloandroid/OtherParcelable.aidl" # android.helloandroid.OtherParcelable
65    ],
66    # We need to specify idl_import_root because the aidl file which
67    # declares android.helloandroid.OtherParcelable is not positioned
68    # at android/helloandroid/OtherParcelable.aidl under a normal java root.
69    # Setting idl_import_root to "src" in //java/bazel/helloandroid
70    # adds java/bazel/helloandroid/src to the list of roots
71    # the aidl compiler will search for imported types.
72    idl_import_root = "src",
73)
74
75# Here, OtherInterface.aidl has an "import android.helloandroid.CallbackInterface;" statement.
76android_library(
77    name = "foreign_interface",
78    idl_srcs = [
79        "src/android/helloandroid/OtherInterface.aidl" # android.helloandroid.OtherInterface
80        "src/android/helloandroid/CallbackInterface.aidl" # android.helloandroid.CallbackInterface
81    ],
82    # As above, idl_srcs which are not correctly positioned under a java root
83    # must have idl_import_root set. Otherwise, OtherInterface (or any other
84    # interface in a library which depends on this one) will not be able
85    # to find CallbackInterface when it is imported.
86    idl_import_root = "src",
87)
88
89# MyParcelable.aidl is imported by MyInterface.aidl, so the generated
90# MyInterface.java requires MyParcelable.class at compile time.
91# Depending on :parcelable ensures that aidl compilation of MyInterface.aidl
92# specifies the correct import roots and can access MyParcelable.aidl, and
93# makes MyParcelable.class available to Java compilation of MyInterface.java
94# as usual.
95android_library(
96    name = "idl",
97    idl_srcs = ["MyInterface.aidl"],
98    deps = [":parcelable"],
99)
100
101# Here, ServiceParcelable uses and thus depends on ParcelableService,
102# when it's compiled, but ParcelableService also uses ServiceParcelable,
103# which creates a circular dependency.
104# As a result, these files must be compiled together, in the same android_library.
105android_library(
106    name = "circular_dependencies",
107    srcs = ["ServiceParcelable.java"],
108    idl_srcs = ["ParcelableService.aidl"],
109    idl_parcelables = ["ServiceParcelable.aidl"],
110)
111```
112"""
113
114def _outputs(name, _package_name, _defined_local_resources):
115    outputs = dict(
116        lib_jar = "lib%{name}.jar",
117        lib_src_jar = "lib%{name}-src.jar",
118        aar = "%{name}.aar",
119    )
120
121    if _defined_local_resources:
122        # TODO(b/177261846): resource-related predeclared outputs need to be re-pointed at the
123        # corresponding artifacts in the Starlark pipeline.
124        label = "//" + _package_name + ":" + name
125        if acls.in_android_library_starlark_resource_outputs_rollout(label):
126            path_prefix = "_migrated/"
127        else:
128            path_prefix = ""
129        outputs.update(
130            dict(
131                resources_src_jar = path_prefix + "%{name}.srcjar",
132                resources_txt = path_prefix + "%{name}_symbols/R.txt",
133                resources_jar = path_prefix + "%{name}_resources.jar",
134            ),
135        )
136
137    return outputs
138
139def make_rule(
140        attrs = _ATTRS,
141        implementation = _impl,
142        outputs = _outputs,
143        additional_toolchains = [],
144        additional_providers = []):
145    """Makes the rule.
146
147    Args:
148      attrs: A dict. The attributes for the rule.
149      implementation: A function. The rule's implementation method.
150      outputs: A dict, function, or None. The rule's outputs.
151      additional_toolchains: A list. Additional toolchains passed to pass to rule(toolchains).
152      additional_providers: A list. Additional providers passed to pass to rule(providers).
153
154    Returns:
155      A rule.
156    """
157    return rule(
158        attrs = attrs,
159        fragments = [
160            "android",
161            "java",
162        ],
163        implementation = implementation,
164        doc = _RULE_DOC,
165        provides = [
166            AndroidCcLinkParamsInfo,
167            AndroidIdeInfo,
168            AndroidIdlInfo,
169            AndroidLibraryResourceClassJarProvider,
170            AndroidNativeLibsInfo,
171            JavaInfo,
172        ] + additional_providers,
173        outputs = outputs,
174        toolchains = [
175            "//toolchains/android:toolchain_type",
176            "//toolchains/android_sdk:toolchain_type",
177            "@bazel_tools//tools/jdk:toolchain_type",
178        ] + additional_toolchains,
179        _skylark_testable = True,
180    )
181
182android_library = make_rule()
183
184def _is_defined(name, attrs):
185    return name in attrs and attrs[name] != None
186
187def attrs_metadata(attrs):
188    """Adds additional metadata for specific android_library attrs.
189
190    Bazel native rules have additional capabilities when inspecting attrs that
191    are not available in Starlark. For example, native rules are able to
192    determine if an attribute was set by a user and make decisions based on this
193    knowledge - sometimes the behavior may differ if the user specifies the
194    default value of the attribute. As such the Starlark android_library uses
195    this shim to provide similar capabilities.
196
197    Args:
198      attrs: The attributes passed to the android_library rule.
199
200    Returns:
201      A dictionary containing attr values with additional metadata.
202    """
203
204    # Required for the outputs.
205    attrs["$defined_local_resources"] = bool(
206        attrs.get("assets") or
207        attrs.get("assets_dir") or
208        attrs.get("assets_dir") == "" or
209        attrs.get("export_manifest") or
210        attrs.get("manifest") or
211        attrs.get("resource_files"),
212    )
213
214    # TODO(b/116691720): Remove normalization when bug is fixed.
215    if _is_defined("exports_manifest", attrs):
216        attrs["exports_manifest"] = _attrs.tristate.normalize(
217            attrs.get("exports_manifest"),
218        )
219
220    # TODO(b/127517031): Remove these entries once fixed.
221    attrs["$defined_assets"] = _is_defined("assets", attrs)
222    attrs["$defined_assets_dir"] = _is_defined("assets_dir", attrs)
223    attrs["$defined_idl_import_root"] = _is_defined("idl_import_root", attrs)
224    attrs["$defined_idl_parcelables"] = _is_defined("idl_parcelables", attrs)
225    attrs["$defined_idl_srcs"] = _is_defined("idl_srcs", attrs)
226
227    # Required for ACLs check in _outputs(), since the callback can't access
228    # the native module.
229    attrs["$package_name"] = native.package_name()
230
231    return attrs
232
233def android_library_macro(**attrs):
234    """Bazel android_library rule.
235
236    https://docs.bazel.build/versions/master/be/android.html#android_library
237
238    Args:
239      **attrs: Rule attributes
240    """
241    android_library(**attrs_metadata(attrs))
242