1*9e965d6fSRomain Jobredeaux# Copyright 2023 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"""Aspect that transitively build .dex archives and desugar jars.""" 16*9e965d6fSRomain Jobredeaux 17*9e965d6fSRomain Jobredeauxload(":utils.bzl", _get_android_sdk = "get_android_sdk", _utils = "utils") 18*9e965d6fSRomain Jobredeauxload(":dex.bzl", _dex = "dex") 19*9e965d6fSRomain Jobredeauxload(":desugar.bzl", _desugar = "desugar") 20*9e965d6fSRomain Jobredeauxload(":providers.bzl", "StarlarkAndroidDexInfo") 21*9e965d6fSRomain Jobredeauxload(":attrs.bzl", _attrs = "attrs") 22*9e965d6fSRomain Jobredeauxload("//rules:acls.bzl", "acls") 23*9e965d6fSRomain Jobredeaux 24*9e965d6fSRomain Jobredeaux_tristate = _attrs.tristate 25*9e965d6fSRomain Jobredeaux 26*9e965d6fSRomain Jobredeauxdef _aspect_attrs(): 27*9e965d6fSRomain Jobredeaux """Attrs of the rule requiring traversal by the aspect.""" 28*9e965d6fSRomain Jobredeaux return [ 29*9e965d6fSRomain Jobredeaux "aidl_lib", # for the aidl runtime in the android_sdk rule 30*9e965d6fSRomain Jobredeaux "deps", 31*9e965d6fSRomain Jobredeaux "exports", 32*9e965d6fSRomain Jobredeaux "runtime", 33*9e965d6fSRomain Jobredeaux "runtime_deps", 34*9e965d6fSRomain Jobredeaux "_android_sdk", 35*9e965d6fSRomain Jobredeaux "_aspect_proto_toolchain_for_javalite", # To get from proto_library through proto_lang_toolchain rule to proto runtime library. 36*9e965d6fSRomain Jobredeaux "_build_stamp_deps", # for build stamp runtime class deps 37*9e965d6fSRomain Jobredeaux "_build_stamp_mergee_manifest_lib", # for empty build stamp Service class implementation 38*9e965d6fSRomain Jobredeaux "_toolchain", # to get Kotlin toolchain component in android_library 39*9e965d6fSRomain Jobredeaux ] 40*9e965d6fSRomain Jobredeaux 41*9e965d6fSRomain Jobredeaux# Also used by the android_binary_internal rule 42*9e965d6fSRomain Jobredeauxdef get_aspect_deps(ctx): 43*9e965d6fSRomain Jobredeaux """Get all the deps of the dex_desugar_aspect that requires traversal. 44*9e965d6fSRomain Jobredeaux 45*9e965d6fSRomain Jobredeaux Args: 46*9e965d6fSRomain Jobredeaux ctx: The context. 47*9e965d6fSRomain Jobredeaux 48*9e965d6fSRomain Jobredeaux Returns: 49*9e965d6fSRomain Jobredeaux deps_list: List of all deps of the dex_desugar_aspect that requires traversal. 50*9e965d6fSRomain Jobredeaux """ 51*9e965d6fSRomain Jobredeaux deps_list = [] 52*9e965d6fSRomain Jobredeaux for deps in [getattr(ctx.attr, attr, []) for attr in _aspect_attrs()]: 53*9e965d6fSRomain Jobredeaux if str(type(deps)) == "list": 54*9e965d6fSRomain Jobredeaux deps_list += deps 55*9e965d6fSRomain Jobredeaux elif str(type(deps)) == "Target": 56*9e965d6fSRomain Jobredeaux deps_list.append(deps) 57*9e965d6fSRomain Jobredeaux return deps_list 58*9e965d6fSRomain Jobredeaux 59*9e965d6fSRomain Jobredeauxdef _aspect_impl(target, ctx): 60*9e965d6fSRomain Jobredeaux """Adapts the rule and target data. 61*9e965d6fSRomain Jobredeaux 62*9e965d6fSRomain Jobredeaux Args: 63*9e965d6fSRomain Jobredeaux target: The target. 64*9e965d6fSRomain Jobredeaux ctx: The context. 65*9e965d6fSRomain Jobredeaux 66*9e965d6fSRomain Jobredeaux Returns: 67*9e965d6fSRomain Jobredeaux A list of providers. 68*9e965d6fSRomain Jobredeaux """ 69*9e965d6fSRomain Jobredeaux if not acls.in_android_binary_starlark_dex_desugar_proguard(str(ctx.label)): 70*9e965d6fSRomain Jobredeaux return [] 71*9e965d6fSRomain Jobredeaux 72*9e965d6fSRomain Jobredeaux incremental_dexing = getattr(ctx.rule.attr, "incremental_dexing", _tristate.auto) 73*9e965d6fSRomain Jobredeaux min_sdk_version = getattr(ctx.rule.attr, "min_sdk_version", 0) 74*9e965d6fSRomain Jobredeaux 75*9e965d6fSRomain Jobredeaux if incremental_dexing == _tristate.no or \ 76*9e965d6fSRomain Jobredeaux (not ctx.fragments.android.use_incremental_dexing and 77*9e965d6fSRomain Jobredeaux incremental_dexing == _tristate.auto): 78*9e965d6fSRomain Jobredeaux return [] 79*9e965d6fSRomain Jobredeaux 80*9e965d6fSRomain Jobredeaux # TODO(b/33557068): Desugar protos if needed instead of assuming they don't need desugaring 81*9e965d6fSRomain Jobredeaux ignore_desugar = not ctx.fragments.android.desugar_java8 or ctx.rule.kind == "proto_library" 82*9e965d6fSRomain Jobredeaux 83*9e965d6fSRomain Jobredeaux extra_toolchain_jars = _get_platform_based_toolchain_jars(ctx) 84*9e965d6fSRomain Jobredeaux 85*9e965d6fSRomain Jobredeaux if hasattr(ctx.rule.attr, "neverlink") and ctx.rule.attr.neverlink: 86*9e965d6fSRomain Jobredeaux return [] 87*9e965d6fSRomain Jobredeaux 88*9e965d6fSRomain Jobredeaux dex_archives_dict = {} 89*9e965d6fSRomain Jobredeaux runtime_jars = _get_produced_runtime_jars(target, ctx, extra_toolchain_jars) 90*9e965d6fSRomain Jobredeaux bootclasspath = _get_boot_classpath(target, ctx) 91*9e965d6fSRomain Jobredeaux compiletime_classpath = target[JavaInfo].transitive_compile_time_jars if JavaInfo in target else None 92*9e965d6fSRomain Jobredeaux if runtime_jars: 93*9e965d6fSRomain Jobredeaux basename_clash = _check_basename_clash(runtime_jars) 94*9e965d6fSRomain Jobredeaux aspect_dexopts = _get_aspect_dexopts(ctx) 95*9e965d6fSRomain Jobredeaux min_sdk_filename_part = "--min_sdk_version=" + min_sdk_version if min_sdk_version > 0 else "" 96*9e965d6fSRomain Jobredeaux for jar in runtime_jars: 97*9e965d6fSRomain Jobredeaux if not ignore_desugar: 98*9e965d6fSRomain Jobredeaux unique_desugar_filename = (jar.path if basename_clash else jar.basename) + \ 99*9e965d6fSRomain Jobredeaux min_sdk_filename_part + "_desugared.jar" 100*9e965d6fSRomain Jobredeaux desugared_jar = _dex.get_dx_artifact(ctx, unique_desugar_filename) 101*9e965d6fSRomain Jobredeaux _desugar.desugar( 102*9e965d6fSRomain Jobredeaux ctx, 103*9e965d6fSRomain Jobredeaux input = jar, 104*9e965d6fSRomain Jobredeaux output = desugared_jar, 105*9e965d6fSRomain Jobredeaux bootclasspath = bootclasspath, 106*9e965d6fSRomain Jobredeaux classpath = compiletime_classpath, 107*9e965d6fSRomain Jobredeaux min_sdk_version = min_sdk_version, 108*9e965d6fSRomain Jobredeaux desugar_exec = ctx.executable._desugar_java8, 109*9e965d6fSRomain Jobredeaux ) 110*9e965d6fSRomain Jobredeaux else: 111*9e965d6fSRomain Jobredeaux desugared_jar = None 112*9e965d6fSRomain Jobredeaux 113*9e965d6fSRomain Jobredeaux for incremental_dexopts_list in aspect_dexopts: 114*9e965d6fSRomain Jobredeaux incremental_dexopts = "".join(incremental_dexopts_list) 115*9e965d6fSRomain Jobredeaux 116*9e965d6fSRomain Jobredeaux unique_dx_filename = (jar.short_path if basename_clash else jar.basename) + \ 117*9e965d6fSRomain Jobredeaux incremental_dexopts + min_sdk_filename_part + ".dex.zip" 118*9e965d6fSRomain Jobredeaux dex = _dex.get_dx_artifact(ctx, unique_dx_filename) 119*9e965d6fSRomain Jobredeaux _dex.dex( 120*9e965d6fSRomain Jobredeaux ctx, 121*9e965d6fSRomain Jobredeaux input = desugared_jar if desugared_jar else jar, 122*9e965d6fSRomain Jobredeaux output = dex, 123*9e965d6fSRomain Jobredeaux incremental_dexopts = incremental_dexopts_list, 124*9e965d6fSRomain Jobredeaux min_sdk_version = min_sdk_version, 125*9e965d6fSRomain Jobredeaux dex_exec = ctx.executable._dexbuilder, 126*9e965d6fSRomain Jobredeaux ) 127*9e965d6fSRomain Jobredeaux 128*9e965d6fSRomain Jobredeaux dex_archive = struct( 129*9e965d6fSRomain Jobredeaux jar = jar, 130*9e965d6fSRomain Jobredeaux desugared_jar = desugared_jar, 131*9e965d6fSRomain Jobredeaux dex = dex, 132*9e965d6fSRomain Jobredeaux ) 133*9e965d6fSRomain Jobredeaux 134*9e965d6fSRomain Jobredeaux if incremental_dexopts not in dex_archives_dict: 135*9e965d6fSRomain Jobredeaux dex_archives_dict[incremental_dexopts] = [] 136*9e965d6fSRomain Jobredeaux dex_archives_dict[incremental_dexopts].append(dex_archive) 137*9e965d6fSRomain Jobredeaux 138*9e965d6fSRomain Jobredeaux infos = _utils.collect_providers(StarlarkAndroidDexInfo, get_aspect_deps(ctx.rule)) 139*9e965d6fSRomain Jobredeaux merged_info = _dex.merge_infos(infos) 140*9e965d6fSRomain Jobredeaux 141*9e965d6fSRomain Jobredeaux for dexopts in dex_archives_dict: 142*9e965d6fSRomain Jobredeaux if dexopts in merged_info.dex_archives_dict: 143*9e965d6fSRomain Jobredeaux merged_info.dex_archives_dict[dexopts] = depset(dex_archives_dict[dexopts], transitive = [merged_info.dex_archives_dict[dexopts]]) 144*9e965d6fSRomain Jobredeaux else: 145*9e965d6fSRomain Jobredeaux merged_info.dex_archives_dict[dexopts] = depset(dex_archives_dict[dexopts]) 146*9e965d6fSRomain Jobredeaux 147*9e965d6fSRomain Jobredeaux return [ 148*9e965d6fSRomain Jobredeaux StarlarkAndroidDexInfo( 149*9e965d6fSRomain Jobredeaux dex_archives_dict = merged_info.dex_archives_dict, 150*9e965d6fSRomain Jobredeaux ), 151*9e965d6fSRomain Jobredeaux ] 152*9e965d6fSRomain Jobredeaux 153*9e965d6fSRomain Jobredeauxdef _get_produced_runtime_jars(target, ctx, extra_toolchain_jars): 154*9e965d6fSRomain Jobredeaux if ctx.rule.kind == "proto_library": 155*9e965d6fSRomain Jobredeaux if getattr(ctx.rule.attr, "srcs", []): 156*9e965d6fSRomain Jobredeaux if JavaInfo in target: 157*9e965d6fSRomain Jobredeaux return [java_output.class_jar for java_output in target[JavaInfo].java_outputs] 158*9e965d6fSRomain Jobredeaux return [] 159*9e965d6fSRomain Jobredeaux else: 160*9e965d6fSRomain Jobredeaux jars = [] 161*9e965d6fSRomain Jobredeaux if JavaInfo in target: 162*9e965d6fSRomain Jobredeaux jars.extend(target[JavaInfo].runtime_output_jars) 163*9e965d6fSRomain Jobredeaux 164*9e965d6fSRomain Jobredeaux # TODO(b/124540821): Disable R.jar desugaring (with a flag). 165*9e965d6fSRomain Jobredeaux if AndroidIdeInfo in target and target[AndroidIdeInfo].resource_jar: 166*9e965d6fSRomain Jobredeaux jars.append(target[AndroidIdeInfo].resource_jar.class_jar) 167*9e965d6fSRomain Jobredeaux 168*9e965d6fSRomain Jobredeaux if AndroidApplicationResourceInfo in target and target[AndroidApplicationResourceInfo].build_stamp_jar: 169*9e965d6fSRomain Jobredeaux jars.append(target[AndroidApplicationResourceInfo].build_stamp_jar) 170*9e965d6fSRomain Jobredeaux 171*9e965d6fSRomain Jobredeaux jars.extend(extra_toolchain_jars) 172*9e965d6fSRomain Jobredeaux return jars 173*9e965d6fSRomain Jobredeaux 174*9e965d6fSRomain Jobredeauxdef _get_platform_based_toolchain_jars(ctx): 175*9e965d6fSRomain Jobredeaux if not ctx.fragments.android.incompatible_use_toolchain_resolution: 176*9e965d6fSRomain Jobredeaux return [] 177*9e965d6fSRomain Jobredeaux 178*9e965d6fSRomain Jobredeaux if not getattr(ctx.rule.attr, "_android_sdk", None): 179*9e965d6fSRomain Jobredeaux return [] 180*9e965d6fSRomain Jobredeaux 181*9e965d6fSRomain Jobredeaux android_sdk = ctx.rule.attr._android_sdk 182*9e965d6fSRomain Jobredeaux 183*9e965d6fSRomain Jobredeaux if AndroidSdkInfo in android_sdk and android_sdk[AndroidSdkInfo].aidl_lib: 184*9e965d6fSRomain Jobredeaux return android_sdk[AndroidSdkInfo].aidl_lib[JavaInfo].runtime_output_jars 185*9e965d6fSRomain Jobredeaux 186*9e965d6fSRomain Jobredeaux return [] 187*9e965d6fSRomain Jobredeaux 188*9e965d6fSRomain Jobredeauxdef _get_aspect_dexopts(ctx): 189*9e965d6fSRomain Jobredeaux return _power_set(_dex.normalize_dexopts(ctx.fragments.android.get_dexopts_supported_in_incremental_dexing)) 190*9e965d6fSRomain Jobredeaux 191*9e965d6fSRomain Jobredeauxdef _get_boot_classpath(target, ctx): 192*9e965d6fSRomain Jobredeaux if JavaInfo in target: 193*9e965d6fSRomain Jobredeaux compilation_info = target[JavaInfo].compilation_info 194*9e965d6fSRomain Jobredeaux if compilation_info and compilation_info.boot_classpath: 195*9e965d6fSRomain Jobredeaux return compilation_info.boot_classpath 196*9e965d6fSRomain Jobredeaux 197*9e965d6fSRomain Jobredeaux android_jar = _get_android_sdk(ctx).android_jar 198*9e965d6fSRomain Jobredeaux if android_jar: 199*9e965d6fSRomain Jobredeaux return [android_jar] 200*9e965d6fSRomain Jobredeaux 201*9e965d6fSRomain Jobredeaux # This shouldn't ever be reached, but if it is, we should be clear about the error. 202*9e965d6fSRomain Jobredeaux fail("No compilation info or android jar!") 203*9e965d6fSRomain Jobredeaux 204*9e965d6fSRomain Jobredeauxdef _check_basename_clash(artifacts): 205*9e965d6fSRomain Jobredeaux seen = {} 206*9e965d6fSRomain Jobredeaux for artifact in artifacts: 207*9e965d6fSRomain Jobredeaux basename = artifact.basename 208*9e965d6fSRomain Jobredeaux if basename not in seen: 209*9e965d6fSRomain Jobredeaux seen[basename] = True 210*9e965d6fSRomain Jobredeaux else: 211*9e965d6fSRomain Jobredeaux return True 212*9e965d6fSRomain Jobredeaux return False 213*9e965d6fSRomain Jobredeaux 214*9e965d6fSRomain Jobredeauxdef _power_set(items): 215*9e965d6fSRomain Jobredeaux """Calculates the power set of the given items. 216*9e965d6fSRomain Jobredeaux """ 217*9e965d6fSRomain Jobredeaux 218*9e965d6fSRomain Jobredeaux def _exp(base, n): 219*9e965d6fSRomain Jobredeaux """ Calculates base ** n.""" 220*9e965d6fSRomain Jobredeaux res = 1 221*9e965d6fSRomain Jobredeaux for _ in range(n): 222*9e965d6fSRomain Jobredeaux res *= base 223*9e965d6fSRomain Jobredeaux return res 224*9e965d6fSRomain Jobredeaux 225*9e965d6fSRomain Jobredeaux power_set = [] 226*9e965d6fSRomain Jobredeaux size = len(items) 227*9e965d6fSRomain Jobredeaux 228*9e965d6fSRomain Jobredeaux for i in range(_exp(2, size)): 229*9e965d6fSRomain Jobredeaux element = [items[j] for j in range(size) if (i // _exp(2, j) % 2) != 0] 230*9e965d6fSRomain Jobredeaux power_set.append(element) 231*9e965d6fSRomain Jobredeaux 232*9e965d6fSRomain Jobredeaux return power_set 233*9e965d6fSRomain Jobredeaux 234*9e965d6fSRomain Jobredeauxdex_desugar_aspect = aspect( 235*9e965d6fSRomain Jobredeaux implementation = _aspect_impl, 236*9e965d6fSRomain Jobredeaux attr_aspects = _aspect_attrs(), 237*9e965d6fSRomain Jobredeaux attrs = _attrs.add( 238*9e965d6fSRomain Jobredeaux { 239*9e965d6fSRomain Jobredeaux "_desugar_java8": attr.label( 240*9e965d6fSRomain Jobredeaux default = Label("@bazel_tools//tools/android:desugar_java8"), 241*9e965d6fSRomain Jobredeaux cfg = "exec", 242*9e965d6fSRomain Jobredeaux executable = True, 243*9e965d6fSRomain Jobredeaux ), 244*9e965d6fSRomain Jobredeaux "_dexbuilder": attr.label( 245*9e965d6fSRomain Jobredeaux default = Label("@bazel_tools//tools/android:dexbuilder"), 246*9e965d6fSRomain Jobredeaux allow_files = True, 247*9e965d6fSRomain Jobredeaux cfg = "exec", 248*9e965d6fSRomain Jobredeaux executable = True, 249*9e965d6fSRomain Jobredeaux ), 250*9e965d6fSRomain Jobredeaux }, 251*9e965d6fSRomain Jobredeaux _attrs.ANDROID_SDK, 252*9e965d6fSRomain Jobredeaux ), 253*9e965d6fSRomain Jobredeaux fragments = ["android"], 254*9e965d6fSRomain Jobredeaux toolchains = ["//toolchains/android_sdk:toolchain_type"], 255*9e965d6fSRomain Jobredeaux required_aspect_providers = [[JavaInfo]], 256*9e965d6fSRomain Jobredeaux) 257