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 15"""A macro to handle shared library stripping.""" 16 17load("@bazel_skylib//lib:paths.bzl", "paths") 18load(":cc_library_common.bzl", "CcAndroidMkInfo", "check_valid_ldlibs") 19load(":clang_tidy.bzl", "collect_deps_clang_tidy_info") 20load( 21 ":composed_transitions.bzl", 22 "drop_lto_and_sanitizer_transition", 23 "lto_and_sanitizer_deps_transition", 24) 25 26CcUnstrippedInfo = provider( 27 "Provides unstripped binary/shared library", 28 fields = { 29 "unstripped": "unstripped target", 30 }, 31) 32 33# Keep this consistent with soong/cc/strip.go#NeedsStrip. 34def _needs_strip(ctx): 35 if ctx.attr.none: 36 return False 37 if ctx.target_platform_has_constraint(ctx.attr._android_constraint[platform_common.ConstraintValueInfo]): 38 return True 39 return (ctx.attr.all or ctx.attr.keep_symbols or 40 ctx.attr.keep_symbols_and_debug_frame or ctx.attr.keep_symbols_list) 41 42# Keep this consistent with soong/cc/strip.go#strip and soong/cc/builder.go#transformStrip. 43def _get_strip_args(attrs): 44 strip_args = [] 45 keep_mini_debug_info = False 46 if attrs.keep_symbols: 47 strip_args.append("--keep-symbols") 48 elif attrs.keep_symbols_and_debug_frame: 49 strip_args.append("--keep-symbols-and-debug-frame") 50 elif attrs.keep_symbols_list: 51 strip_args.append("-k" + ",".join(attrs.keep_symbols_list)) 52 elif not attrs.all: 53 strip_args.append("--keep-mini-debug-info") 54 keep_mini_debug_info = True 55 56 if not keep_mini_debug_info: 57 strip_args.append("--add-gnu-debuglink") 58 59 return strip_args 60 61# https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/builder.go;l=131-146;drc=master 62def stripped_impl(ctx, file, prefix = "", stem = "", suffix = "", extension = "", subdir = ""): 63 filename_stem = stem or ctx.attr.name 64 filename = prefix + filename_stem + suffix + extension 65 out_file = ctx.actions.declare_file( 66 paths.join( 67 subdir, # Prevent name collision by generating in a directory unique to the target 68 filename, 69 ), 70 ) 71 if not _needs_strip(ctx): 72 ctx.actions.symlink( 73 output = out_file, 74 target_file = file, 75 ) 76 return out_file 77 d_file = ctx.actions.declare_file( 78 paths.join( 79 subdir, 80 filename + ".d", 81 ), 82 ) 83 84 ctx.actions.run( 85 env = { 86 "CREATE_MINIDEBUGINFO": ctx.executable._create_minidebuginfo.path, 87 "XZ": ctx.executable._xz.path, 88 "CLANG_BIN": ctx.executable._ar.dirname, 89 }, 90 inputs = [file], 91 tools = [ 92 ctx.executable._ar, 93 ctx.executable._create_minidebuginfo, 94 ctx.executable._objcopy, 95 ctx.executable._readelf, 96 ctx.executable._strip, 97 ctx.executable._strip_script, 98 ctx.executable._xz, 99 ], 100 outputs = [out_file, d_file], 101 executable = ctx.executable._strip_script, 102 arguments = _get_strip_args(ctx.attr) + [ 103 "-i", 104 file.path, 105 "-o", 106 out_file.path, 107 "-d", 108 d_file.path, 109 ], 110 mnemonic = "CcStrip", 111 ) 112 return out_file 113 114strip_attrs = dict( 115 keep_symbols = attr.bool(default = False), 116 keep_symbols_and_debug_frame = attr.bool(default = False), 117 all = attr.bool(default = False), 118 none = attr.bool(default = False), 119 keep_symbols_list = attr.string_list(default = []), 120) 121common_strip_attrs = dict( 122 strip_attrs, 123 _xz = attr.label( 124 cfg = "exec", 125 executable = True, 126 allow_single_file = True, 127 default = "//prebuilts/build-tools:linux-x86/bin/xz", 128 ), 129 _create_minidebuginfo = attr.label( 130 cfg = "exec", 131 executable = True, 132 allow_single_file = True, 133 default = "//prebuilts/build-tools:linux-x86/bin/create_minidebuginfo", 134 ), 135 _strip_script = attr.label( 136 cfg = "exec", 137 executable = True, 138 allow_single_file = True, 139 default = "//build/soong/scripts:strip.sh", 140 ), 141 _ar = attr.label( 142 cfg = "exec", 143 executable = True, 144 allow_single_file = True, 145 default = "//prebuilts/clang/host/linux-x86:llvm-ar", 146 ), 147 _strip = attr.label( 148 cfg = "exec", 149 executable = True, 150 allow_single_file = True, 151 default = "//prebuilts/clang/host/linux-x86:llvm-strip", 152 ), 153 _readelf = attr.label( 154 cfg = "exec", 155 executable = True, 156 allow_single_file = True, 157 default = "//prebuilts/clang/host/linux-x86:llvm-readelf", 158 ), 159 _objcopy = attr.label( 160 cfg = "exec", 161 executable = True, 162 allow_single_file = True, 163 default = "//prebuilts/clang/host/linux-x86:llvm-objcopy", 164 ), 165 _cc_toolchain = attr.label( 166 default = Label("@local_config_cc//:toolchain"), 167 providers = [cc_common.CcToolchainInfo], 168 ), 169 _android_constraint = attr.label( 170 default = Label("//build/bazel_common_rules/platforms/os:android"), 171 ), 172 _darwin_constraint = attr.label( 173 default = Label("//build/bazel_common_rules/platforms/os:darwin"), 174 ), 175 _linux_constraint = attr.label( 176 default = Label("//build/bazel_common_rules/platforms/os:linux"), 177 ), 178 _windows_constraint = attr.label( 179 default = Label("//build/bazel_common_rules/platforms/os:windows"), 180 ), 181) 182 183def _stripped_shared_library_impl(ctx): 184 check_valid_ldlibs(ctx, ctx.attr.linkopts) 185 186 out_file = stripped_impl(ctx, ctx.file.src, prefix = "lib", extension = ".so", subdir = ctx.attr.name) 187 188 return [ 189 DefaultInfo(files = depset([out_file])), 190 ctx.attr.src[CcSharedLibraryInfo], 191 ctx.attr.src[OutputGroupInfo], 192 ] 193 194stripped_shared_library = rule( 195 implementation = _stripped_shared_library_impl, 196 attrs = dict( 197 common_strip_attrs, 198 src = attr.label( 199 mandatory = True, 200 providers = [CcSharedLibraryInfo], 201 allow_single_file = True, 202 ), 203 linkopts = attr.string_list(default = []), # Used for validation 204 ), 205 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], 206) 207 208# A marker provider to distinguish a cc_binary from everything else that exports 209# a CcInfo. 210StrippedCcBinaryInfo = provider() 211 212def _stripped_binary_impl(ctx): 213 check_valid_ldlibs(ctx, ctx.attr.linkopts) 214 215 common_providers = [ 216 ctx.attr.src[0][CcInfo], 217 ctx.attr.src[0][InstrumentedFilesInfo], 218 ctx.attr.src[0][DebugPackageInfo], 219 ctx.attr.src[0][OutputGroupInfo], 220 StrippedCcBinaryInfo(), # a marker for dependents 221 CcUnstrippedInfo( 222 unstripped = ctx.attr.unstripped, 223 ), 224 collect_deps_clang_tidy_info(ctx), 225 ] + [ 226 d[CcAndroidMkInfo] 227 for d in ctx.attr.androidmk_deps 228 ] 229 230 # Generate binary in a directory unique to this target to prevent possible collisions due to common `stem` 231 # Generate in `bin` to prevent incrementality issues for mixed builds where <package>/<name> could be a file and not a dir 232 subdir = paths.join("bin", ctx.attr.name) 233 out_file = stripped_impl(ctx, ctx.file.src, stem = ctx.attr.stem, suffix = ctx.attr.suffix, subdir = subdir) 234 235 return [ 236 DefaultInfo( 237 files = depset([out_file]), 238 executable = out_file, 239 runfiles = ctx.attr.src[0][DefaultInfo].default_runfiles, 240 ), 241 ] + common_providers 242 243_rule_attrs = dict( 244 common_strip_attrs, 245 src = attr.label( 246 mandatory = True, 247 allow_single_file = True, 248 providers = [CcInfo], 249 cfg = lto_and_sanitizer_deps_transition, 250 ), 251 linkopts = attr.string_list(default = []), # Used for validation 252 runtime_deps = attr.label_list( 253 providers = [CcInfo], 254 doc = "Deps that should be installed along with this target. Read by the apex cc aspect.", 255 ), 256 androidmk_deps = attr.label_list( 257 providers = [CcAndroidMkInfo], 258 cfg = lto_and_sanitizer_deps_transition, 259 ), 260 stem = attr.string(), 261 suffix = attr.string(), 262 unstripped = attr.label( 263 mandatory = True, 264 allow_single_file = True, 265 cfg = lto_and_sanitizer_deps_transition, 266 doc = "Unstripped binary to be returned by ", 267 ), 268 package_name = attr.string( 269 mandatory = True, 270 doc = "Just the path to the target package. Used by transitions.", 271 ), 272 _allowlist_function_transition = attr.label( 273 default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 274 ), 275) 276 277stripped_binary = rule( 278 implementation = _stripped_binary_impl, 279 cfg = drop_lto_and_sanitizer_transition, 280 attrs = _rule_attrs, 281 executable = True, 282 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], 283) 284 285stripped_test = rule( 286 implementation = _stripped_binary_impl, 287 cfg = drop_lto_and_sanitizer_transition, 288 attrs = _rule_attrs, 289 test = True, 290 toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], 291) 292