xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/aapt.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
1# Copyright 2019 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 AAPT Commands."""
16
17load(
18    "//rules:utils.bzl",
19    "ANDROID_TOOLCHAIN_TYPE",
20)
21
22def _link(
23        ctx,
24        out_r_java,
25        out_resource_apk,
26        manifest = None,
27        java_package = None,
28        assets = depset([]),
29        assets_dirs = [],
30        compiled_resources = depset([]),
31        config_filters = [],
32        make_r_java_ids_non_final = False,
33        compatible_with_resource_shrinking = True,
34        enable_debug = False,
35        enable_static_lib = False,
36        android_jar = None,
37        aapt = None):
38    """Links compiled Android Resources with AAPT.
39
40    Args:
41      ctx: The context.
42      out_r_java: A File. The R.java outputted by linking resources.
43      out_resource_apk: A File. The Resource APK outputted by linking resources.
44      manifest: A File. The AndroidManifest.xml.
45      java_package: A string. The Java package for the generated R.java.
46      assets: A list of Files. The list of assets from the transitive closure of
47        the project.
48      assets_dirs: A list of strings. The list of asset directories in the
49        transitive closure of the project.
50      compiled_resources: List of intermediate compiled android resource files.
51      config_filters: A list of Strings. The configuration filters.
52      make_r_java_ids_non_final: A bool. Makes the R.java produced from linkin
53        have non-final values.
54      compatible_with_resource_shrinking: A bool. When enabled produces the
55        output in proto format which is a requirement for resource shrinking.
56      enable_debug: A bool. Enable debugging
57      enable_static_lib: A bool. Enable static lib.
58      android_jar: A File. The Android Jar.
59      aapt: A FilesToRunProvider. The AAPT executable.
60    """
61
62    # Output the list of resources in reverse topological order.
63    resources_param = ctx.actions.declare_file(
64        out_r_java.basename + ".params",
65        sibling = out_r_java,
66    )
67    args = ctx.actions.args()
68    args.use_param_file("%s", use_always = True)
69    args.set_param_file_format("multiline")
70    args.add_all(compiled_resources, expand_directories = True)
71    ctx.actions.run_shell(
72        command = """
73# Reverses the set of inputs that have been topologically ordered to utilize the
74# overlay/override semantics of aapt2.
75set -e
76
77echo $(tac $1) > $2
78""",
79        arguments = [args, resources_param.path],
80        outputs = [resources_param],
81        inputs = compiled_resources,
82    )
83
84    args = ctx.actions.args()
85    args.add("link")
86    if enable_static_lib:
87        args.add("--static-lib")
88    args.add("--no-version-vectors")
89    args.add("--no-static-lib-packages")  # Turn off namespaced resource
90
91    args.add("--manifest", manifest)
92    args.add("--auto-add-overlay")  # Enables resource redefinition and merging
93    args.add("--override-styles-instead-of-overlaying")  # mimic AAPT1.
94    if make_r_java_ids_non_final:
95        args.add("--non-final-ids")
96    if compatible_with_resource_shrinking:
97        args.add("--proto-format")
98    if enable_debug:
99        args.add("--debug-mode")
100    args.add("--custom-package", java_package)
101    args.add("-I", android_jar)
102    args.add_all(assets_dirs, before_each = "-A")
103    args.add("-R", resources_param, format = "@%s")
104    args.add("-0", ".apk")
105    args.add_joined("-c", config_filters, join_with = ",", omit_if_empty = True)
106    args.add("--java", out_r_java.path.rpartition(java_package.replace(".", "/"))[0])
107    args.add("-o", out_resource_apk)
108
109    ctx.actions.run(
110        executable = aapt,
111        arguments = [args],
112        inputs = depset(
113            [android_jar, resources_param] +
114            ([manifest] if manifest else []),
115            transitive = [assets, compiled_resources],
116        ),
117        outputs = [out_resource_apk, out_r_java],
118        mnemonic = "LinkAndroidResources",
119        progress_message = "ResV3 Linking Android Resources to %s" % out_resource_apk.short_path,
120        toolchain = ANDROID_TOOLCHAIN_TYPE,
121    )
122
123def _compile(
124        ctx,
125        out_dir,
126        resource_files,
127        aapt):
128    """Compile and store resources in a single archive.
129
130    Args:
131      ctx: The context.
132      out_dir: File. A file to store the output.
133      resource_files: A list of Files. The list of resource files or directories
134        to process.
135      aapt: AAPT. Tool for compiling resources.
136    """
137    if not out_dir:
138        fail("No output directory specified.")
139    if not out_dir.is_directory:
140        fail("Output directory is not a directory artifact.")
141    if not resource_files:
142        fail("No resource files given.")
143
144    # Retrieves the list of files at runtime when a directory is passed.
145    args = ctx.actions.args()
146    args.add_all(resource_files, expand_directories = True)
147
148    ctx.actions.run_shell(
149        command = """
150set -e
151
152AAPT=%s
153OUT_DIR=%s
154RESOURCE_FILES=$@
155
156i=0
157declare -A out_dir_map
158for f in ${RESOURCE_FILES}; do
159  res_dir="$(dirname $(dirname ${f}))"
160  if [ -z "${out_dir_map[${res_dir}]}" ]; then
161      out_dir="${OUT_DIR}/$((++i))"
162      mkdir -p ${out_dir}
163      out_dir_map[${res_dir}]="${out_dir}"
164  fi
165  # Outputs from multiple directories can overwrite the outputs. As we do not
166  # control the outputs for now store each in its own sub directory which will be
167  # captured by the over_dir.
168  # TODO(b/139757260): Re-evaluate this one compile per file or multiple and zip
169  # merge.
170  "${AAPT}" compile --legacy "${f}" -o "${out_dir_map[${res_dir}]}"
171done
172""" % (aapt.executable.path, out_dir.path),
173        tools = [aapt],
174        arguments = [args],
175        inputs = resource_files,
176        outputs = [out_dir],
177        mnemonic = "CompileAndroidResources",
178        progress_message = "ResV3 Compiling Android Resources in %s" % out_dir,
179        toolchain = ANDROID_TOOLCHAIN_TYPE,
180    )
181
182def _convert(
183        ctx,
184        out = None,
185        input = None,
186        to_proto = False,
187        aapt = None):
188    args = ctx.actions.args()
189    args.add("convert")
190    args.add("--output-format", ("proto" if to_proto else "binary"))
191    args.add("-o", out)
192    args.add(input)
193
194    ctx.actions.run(
195        executable = aapt,
196        arguments = [args],
197        inputs = [input],
198        outputs = [out],
199        mnemonic = "AaptConvert",
200        progress_message = "ResV3 Convert to %s" % out.short_path,
201        toolchain = ANDROID_TOOLCHAIN_TYPE,
202    )
203
204aapt = struct(
205    link = _link,
206    compile = _compile,
207    convert = _convert,
208)
209