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_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") 16load("//build/bazel/rules/abi:abi_dump.bzl", "AbiDiffInfo", "abi_dump") 17load( 18 ":cc_library_common.bzl", 19 "CcAndroidMkInfo", 20 "add_lists_defaulting_to_none", 21 "parse_sdk_version", 22 "sanitizer_deps", 23 "system_dynamic_deps_defaults", 24) 25load(":cc_library_static.bzl", "cc_library_static") 26load(":clang_tidy.bzl", "collect_deps_clang_tidy_info") 27load( 28 ":composed_transitions.bzl", 29 "lto_and_fdo_profile_incoming_transition", 30) 31load( 32 ":fdo_profile_transitions.bzl", 33 "FDO_PROFILE_ATTR_KEY", 34) 35load(":generate_toc.bzl", "CcTocInfo", "generate_toc") 36load(":lto_transitions.bzl", "lto_deps_transition") 37load(":stl.bzl", "stl_info_from_attr") 38load(":stripped_cc_common.bzl", "CcUnstrippedInfo", "stripped_shared_library") 39load(":versioned_cc_common.bzl", "versioned_shared_library") 40 41def cc_library_shared( 42 name, 43 suffix = "", 44 # Common arguments between shared_root and the shared library 45 features = [], 46 dynamic_deps = [], 47 implementation_dynamic_deps = [], 48 linkopts = [], 49 target_compatible_with = [], 50 # Ultimately _static arguments for shared_root production 51 srcs = [], 52 srcs_c = [], 53 srcs_as = [], 54 copts = [], 55 cppflags = [], 56 conlyflags = [], 57 asflags = [], 58 hdrs = [], 59 implementation_deps = [], 60 deps = [], 61 whole_archive_deps = [], 62 implementation_whole_archive_deps = [], 63 system_dynamic_deps = None, 64 runtime_deps = [], 65 export_includes = [], 66 export_absolute_includes = [], 67 export_system_includes = [], 68 local_includes = [], 69 absolute_includes = [], 70 rtti = False, 71 stl = "", 72 cpp_std = "", 73 c_std = "", 74 additional_linker_inputs = None, 75 76 # Purely _shared arguments 77 strip = {}, 78 79 # TODO(b/202299295): Handle data attribute. 80 data = [], # @unused 81 use_version_lib = False, 82 stubs_symbol_file = None, 83 inject_bssl_hash = False, 84 sdk_version = "", # @unused 85 min_sdk_version = "", 86 abi_checker_enabled = None, 87 abi_checker_symbol_file = None, 88 abi_checker_exclude_symbol_versions = [], 89 abi_checker_exclude_symbol_tags = [], 90 abi_checker_check_all_apis = False, 91 abi_checker_diff_flags = [], 92 native_coverage = True, 93 tags = [], 94 fdo_profile = None, 95 tidy = None, 96 tidy_checks = None, 97 tidy_checks_as_errors = None, 98 tidy_flags = None, 99 tidy_disabled_srcs = None, 100 tidy_timeout_srcs = None, 101 tidy_gen_header_filter = None, 102 **kwargs): 103 "Bazel macro to correspond with the cc_library_shared Soong module." 104 105 # There exist modules named 'libtest_missing_symbol' and 106 # 'libtest_missing_symbol_root'. Ensure that that the target suffixes are 107 # sufficiently unique. 108 shared_root_name = name + "__internal_root" 109 unstripped_name = name + "_unstripped" 110 stripped_name = name + "_stripped" 111 112 if system_dynamic_deps == None: 113 system_dynamic_deps = system_dynamic_deps_defaults 114 115 if min_sdk_version: 116 features = features + parse_sdk_version(min_sdk_version) + ["-sdk_version_default"] 117 118 if fdo_profile != None: 119 # FIXME(b/261609769): This is a temporary workaround to add link flags 120 # that requires the path to fdo profile. 121 # This workaround is error-prone because it assumes all the fdo_profile 122 # targets are created in a specific way (e.g. fdo_profile target named foo 123 # uses an afdo profile file named foo.afdo in the same folder). 124 fdo_profile_path = fdo_profile + ".afdo" 125 linkopts = linkopts + [ 126 "-funique-internal-linkage-names", 127 "-fprofile-sample-accurate", 128 "-fprofile-sample-use=$(location {})".format(fdo_profile_path), 129 "-Wl,-mllvm,-no-warn-sample-unused=true", 130 ] 131 if additional_linker_inputs != None: 132 additional_linker_inputs = additional_linker_inputs + [fdo_profile_path] 133 else: 134 additional_linker_inputs = [fdo_profile_path] 135 136 stl_info = stl_info_from_attr(stl, True) 137 linkopts = linkopts + stl_info.linkopts 138 copts = copts + stl_info.cppflags 139 140 extra_archive_deps = [] 141 if not native_coverage: 142 features = features + ["-coverage"] 143 else: 144 features = features + select({ 145 "//build/bazel/rules/cc:android_coverage_lib_flag": ["android_coverage_lib"], 146 "//conditions:default": [], 147 }) 148 149 # TODO(b/233660582): deal with the cases where the default lib shouldn't be used 150 extra_archive_deps = select({ 151 "//build/bazel/rules/cc:android_coverage_lib_flag": ["//system/extras/toolchain-extras:libprofile-clang-extras"], 152 "//conditions:default": [], 153 }) 154 155 # The static library at the root of the shared library. 156 # This may be distinct from the static version of the library if e.g. 157 # the static-variant srcs are different than the shared-variant srcs. 158 cc_library_static( 159 name = shared_root_name, 160 hdrs = hdrs, 161 srcs = srcs, 162 srcs_c = srcs_c, 163 srcs_as = srcs_as, 164 copts = copts, 165 cppflags = cppflags, 166 conlyflags = conlyflags, 167 asflags = asflags, 168 export_includes = export_includes, 169 export_absolute_includes = export_absolute_includes, 170 export_system_includes = export_system_includes, 171 local_includes = local_includes, 172 absolute_includes = absolute_includes, 173 rtti = rtti, 174 stl = "none", 175 cpp_std = cpp_std, 176 c_std = c_std, 177 dynamic_deps = dynamic_deps, 178 implementation_deps = implementation_deps + stl_info.static_deps, 179 implementation_dynamic_deps = implementation_dynamic_deps + stl_info.shared_deps, 180 implementation_whole_archive_deps = implementation_whole_archive_deps, 181 system_dynamic_deps = system_dynamic_deps, 182 deps = deps, 183 whole_archive_deps = whole_archive_deps + extra_archive_deps, 184 features = features, 185 target_compatible_with = target_compatible_with, 186 tags = ["manual"], 187 native_coverage = native_coverage, 188 tidy = tidy, 189 tidy_checks = tidy_checks, 190 tidy_checks_as_errors = tidy_checks_as_errors, 191 tidy_flags = tidy_flags, 192 tidy_disabled_srcs = tidy_disabled_srcs, 193 tidy_timeout_srcs = tidy_timeout_srcs, 194 tidy_gen_header_filter = tidy_gen_header_filter, 195 ) 196 197 sanitizer_deps_name = name + "_sanitizer_deps" 198 sanitizer_deps( 199 name = sanitizer_deps_name, 200 dep = shared_root_name, 201 tags = ["manual"], 202 ) 203 204 # implementation_deps and deps are to be linked into the shared library via 205 # --no-whole-archive. In order to do so, they need to be dependencies of 206 # a "root" of the cc_shared_library, but may not be roots themselves. 207 # Below we define stub roots (which themselves have no srcs) in order to facilitate 208 # this. 209 imp_deps_stub = name + "_implementation_deps" 210 deps_stub = name + "_deps" 211 native.cc_library( 212 name = imp_deps_stub, 213 deps = ( 214 implementation_deps + 215 implementation_whole_archive_deps + 216 stl_info.static_deps + 217 implementation_dynamic_deps + 218 system_dynamic_deps + 219 stl_info.shared_deps + 220 [sanitizer_deps_name] 221 ), 222 target_compatible_with = target_compatible_with, 223 tags = ["manual"], 224 ) 225 native.cc_library( 226 name = deps_stub, 227 deps = deps + dynamic_deps, 228 target_compatible_with = target_compatible_with, 229 tags = ["manual"], 230 ) 231 232 shared_dynamic_deps = add_lists_defaulting_to_none( 233 dynamic_deps, 234 system_dynamic_deps, 235 implementation_dynamic_deps, 236 stl_info.shared_deps, 237 ) 238 239 soname = name + suffix + ".so" 240 soname_flag = "-Wl,-soname," + soname 241 242 native.cc_shared_library( 243 name = unstripped_name, 244 user_link_flags = linkopts + [soname_flag], 245 dynamic_deps = shared_dynamic_deps, 246 additional_linker_inputs = additional_linker_inputs, 247 deps = [shared_root_name, imp_deps_stub, deps_stub], 248 features = features, 249 target_compatible_with = target_compatible_with, 250 tags = ["manual"], 251 **kwargs 252 ) 253 254 hashed_name = name + "_hashed" 255 _bssl_hash_injection( 256 name = hashed_name, 257 src = unstripped_name, 258 inject_bssl_hash = inject_bssl_hash, 259 tags = ["manual"], 260 ) 261 262 versioned_name = name + "_versioned" 263 versioned_shared_library( 264 name = versioned_name, 265 src = hashed_name, 266 stamp_build_number = use_version_lib, 267 tags = ["manual"], 268 ) 269 270 stripped_shared_library( 271 name = stripped_name, 272 src = versioned_name, 273 target_compatible_with = target_compatible_with, 274 tags = ["manual"], 275 **strip 276 ) 277 278 # The logic here is based on the shouldCreateSourceAbiDumpForLibrary() in sabi.go 279 # abi_root is used to control if abi_dump aspects should be run on the static 280 # deps because there is no way to control the aspects directly from the rule. 281 abi_root = shared_root_name 282 283 # explicitly disabled 284 if abi_checker_enabled == False: 285 abi_root = None 286 elif abi_checker_enabled == True or stubs_symbol_file: 287 # The logic comes from here: 288 # https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/library.go;l=2288;drc=73feba33308bf9432aea43e069ed24a2f0312f1b 289 if not abi_checker_symbol_file and stubs_symbol_file: 290 abi_checker_symbol_file = stubs_symbol_file 291 else: 292 abi_root = None 293 294 abi_checker_explicitly_disabled = abi_checker_enabled == False 295 296 abi_dump_name = name + "_abi_dump" 297 abi_dump( 298 name = abi_dump_name, 299 shared = stripped_name, 300 root = abi_root, 301 soname = soname, 302 has_stubs = stubs_symbol_file != None, 303 enabled = abi_checker_enabled, 304 explicitly_disabled = abi_checker_explicitly_disabled, 305 symbol_file = abi_checker_symbol_file, 306 exclude_symbol_versions = abi_checker_exclude_symbol_versions, 307 exclude_symbol_tags = abi_checker_exclude_symbol_tags, 308 check_all_apis = abi_checker_check_all_apis, 309 diff_flags = abi_checker_diff_flags, 310 tags = ["manual"], 311 ) 312 313 _cc_library_shared_proxy( 314 name = name, 315 shared = stripped_name, 316 shared_debuginfo = unstripped_name, 317 deps = [shared_root_name], 318 features = features, 319 output_file = soname, 320 target_compatible_with = target_compatible_with, 321 has_stubs = stubs_symbol_file != None, 322 runtime_deps = runtime_deps, 323 abi_dump = abi_dump_name, 324 fdo_profile = fdo_profile, 325 tags = tags, 326 ) 327 328def _create_dynamic_library_linker_input_for_file(ctx, shared_info, output): 329 cc_toolchain = find_cpp_toolchain(ctx) 330 feature_configuration = cc_common.configure_features( 331 ctx = ctx, 332 cc_toolchain = cc_toolchain, 333 ) 334 335 new_library_to_link = cc_common.create_library_to_link( 336 actions = ctx.actions, 337 dynamic_library = output, 338 feature_configuration = feature_configuration, 339 cc_toolchain = cc_toolchain, 340 ) 341 342 new_linker_input = cc_common.create_linker_input( 343 owner = shared_info.linker_input.owner, 344 libraries = depset([new_library_to_link]), 345 ) 346 return new_linker_input 347 348def _correct_cc_shared_library_linking(ctx, shared_info, new_output, static_root): 349 # we may have done some post-processing of the shared library 350 # replace the linker_input that has not been post-processed with the 351 # library that has been post-processed 352 new_linker_input = _create_dynamic_library_linker_input_for_file(ctx, shared_info, new_output) 353 354 # only export the static internal root, we include other libraries as roots 355 # that should be linked as alwayslink; however, if they remain as exports, 356 # they will be linked dynamically, not statically when they should be 357 static_root_label = str(static_root.label) 358 if static_root_label not in shared_info.exports: 359 fail("Expected %s in exports %s" % (static_root_label, shared_info.exports)) 360 exports = [static_root_label] 361 362 return CcSharedLibraryInfo( 363 dynamic_deps = shared_info.dynamic_deps, 364 exports = exports, 365 link_once_static_libs = shared_info.link_once_static_libs, 366 linker_input = new_linker_input, 367 preloaded_deps = shared_info.preloaded_deps, 368 ) 369 370CcStubLibrariesInfo = provider( 371 fields = { 372 "has_stubs": "If the shared library has stubs", 373 }, 374) 375 376# A provider to propagate shared library output artifacts, primarily useful 377# for root level querying in Soong-Bazel mixed builds. 378# Ideally, it would be preferable to reuse the existing native 379# CcSharedLibraryInfo provider, but that provider requires that shared library 380# artifacts are wrapped in a linker input. Artifacts retrievable from this linker 381# input are symlinks to the original artifacts, which is problematic when 382# other dependencies expect a real file. 383CcSharedLibraryOutputInfo = provider( 384 fields = { 385 "output_file": "A single .so file, produced by this target.", 386 }, 387) 388 389def _cc_library_shared_proxy_impl(ctx): 390 # Using a "deps" label_list instead of a single mandatory label attribute 391 # is a hack to support aspect propagation of graph_aspect of the native 392 # cc_shared_library. The aspect will only be applied and propagated along 393 # a label_list attribute named "deps". 394 if len(ctx.attr.deps) != 1: 395 fail("Exactly one 'deps' must be specified for cc_library_shared_proxy") 396 root_files = ctx.attr.deps[0][DefaultInfo].files.to_list() 397 shared_files = ctx.attr.shared[0][DefaultInfo].files.to_list() 398 shared_debuginfo = ctx.attr.shared_debuginfo[0][DefaultInfo].files.to_list() 399 if len(shared_files) != 1 or len(shared_debuginfo) != 1: 400 fail("Expected only one shared library file and one debuginfo file for it") 401 402 shared_lib = shared_files[0] 403 abi_diff_files = ctx.attr.abi_dump[AbiDiffInfo].diff_files.to_list() 404 405 # Copy the output instead of symlinking. This is because this output 406 # can be directly installed into a system image; this installation treats 407 # symlinks differently from real files (symlinks will be preserved relative 408 # to the image root). 409 ctx.actions.run_shell( 410 # We need to add the abi dump files to the inputs of this copy action even 411 # though they are not used, otherwise not all the abi dump files will be 412 # created. For example, for b build 413 # packages/modules/adb/pairing_connection:libadb_pairing_server, only 414 # libadb_pairing_server.so.lsdump will be created, libadb_pairing_auth.so.lsdump 415 # and libadb_pairing_connection.so.lsdump will not be. The reason is that 416 # even though libadb_pairing server depends on libadb_pairing_auth and 417 # libadb_pairing_connection, the abi dump files are not explicitly used 418 # by libadb_pairing_server, so bazel won't bother generating them. 419 inputs = depset(direct = [shared_lib] + abi_diff_files), 420 outputs = [ctx.outputs.output_file], 421 command = "cp -f %s %s" % (shared_lib.path, ctx.outputs.output_file.path), 422 mnemonic = "CopyFile", 423 progress_message = "Copying files", 424 use_default_shell_env = True, 425 ) 426 427 toc_info = generate_toc(ctx, ctx.attr.name, ctx.outputs.output_file) 428 429 files = root_files + [ctx.outputs.output_file, toc_info.toc] + abi_diff_files 430 431 return [ 432 DefaultInfo( 433 files = depset(direct = files), 434 runfiles = ctx.runfiles(files = [ctx.outputs.output_file]), 435 ), 436 _correct_cc_shared_library_linking(ctx, ctx.attr.shared[0][CcSharedLibraryInfo], ctx.outputs.output_file, ctx.attr.deps[0]), 437 toc_info, 438 # The _only_ linker_input is the statically linked root itself. We need to propagate this 439 # as cc_shared_library identifies which libraries can be linked dynamically based on the 440 # linker_inputs of the roots 441 ctx.attr.deps[0][CcInfo], 442 ctx.attr.deps[0][CcAndroidMkInfo], 443 CcStubLibrariesInfo(has_stubs = ctx.attr.has_stubs), 444 ctx.attr.shared[0][OutputGroupInfo], 445 CcSharedLibraryOutputInfo(output_file = ctx.outputs.output_file), 446 CcUnstrippedInfo(unstripped = shared_debuginfo[0]), 447 ctx.attr.abi_dump[AbiDiffInfo], 448 collect_deps_clang_tidy_info(ctx), 449 ] 450 451_cc_library_shared_proxy = rule( 452 implementation = _cc_library_shared_proxy_impl, 453 # Incoming transition to override outgoing transition from rdep 454 cfg = lto_and_fdo_profile_incoming_transition, 455 attrs = { 456 FDO_PROFILE_ATTR_KEY: attr.label(), 457 "shared": attr.label( 458 mandatory = True, 459 providers = [CcSharedLibraryInfo], 460 cfg = lto_deps_transition, 461 ), 462 "shared_debuginfo": attr.label( 463 mandatory = True, 464 cfg = lto_deps_transition, 465 ), 466 # "deps" should be a single element: the root target of the shared library. 467 # See _cc_library_shared_proxy_impl comment for explanation. 468 "deps": attr.label_list( 469 mandatory = True, 470 providers = [CcInfo], 471 cfg = lto_deps_transition, 472 ), 473 "output_file": attr.output(mandatory = True), 474 "has_stubs": attr.bool(default = False), 475 "runtime_deps": attr.label_list( 476 providers = [CcInfo], 477 doc = "Deps that should be installed along with this target. Read by the apex cc aspect.", 478 ), 479 "abi_dump": attr.label(providers = [AbiDiffInfo]), 480 "_allowlist_function_transition": attr.label( 481 default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 482 ), 483 "androidmk_static_deps": attr.label_list( 484 providers = [CcInfo], 485 doc = "All the whole archive deps of the lib. This is used to propagate" + 486 " information to AndroidMk about LOCAL_STATIC_LIBRARIES.", 487 ), 488 "androidmk_whole_archive_deps": attr.label_list( 489 providers = [CcInfo], 490 doc = "All the whole archive deps of the lib. This is used to propagate" + 491 " information to AndroidMk about LOCAL_WHOLE_STATIC_LIBRARIES.", 492 ), 493 "androidmk_dynamic_deps": attr.label_list( 494 providers = [CcInfo], 495 doc = "All the dynamic deps of the lib. This is used to propagate" + 496 " information to AndroidMk about LOCAL_SHARED_LIBRARIES.", 497 ), 498 "_toc_script": attr.label( 499 cfg = "exec", 500 executable = True, 501 allow_single_file = True, 502 default = "//build/soong/scripts:toc.sh", 503 ), 504 "_readelf": attr.label( 505 cfg = "exec", 506 executable = True, 507 allow_single_file = True, 508 default = "//prebuilts/clang/host/linux-x86:llvm-readelf", 509 ), 510 }, 511 provides = [CcAndroidMkInfo, CcInfo, CcTocInfo], 512 fragments = ["cpp"], 513 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], 514) 515 516def _bssl_hash_injection_impl(ctx): 517 if len(ctx.files.src) != 1: 518 fail("Expected only one shared library file") 519 520 hashed_file = ctx.files.src[0] 521 if ctx.attr.inject_bssl_hash: 522 hashed_file = ctx.actions.declare_file("lib" + ctx.attr.name + ".so") 523 args = ctx.actions.args() 524 args.add_all(["-in-object", ctx.files.src[0]]) 525 args.add_all(["-o", hashed_file]) 526 527 ctx.actions.run( 528 inputs = ctx.files.src, 529 outputs = [hashed_file], 530 executable = ctx.executable._bssl_inject_hash, 531 arguments = [args], 532 tools = [ctx.executable._bssl_inject_hash], 533 mnemonic = "BsslInjectHash", 534 ) 535 536 return [ 537 DefaultInfo(files = depset([hashed_file])), 538 ctx.attr.src[CcSharedLibraryInfo], 539 ctx.attr.src[OutputGroupInfo], 540 ] 541 542_bssl_hash_injection = rule( 543 implementation = _bssl_hash_injection_impl, 544 attrs = { 545 "src": attr.label( 546 mandatory = True, 547 # TODO(b/217908237): reenable allow_single_file 548 # allow_single_file = True, 549 providers = [CcSharedLibraryInfo], 550 ), 551 "inject_bssl_hash": attr.bool( 552 default = False, 553 doc = "Whether inject BSSL hash", 554 ), 555 "_bssl_inject_hash": attr.label( 556 cfg = "exec", 557 doc = "The BSSL hash injection tool.", 558 executable = True, 559 default = "//prebuilts/build-tools:linux-x86/bin/bssl_inject_hash", 560 allow_single_file = True, 561 ), 562 }, 563) 564