1# Copyright (C) 2022 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//lib:unittest.bzl", "analysistest", "asserts") 16load(":cc_binary.bzl", "cc_binary") 17load(":cc_library_common_test.bzl", "target_provides_androidmk_info_test") 18load(":cc_library_shared.bzl", "cc_library_shared") 19load(":cc_library_static.bzl", "cc_library_static") 20 21def strip_test_assert_flags(env, strip_action, strip_flags): 22 # Extract these flags from strip_action (for example): 23 # build/soong/scripts/strip.sh --keep-symbols --add-gnu-debuglink -i <in> -o <out> -d <out>.d 24 # ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ 25 flag_start_idx = 1 # starts after the strip.sh executable 26 flag_end_idx = strip_action.argv.index("-i") # end of the flags 27 asserts.equals( 28 env, 29 strip_action.argv[flag_start_idx:flag_end_idx], 30 strip_flags, 31 ) 32 33def _cc_binary_strip_test(ctx): 34 env = analysistest.begin(ctx) 35 actions = analysistest.target_actions(env) 36 filtered_actions = [a for a in actions if a.mnemonic == "CcStrip"] 37 on_target = ctx.target_platform_has_constraint( 38 ctx.attr._android_constraint[platform_common.ConstraintValueInfo], 39 ) 40 if ctx.attr.strip_flags or on_target: 41 # expected to find strip flags, so look for a CcStrip action. 42 asserts.true( 43 env, 44 len(filtered_actions) == 1, 45 "expected to find an action with CcStrip mnemonic in %s" % actions, 46 ) 47 if ctx.attr.strip_flags or not on_target: 48 strip_test_assert_flags(env, filtered_actions[0], ctx.attr.strip_flags) 49 return analysistest.end(env) 50 else: 51 asserts.true( 52 env, 53 len(filtered_actions) == 0, 54 "expected to not find an action with CcStrip mnemonic in %s" % actions, 55 ) 56 return analysistest.end(env) 57 58cc_binary_strip_test = analysistest.make( 59 _cc_binary_strip_test, 60 attrs = { 61 "strip_flags": attr.string_list(), 62 "_android_constraint": attr.label(default = Label("//build/bazel_common_rules/platforms/os:android")), 63 }, 64) 65 66def _cc_binary_strip_default(): 67 name = "cc_binary_strip_default" 68 test_name = name + "_test" 69 70 cc_binary( 71 name = name, 72 srcs = ["main.cc"], 73 tags = ["manual"], 74 ) 75 76 cc_binary_strip_test( 77 name = test_name, 78 target_under_test = name, 79 strip_flags = [], 80 ) 81 82 return test_name 83 84def _cc_binary_strip_keep_symbols(): 85 name = "cc_binary_strip_keep_symbols" 86 test_name = name + "_test" 87 88 cc_binary( 89 name = name, 90 srcs = ["main.cc"], 91 tags = ["manual"], 92 strip = {"keep_symbols": True}, 93 ) 94 95 cc_binary_strip_test( 96 name = test_name, 97 target_under_test = name, 98 strip_flags = [ 99 "--keep-symbols", 100 "--add-gnu-debuglink", 101 ], 102 ) 103 104 return test_name 105 106def _cc_binary_strip_keep_symbols_and_debug_frame(): 107 name = "cc_binary_strip_keep_symbols_and_debug_frame" 108 test_name = name + "_test" 109 110 cc_binary( 111 name = name, 112 srcs = ["main.cc"], 113 tags = ["manual"], 114 strip = {"keep_symbols_and_debug_frame": True}, 115 ) 116 117 cc_binary_strip_test( 118 name = test_name, 119 target_under_test = name, 120 strip_flags = [ 121 "--keep-symbols-and-debug-frame", 122 "--add-gnu-debuglink", 123 ], 124 ) 125 126 return test_name 127 128def _cc_binary_strip_keep_symbols_list(): 129 name = "cc_binary_strip_keep_symbols_list" 130 test_name = name + "_test" 131 132 cc_binary( 133 name = name, 134 srcs = ["main.cc"], 135 tags = ["manual"], 136 strip = {"keep_symbols_list": ["foo", "bar"]}, 137 ) 138 139 cc_binary_strip_test( 140 name = test_name, 141 target_under_test = name, 142 strip_flags = [ 143 "-kfoo,bar", 144 "--add-gnu-debuglink", 145 ], 146 ) 147 148 return test_name 149 150def _cc_binary_strip_all(): 151 name = "cc_binary_strip_all" 152 test_name = name + "_test" 153 154 cc_binary( 155 name = name, 156 srcs = ["main.cc"], 157 tags = ["manual"], 158 strip = {"all": True}, 159 ) 160 161 cc_binary_strip_test( 162 name = test_name, 163 target_under_test = name, 164 strip_flags = [ 165 "--add-gnu-debuglink", 166 ], 167 ) 168 169 return test_name 170 171def _cc_binary_suffix_test_impl(ctx): 172 env = analysistest.begin(ctx) 173 target = analysistest.target_under_test(env) 174 info = target[DefaultInfo] 175 suffix = ctx.attr.suffix 176 177 outputs = info.files.to_list() 178 asserts.true( 179 env, 180 len(outputs) == 1, 181 "Expected 1 output file; got %s" % outputs, 182 ) 183 out = outputs[0] 184 asserts.true( 185 env, 186 out.path.endswith(suffix), 187 "Expected output filename to end in `%s`; it was instead %s" % (suffix, out), 188 ) 189 190 if ctx.attr.stem: 191 asserts.equals( 192 env, 193 out.basename, 194 ctx.attr.stem, 195 "Expected output filename %s to be equal to `stem` attribute %s" % (out, ctx.attr.stem), 196 ) 197 198 return analysistest.end(env) 199 200cc_binary_suffix_test = analysistest.make( 201 _cc_binary_suffix_test_impl, 202 attrs = { 203 "stem": attr.string(), 204 "suffix": attr.string(), 205 }, 206) 207 208def _cc_binary_suffix(): 209 name = "cc_binary_suffix" 210 test_name = name + "_test" 211 suffix = "-suf" 212 213 cc_binary( 214 name, 215 srcs = ["src.cc"], 216 tags = ["manual"], 217 suffix = suffix, 218 ) 219 cc_binary_suffix_test( 220 name = test_name, 221 target_under_test = name, 222 suffix = suffix, 223 ) 224 return test_name 225 226def _cc_binary_empty_suffix(): 227 name = "cc_binary_empty_suffix" 228 test_name = name + "_test" 229 230 cc_binary( 231 name, 232 srcs = ["src.cc"], 233 tags = ["manual"], 234 ) 235 cc_binary_suffix_test( 236 name = test_name, 237 target_under_test = name, 238 ) 239 return test_name 240 241def _cc_binary_with_stem(): 242 name = "cc_binary_with_stem" 243 test_name = name + "_test" 244 245 cc_binary( 246 name, 247 srcs = ["src.cc"], 248 stem = "bar", 249 tags = ["manual"], 250 ) 251 cc_binary_suffix_test( 252 name = test_name, 253 stem = "bar", 254 target_under_test = name, 255 ) 256 return test_name 257 258def _cc_binary_provides_androidmk_info(): 259 name = "cc_binary_provides_androidmk_info" 260 dep_name = name + "_static_dep" 261 whole_archive_dep_name = name + "_whole_archive_dep" 262 dynamic_dep_name = name + "_dynamic_dep" 263 test_name = name + "_test" 264 265 cc_library_static( 266 name = dep_name, 267 srcs = ["foo.c"], 268 tags = ["manual"], 269 ) 270 cc_library_static( 271 name = whole_archive_dep_name, 272 srcs = ["foo.c"], 273 tags = ["manual"], 274 ) 275 cc_library_shared( 276 name = dynamic_dep_name, 277 srcs = ["foo.c"], 278 tags = ["manual"], 279 ) 280 cc_binary( 281 name = name, 282 srcs = ["foo.cc"], 283 deps = [dep_name], 284 whole_archive_deps = [whole_archive_dep_name], 285 dynamic_deps = [dynamic_dep_name], 286 tags = ["manual"], 287 ) 288 android_test_name = test_name + "_android" 289 linux_test_name = test_name + "_linux" 290 target_provides_androidmk_info_test( 291 name = android_test_name, 292 target_under_test = name, 293 expected_static_libs = [dep_name, "libc++demangle", "libunwind"], 294 expected_whole_static_libs = [whole_archive_dep_name], 295 expected_shared_libs = [dynamic_dep_name, "libc++", "libc_stub_libs-current", "libdl_stub_libs-current", "libm_stub_libs-current"], 296 target_compatible_with = ["//build/bazel_common_rules/platforms/os:android"], 297 ) 298 target_provides_androidmk_info_test( 299 name = linux_test_name, 300 target_under_test = name, 301 expected_static_libs = [dep_name], 302 expected_whole_static_libs = [whole_archive_dep_name], 303 expected_shared_libs = [dynamic_dep_name, "libc++"], 304 target_compatible_with = ["//build/bazel_common_rules/platforms/os:linux"], 305 ) 306 return [ 307 android_test_name, 308 linux_test_name, 309 ] 310 311def _cc_bad_linkopts_test_impl(ctx): 312 env = analysistest.begin(ctx) 313 if ctx.target_platform_has_constraint(ctx.attr._android_constraint[platform_common.ConstraintValueInfo]): 314 asserts.expect_failure(env, "Library requested via -l is not supported for device builds. Use implementation_deps instead.") 315 else: 316 asserts.expect_failure(env, "Host library(s) requested via -l is not available in the toolchain.") 317 return analysistest.end(env) 318 319cc_bad_linkopts_test = analysistest.make( 320 _cc_bad_linkopts_test_impl, 321 expect_failure = True, 322 attrs = { 323 "_android_constraint": attr.label( 324 default = Label("//build/bazel_common_rules/platforms/os:android"), 325 ), 326 }, 327) 328 329# Test that an error is raised if a user requests a library that is not available in the toolchain. 330def _cc_binary_bad_linkopts(): 331 subject_name = "cc_binary_bad_linkopts" 332 test_name = subject_name + "_test" 333 334 cc_binary( 335 name = subject_name, 336 linkopts = ["-lunknown"], 337 tags = ["manual"], 338 ) 339 cc_bad_linkopts_test( 340 name = test_name, 341 target_under_test = subject_name, 342 ) 343 return test_name 344 345def cc_binary_test_suite(name): 346 native.test_suite( 347 name = name, 348 tests = [ 349 _cc_binary_strip_default(), 350 _cc_binary_strip_keep_symbols(), 351 _cc_binary_strip_keep_symbols_and_debug_frame(), 352 _cc_binary_strip_keep_symbols_list(), 353 _cc_binary_strip_all(), 354 _cc_binary_suffix(), 355 _cc_binary_empty_suffix(), 356 _cc_binary_with_stem(), 357 _cc_binary_bad_linkopts(), 358 ] + _cc_binary_provides_androidmk_info(), 359 ) 360