1# Copyright (C) 2021 The Android Open Source Project 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 15load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 16load("//build/bazel/product_config:product_variables_providing_rule.bzl", "ProductVariablesInfo") 17load("//build/bazel/rules:metadata.bzl", "MetadataFileInfo") 18load("//build/bazel/rules/cc:cc_library_common.bzl", "parse_apex_sdk_version") 19load("//build/bazel/rules/cc:cc_library_shared.bzl", "CcSharedLibraryOutputInfo", "CcStubLibrariesInfo") 20load("//build/bazel/rules/cc:cc_stub_library.bzl", "CcStubLibrarySharedInfo") 21load("//build/bazel/rules/cc:stripped_cc_common.bzl", "CcUnstrippedInfo") 22load("//build/bazel/rules/license:license_aspect.bzl", "license_aspect") 23 24ApexCcInfo = provider( 25 "Info needed to use CC targets in APEXes", 26 fields = { 27 "provides_native_libs": "Labels of native shared libs that this apex provides.", 28 "requires_native_libs": "Labels of native shared libs that this apex requires.", 29 "transitive_shared_libs": "File references to transitive .so libs produced by the CC targets and should be included in the APEX.", 30 }, 31) 32 33ApexCcMkInfo = provider( 34 "AndroidMk data about CC targets in APEXes", 35 fields = { 36 "make_modules_to_install": "List of module names that should be installed into the system, along with this APEX", 37 }, 38) 39 40# Special libraries that are installed to the bootstrap subdirectory. Bionic 41# libraries are assumed to be provided by the system, and installed automatically 42# as a symlink to the runtime APEX. 43# 44# This list is from https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/cc.go;l=1439-1452;drc=9c667416ded33b93a44c5f1894ea23cae6699a17 45# 46# NOTE: Keep this list in sync with the Soong list. 47# 48# See cc/binary.go#install for more information. 49def _installed_to_bootstrap(label): 50 label = str(label) 51 52 # hwasan 53 if label == "@//prebuilts/clang/host/linux-x86:libclang_rt.hwasan": 54 return True 55 56 # bionic libs 57 if label in [ 58 "@//bionic/libc:libc", 59 "@//bionic/libc:libc_hwasan", # For completeness, but no one should be depending on this. 60 "@//bionic/libm:libm", 61 "@//bionic/libdl:libdl", 62 "@//bionic/libdl_android:libdl_android", 63 "@//bionic/linker:linker", 64 ]: 65 return True 66 67 return False 68 69def has_cc_stubs(target): 70 """ 71 Return True if this target provides stubs. 72 73 There is no need to check versions of stubs any more, see aosp/1609533. 74 75 These stable ABI libraries are intentionally omitted from APEXes as they are 76 provided from another APEX or the platform. By omitting them from APEXes, we 77 ensure that there are no multiple copies of such libraries on a device. 78 79 Args: 80 target: The target to check for stubs on. 81 Returns: 82 If the target has cc stubs 83 """ 84 if CcStubLibrarySharedInfo in target: 85 # This is a stub lib (direct or transitive). 86 return True 87 88 if CcStubLibrariesInfo in target and target[CcStubLibrariesInfo].has_stubs: 89 # Direct deps of the apex. The apex would depend on the source lib, not stub lib, 90 # so check for CcStubLibrariesInfo.has_stubs. 91 return True 92 93 return False 94 95# Check if this target is specified as a direct dependency of the APEX, 96# as opposed to a transitive dependency, as the transitivity impacts 97# the files that go into an APEX. 98def is_apex_direct_dep(label, ctx): 99 apex_direct_deps = ctx.attr._apex_direct_deps[BuildSettingInfo].value 100 return str(label) in apex_direct_deps 101 102MinSdkVersionInfo = provider( 103 "MinSdkVersionInfo provides metadata about the min_sdk_version attribute of a target", 104 fields = { 105 "apex_inherit": "true if min_sdk_version: \"apex_inherit\" is present on the module", 106 "min_sdk_version": "value of min_sdk_version", 107 }, 108) 109 110def get_min_sdk_version(ctx): 111 """get_min_sdk_version returns the min_sdk_version for the existing target 112 113 Args: 114 ctx (rule context): a rule context 115 Returns: 116 MinSdkVersionInfo 117 """ 118 min_sdk_version = None 119 apex_inherit = False 120 if hasattr(ctx.rule.attr, "min_sdk_version"): 121 if ctx.rule.attr.min_sdk_version == "apex_inherit": 122 apex_inherit = True 123 elif ctx.rule.attr.min_sdk_version: 124 min_sdk_version = parse_apex_sdk_version(ctx.rule.attr.min_sdk_version) 125 else: 126 # min_sdk_version in cc targets are represented as features 127 for f in ctx.rule.attr.features: 128 if f.startswith("sdk_version_"): 129 # e.g. sdk_version_29 or sdk_version_10000 or sdk_version_apex_inherit 130 sdk_version = f.removeprefix("sdk_version_") 131 if sdk_version == "apex_inherit": 132 apex_inherit = True 133 elif min_sdk_version == None: 134 min_sdk_version = int(sdk_version) 135 else: 136 fail( 137 "found more than one sdk_version feature on {target}; features = {features}", 138 target = ctx.label, 139 features = ctx.rule.attr.features, 140 ) 141 return MinSdkVersionInfo( 142 min_sdk_version = min_sdk_version, 143 apex_inherit = apex_inherit, 144 ) 145 146def _validate_min_sdk_version(ctx): 147 dep_min_version = get_min_sdk_version(ctx).min_sdk_version 148 apex_min_version = parse_apex_sdk_version(ctx.attr._min_sdk_version[BuildSettingInfo].value) 149 if dep_min_version and apex_min_version < dep_min_version: 150 fail("The apex %s's min_sdk_version %s cannot be lower than the dep's min_sdk_version %s" % 151 (ctx.attr._apex_name[BuildSettingInfo].value, apex_min_version, dep_min_version)) 152 153def _apex_cc_aspect_impl(target, ctx): 154 # Ensure that dependencies are compatible with this apex's min_sdk_level 155 if not ctx.attr.testonly: 156 _validate_min_sdk_version(ctx) 157 158 # Whether this dep is a direct dep of an APEX or makes a difference in dependency 159 # traversal, and aggregation of libs that are required from the platform/other APEXes, 160 # and libs that this APEX will provide to others. 161 is_direct_dep = is_apex_direct_dep(target.label, ctx) 162 163 provides = [] 164 requires = [] 165 make_modules_to_install = [] 166 167 # The APEX manifest records the stub-providing libs (ABI-stable) in its 168 # direct and transitive deps. 169 # 170 # If a stub-providing lib is in the direct deps of an apex, then the apex 171 # provides the symbols. 172 # 173 # If a stub-providing lib is in the transitive deps of an apex, then the 174 # apex requires the symbols from the platform or other apexes. 175 if has_cc_stubs(target): 176 if is_direct_dep: 177 # Mark this target as "stub-providing" exports of this APEX, 178 # which the system and other APEXes can depend on, and propagate 179 # this list. 180 provides.append(target.label) 181 else: 182 # If this is not a direct dep and the build is in not unbundled mode, 183 # and stubs are available, don't propagate the libraries. 184 185 # Mark this target as required from the system either via 186 # the system partition, or another APEX, and propagate this list. 187 source_library_label = target[CcStubLibrarySharedInfo].source_library_label 188 189 # If a stub library is in the "provides" of the apex, it doesn't need to be in the "requires" 190 if not is_apex_direct_dep(source_library_label, ctx): 191 requires.append(source_library_label) 192 if not ctx.attr._product_variables[ProductVariablesInfo].Unbundled_build and not _installed_to_bootstrap(source_library_label): 193 # It's sufficient to pass the make module name, not the fully qualified bazel label. 194 make_modules_to_install.append(source_library_label.name) 195 196 return [ 197 ApexCcInfo( 198 transitive_shared_libs = depset(), 199 requires_native_libs = depset(direct = requires), 200 provides_native_libs = depset(direct = provides), 201 ), 202 ApexCcMkInfo( 203 make_modules_to_install = depset(direct = make_modules_to_install), 204 ), 205 ] 206 207 shared_object_files = [] 208 209 # Transitive deps containing shared libraries to be propagated the apex. 210 transitive_deps = [] 211 rules_propagate_src = [ 212 "_bssl_hash_injection", 213 "stripped_shared_library", 214 "versioned_shared_library", 215 "stripped_binary", 216 "versioned_binary", 217 ] 218 219 # Exclude the stripped and unstripped so files 220 if ctx.rule.kind == "_cc_library_shared_proxy": 221 shared_object_files.append(struct( 222 stripped = target[CcSharedLibraryOutputInfo].output_file, 223 unstripped = target[CcUnstrippedInfo].unstripped, 224 metadata_file = target[MetadataFileInfo].metadata_file, 225 )) 226 if hasattr(ctx.rule.attr, "shared"): 227 transitive_deps.append(ctx.rule.attr.shared[0]) 228 elif ctx.rule.kind in ["cc_shared_library", "cc_binary"]: 229 # Propagate along the dynamic_deps and deps edges for binaries and shared libs 230 if hasattr(ctx.rule.attr, "dynamic_deps"): 231 for dep in ctx.rule.attr.dynamic_deps: 232 transitive_deps.append(dep) 233 if hasattr(ctx.rule.attr, "deps"): 234 for dep in ctx.rule.attr.deps: 235 transitive_deps.append(dep) 236 elif ctx.rule.kind in rules_propagate_src and hasattr(ctx.rule.attr, "src"): 237 # Propagate along the src edge 238 if ctx.rule.kind == "stripped_binary": 239 transitive_deps.append(ctx.rule.attr.src[0]) 240 else: 241 transitive_deps.append(ctx.rule.attr.src) 242 243 if ctx.rule.kind in ["stripped_binary", "_cc_library_shared_proxy", "_cc_library_combiner"] and hasattr(ctx.rule.attr, "runtime_deps"): 244 for dep in ctx.rule.attr.runtime_deps: 245 unstripped = None 246 if CcUnstrippedInfo in dep: 247 unstripped = dep[CcUnstrippedInfo].unstripped 248 for output_file in dep[DefaultInfo].files.to_list(): 249 if output_file.extension == "so": 250 shared_object_files.append(struct( 251 stripped = output_file, 252 unstripped = unstripped, 253 metadata_file = dep[MetadataFileInfo].metadata_file, 254 )) 255 transitive_deps.append(dep) 256 257 return [ 258 ApexCcInfo( 259 transitive_shared_libs = depset( 260 shared_object_files, 261 transitive = [info[ApexCcInfo].transitive_shared_libs for info in transitive_deps], 262 ), 263 requires_native_libs = depset( 264 [], 265 transitive = [info[ApexCcInfo].requires_native_libs for info in transitive_deps], 266 ), 267 provides_native_libs = depset( 268 provides, 269 transitive = [info[ApexCcInfo].provides_native_libs for info in transitive_deps], 270 ), 271 ), 272 ApexCcMkInfo( 273 make_modules_to_install = depset( 274 [], 275 transitive = [info[ApexCcMkInfo].make_modules_to_install for info in transitive_deps], 276 ), 277 ), 278 ] 279 280# The list of attributes in a cc dep graph where this aspect will traverse on. 281CC_ATTR_ASPECTS = [ 282 "dynamic_deps", 283 "deps", 284 "shared", 285 "src", 286 "runtime_deps", 287 "static_deps", 288 "whole_archive_deps", 289] 290 291# This aspect is intended to be applied on a apex.native_shared_libs attribute 292apex_cc_aspect = aspect( 293 implementation = _apex_cc_aspect_impl, 294 provides = [ApexCcInfo, ApexCcMkInfo], 295 attrs = { 296 # This is propagated from the apex 297 "testonly": attr.bool(default = False), 298 "_apex_direct_deps": attr.label(default = "//build/bazel/rules/apex:apex_direct_deps"), 299 "_apex_name": attr.label(default = "//build/bazel/rules/apex:apex_name"), 300 "_min_sdk_version": attr.label(default = "//build/bazel/rules/apex:min_sdk_version"), 301 "_product_variables": attr.label(default = "//build/bazel/product_config:product_vars"), 302 }, 303 attr_aspects = CC_ATTR_ASPECTS, 304 requires = [license_aspect], 305 # TODO: Have this aspect also propagate along attributes of native_shared_libs? 306) 307