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