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