1""" 2Copyright (C) 2021 The Android Open Source Project 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15""" 16 17load( 18 ":cc_library_common.bzl", 19 "create_ccinfo_for_includes", 20 "is_external_directory", 21 "parse_sdk_version", 22 "system_dynamic_deps_defaults", 23) 24load(":stl.bzl", "static_stl_deps") 25load("@bazel_skylib//lib:collections.bzl", "collections") 26load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain") 27load("@rules_cc//examples:experimental_cc_shared_library.bzl", "CcSharedLibraryInfo") 28load("//build/bazel/product_variables:constants.bzl", "constants") 29 30CcStaticLibraryInfo = provider(fields = ["root_static_archive", "objects"]) 31 32def cc_library_static( 33 name, 34 deps = [], 35 implementation_deps = [], 36 dynamic_deps = [], 37 implementation_dynamic_deps = [], 38 whole_archive_deps = [], 39 implementation_whole_archive_deps = [], 40 system_dynamic_deps = None, 41 export_absolute_includes = [], 42 export_includes = [], 43 export_system_includes = [], 44 local_includes = [], 45 absolute_includes = [], 46 hdrs = [], 47 native_bridge_supported = False, # TODO: not supported yet. 48 use_libcrt = True, 49 rtti = False, 50 stl = "", 51 cpp_std = "", 52 c_std = "", 53 # Flags for C and C++ 54 copts = [], 55 # C++ attributes 56 srcs = [], 57 cppflags = [], 58 # C attributes 59 srcs_c = [], 60 conlyflags = [], 61 # asm attributes 62 srcs_as = [], 63 asflags = [], 64 features = [], 65 alwayslink = None, 66 target_compatible_with = [], 67 # TODO(b/202299295): Handle data attribute. 68 data = [], 69 sdk_version = "", 70 min_sdk_version = "", 71 use_version_lib = False): 72 "Bazel macro to correspond with the cc_library_static Soong module." 73 74 exports_name = "%s_exports" % name 75 locals_name = "%s_locals" % name 76 cpp_name = "%s_cpp" % name 77 c_name = "%s_c" % name 78 asm_name = "%s_asm" % name 79 80 toolchain_features = [] 81 toolchain_features += features 82 83 if is_external_directory(native.package_name()): 84 toolchain_features += [ 85 "-non_external_compiler_flags", 86 "external_compiler_flags", 87 ] 88 89 if use_version_lib: 90 libbuildversionLabel = "//build/soong/cc/libbuildversion:libbuildversion" 91 whole_archive_deps = whole_archive_deps + [libbuildversionLabel] 92 93 if rtti: 94 toolchain_features += ["rtti"] 95 if not use_libcrt: 96 toolchain_features += ["use_libcrt"] 97 if cpp_std: 98 toolchain_features += [cpp_std, "-cpp_std_default"] 99 if c_std: 100 toolchain_features += [c_std, "-c_std_default"] 101 102 if min_sdk_version: 103 toolchain_features += [ 104 "sdk_version_" + parse_sdk_version(min_sdk_version), 105 "-sdk_version_default", 106 ] 107 108 if system_dynamic_deps == None: 109 system_dynamic_deps = system_dynamic_deps_defaults 110 111 _cc_includes( 112 name = exports_name, 113 includes = export_includes, 114 absolute_includes = export_absolute_includes, 115 system_includes = export_system_includes, 116 # whole archive deps always re-export their includes, etc 117 deps = deps + whole_archive_deps + dynamic_deps, 118 target_compatible_with = target_compatible_with, 119 ) 120 121 _cc_includes( 122 name = locals_name, 123 includes = local_includes, 124 absolute_includes = absolute_includes, 125 deps = implementation_deps + implementation_dynamic_deps + system_dynamic_deps + static_stl_deps(stl) + implementation_whole_archive_deps, 126 target_compatible_with = target_compatible_with, 127 ) 128 129 # Silently drop these attributes for now: 130 # - native_bridge_supported 131 common_attrs = dict( 132 [ 133 # TODO(b/199917423): This may be superfluous. Investigate and possibly remove. 134 ("linkstatic", True), 135 ("hdrs", hdrs), 136 # Add dynamic_deps to implementation_deps, as the include paths from the 137 # dynamic_deps are also needed. 138 ("implementation_deps", [locals_name]), 139 ("deps", [exports_name]), 140 ("features", toolchain_features), 141 ("toolchains", ["//build/bazel/platforms:android_target_product_vars"]), 142 ("alwayslink", alwayslink), 143 ("target_compatible_with", target_compatible_with), 144 ], 145 ) 146 147 native.cc_library( 148 name = cpp_name, 149 srcs = srcs, 150 copts = copts + cppflags, 151 **common_attrs 152 ) 153 native.cc_library( 154 name = c_name, 155 srcs = srcs_c, 156 copts = copts + conlyflags, 157 **common_attrs 158 ) 159 native.cc_library( 160 name = asm_name, 161 srcs = srcs_as, 162 copts = asflags, 163 **common_attrs 164 ) 165 166 # Root target to handle combining of the providers of the language-specific targets. 167 _cc_library_combiner( 168 name = name, 169 deps = [cpp_name, c_name, asm_name] + whole_archive_deps + implementation_whole_archive_deps, 170 target_compatible_with = target_compatible_with, 171 ) 172 173# Returns a CcInfo object which combines one or more CcInfo objects, except that all 174# linker inputs owned by owners in `old_owner_labels` are relinked and owned by the current target. 175# 176# This is useful in the "macro with proxy rule" pattern, as some rules upstream 177# may expect they are depending directly on a target which generates linker inputs, 178# as opposed to a proxy target which is a level of indirection to such a target. 179def _cc_library_combiner_impl(ctx): 180 old_owner_labels = [] 181 cc_infos = [] 182 for dep in ctx.attr.deps: 183 old_owner_labels.append(dep.label) 184 cc_infos.append(dep[CcInfo]) 185 combined_info = cc_common.merge_cc_infos(cc_infos = cc_infos) 186 187 objects_to_link = [] 188 189 # This is not ideal, as it flattens a depset. 190 for old_linker_input in combined_info.linking_context.linker_inputs.to_list(): 191 if old_linker_input.owner in old_owner_labels: 192 for lib in old_linker_input.libraries: 193 # These objects will be recombined into the root archive. 194 objects_to_link.extend(lib.objects) 195 else: 196 # Android macros don't handle transitive linker dependencies because 197 # it's unsupported in legacy. We may want to change this going forward, 198 # but for now it's good to validate that this invariant remains. 199 fail("cc_static_library %s given transitive linker dependency from %s" % (ctx.label, old_linker_input.owner)) 200 201 cc_toolchain = find_cpp_toolchain(ctx) 202 CPP_LINK_STATIC_LIBRARY_ACTION_NAME = "c++-link-static-library" 203 feature_configuration = cc_common.configure_features( 204 ctx = ctx, 205 cc_toolchain = cc_toolchain, 206 requested_features = ctx.features, 207 unsupported_features = ctx.disabled_features + ["linker_flags"], 208 ) 209 210 output_file = ctx.actions.declare_file("lib" + ctx.label.name + ".a") 211 linker_input = cc_common.create_linker_input( 212 owner = ctx.label, 213 libraries = depset(direct = [ 214 cc_common.create_library_to_link( 215 actions = ctx.actions, 216 feature_configuration = feature_configuration, 217 cc_toolchain = cc_toolchain, 218 static_library = output_file, 219 objects = objects_to_link, 220 ), 221 ]), 222 ) 223 224 linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linker_input])) 225 226 archiver_path = cc_common.get_tool_for_action( 227 feature_configuration = feature_configuration, 228 action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, 229 ) 230 archiver_variables = cc_common.create_link_variables( 231 feature_configuration = feature_configuration, 232 cc_toolchain = cc_toolchain, 233 output_file = output_file.path, 234 is_using_linker = False, 235 ) 236 command_line = cc_common.get_memory_inefficient_command_line( 237 feature_configuration = feature_configuration, 238 action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, 239 variables = archiver_variables, 240 ) 241 args = ctx.actions.args() 242 args.add_all(command_line) 243 args.add_all(objects_to_link) 244 245 ctx.actions.run( 246 executable = archiver_path, 247 arguments = [args], 248 inputs = depset( 249 direct = objects_to_link, 250 transitive = [ 251 cc_toolchain.all_files, 252 ], 253 ), 254 outputs = [output_file], 255 ) 256 return [ 257 DefaultInfo(files = depset(direct = [output_file]), data_runfiles = ctx.runfiles(files = [output_file])), 258 CcInfo(compilation_context = combined_info.compilation_context, linking_context = linking_context), 259 CcStaticLibraryInfo(root_static_archive = output_file, objects = objects_to_link), 260 ] 261 262# A rule which combines objects of oen or more cc_library targets into a single 263# static linker input. This outputs a single archive file combining the objects 264# of its direct deps, and propagates Cc providers describing that these objects 265# should be linked for linking rules upstream. 266# This rule is useful for maintaining the illusion that the target's deps are 267# comprised by a single consistent rule: 268# - A single archive file is always output by this rule. 269# - A single linker input struct is always output by this rule, and it is 'owned' 270# by this rule. 271_cc_library_combiner = rule( 272 implementation = _cc_library_combiner_impl, 273 attrs = { 274 "deps": attr.label_list(providers = [CcInfo]), 275 "_cc_toolchain": attr.label( 276 default = Label("@local_config_cc//:toolchain"), 277 providers = [cc_common.CcToolchainInfo], 278 ), 279 }, 280 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], 281 provides = [CcInfo], 282 fragments = ["cpp"], 283) 284 285def _cc_includes_impl(ctx): 286 return [create_ccinfo_for_includes( 287 ctx, 288 includes = ctx.attr.includes, 289 absolute_includes = ctx.attr.absolute_includes, 290 system_includes = ctx.attr.system_includes, 291 deps = ctx.attr.deps, 292 )] 293 294# Bazel's native cc_library rule supports specifying include paths two ways: 295# 1. non-exported includes can be specified via copts attribute 296# 2. exported -isystem includes can be specified via includes attribute 297# 298# In order to guarantee a correct inclusion search order, we need to export 299# includes paths for both -I and -isystem; however, there is no native Bazel 300# support to export both of these, this rule provides a CcInfo to propagate the 301# given package-relative include/system include paths as exec root relative 302# include/system include paths. 303_cc_includes = rule( 304 implementation = _cc_includes_impl, 305 attrs = { 306 "absolute_includes": attr.string_list(doc = "List of exec-root relative or absolute search paths for headers, usually passed with -I"), 307 "includes": attr.string_list(doc = "Package-relative list of search paths for headers, usually passed with -I"), 308 "system_includes": attr.string_list(doc = "Package-relative list of search paths for headers, usually passed with -isystem"), 309 "deps": attr.label_list(doc = "Re-propagates the includes obtained from these dependencies.", providers = [CcInfo]), 310 }, 311 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], 312 fragments = ["cpp"], 313 provides = [CcInfo], 314) 315