1# Copyright (C) 2023 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("//build/bazel/rules/cc:cc_binary.bzl", "cc_binary") 17load("//build/bazel/rules/cc:cc_library_shared.bzl", "cc_library_shared") 18load("//build/bazel/rules/cc:cc_library_static.bzl", "cc_library_static") 19load( 20 "//build/bazel/rules/cc/testing:transitions.bzl", 21 "ActionArgsInfo", 22 "compile_action_argv_aspect_generator", 23) 24 25lto_flag = "-flto=thin" 26static_cpp_suffix = "_cpp" 27shared_cpp_suffix = "__internal_root_cpp" 28binary_suffix = "__internal_root" 29 30def _lto_deps_test_impl(ctx): 31 env = analysistest.begin(ctx) 32 target_under_test = analysistest.target_under_test(env) 33 argv_map = target_under_test[ActionArgsInfo].argv_map 34 35 for target in ctx.attr.targets_with_lto: 36 asserts.true( 37 env, 38 target in argv_map, 39 "can't find {} in argv map".format(target), 40 ) 41 if target in argv_map: 42 argv = argv_map[target] 43 asserts.true( 44 env, 45 lto_flag in argv, 46 "Compile action of {} didn't have LTO but it was expected".format( 47 target, 48 ), 49 ) 50 for target in ctx.attr.targets_without_lto: 51 asserts.true( 52 env, 53 target in argv_map, 54 "can't find {} in argv map".format(target), 55 ) 56 if target in argv_map: 57 argv = argv_map[target] 58 asserts.true( 59 env, 60 lto_flag not in argv, 61 "Compile action of {} had LTO but it wasn't expected".format( 62 target, 63 ), 64 ) 65 return analysistest.end(env) 66 67_compile_action_argv_aspect = compile_action_argv_aspect_generator({ 68 "_cc_library_combiner": ["deps", "roots", "includes"], 69 "_cc_includes": ["deps"], 70 "_cc_library_shared_proxy": ["deps"], 71 "stripped_binary": ["androidmk_deps"], 72}) 73 74lto_deps_test = analysistest.make( 75 _lto_deps_test_impl, 76 attrs = { 77 "targets_with_lto": attr.string_list(), 78 "targets_without_lto": attr.string_list(), 79 }, 80 # We need to use aspect to examine the dependencies' actions of the apex 81 # target as the result of the transition, checking the dependencies directly 82 # using names will give you the info before the transition takes effect. 83 extra_target_under_test_aspects = [_compile_action_argv_aspect], 84) 85 86def _test_static_deps_have_lto(): 87 name = "static_deps_have_lto" 88 requested_target_name = name + "_requested_target" 89 static_dep_name = name + "_static_dep" 90 static_dep_of_static_dep_name = "_static_dep_of_static_dep" 91 test_name = name + "_test" 92 93 cc_library_static( 94 name = requested_target_name, 95 srcs = ["foo.cpp"], 96 deps = [static_dep_name], 97 features = ["android_thin_lto"], 98 tags = ["manual"], 99 ) 100 101 cc_library_static( 102 name = static_dep_name, 103 srcs = ["bar.cpp"], 104 deps = [static_dep_of_static_dep_name], 105 tags = ["manual"], 106 ) 107 108 cc_library_static( 109 name = static_dep_of_static_dep_name, 110 srcs = ["baz.cpp"], 111 tags = ["manual"], 112 ) 113 114 lto_deps_test( 115 name = test_name, 116 target_under_test = requested_target_name, 117 targets_with_lto = [ 118 requested_target_name + static_cpp_suffix, 119 static_dep_name + static_cpp_suffix, 120 static_dep_of_static_dep_name + static_cpp_suffix, 121 ], 122 targets_without_lto = [], 123 ) 124 125 return test_name 126 127def _test_deps_of_shared_have_lto_if_enabled(): 128 name = "deps_of_shared_have_lto_if_enabled" 129 requested_target_name = name + "_requested_target" 130 shared_dep_name = name + "_shared_dep" 131 static_dep_of_shared_dep_name = name + "_static_dep_of_shared_dep" 132 test_name = name + "_test" 133 134 cc_library_static( 135 name = requested_target_name, 136 srcs = ["foo.cpp"], 137 dynamic_deps = [shared_dep_name], 138 tags = ["manual"], 139 ) 140 141 cc_library_shared( 142 name = shared_dep_name, 143 srcs = ["bar.cpp"], 144 deps = [static_dep_of_shared_dep_name], 145 features = ["android_thin_lto"], 146 tags = ["manual"], 147 ) 148 149 cc_library_static( 150 name = static_dep_of_shared_dep_name, 151 srcs = ["baz.cpp"], 152 tags = ["manual"], 153 ) 154 155 lto_deps_test( 156 name = test_name, 157 target_under_test = requested_target_name, 158 targets_with_lto = [ 159 shared_dep_name + "__internal_root_cpp", 160 static_dep_of_shared_dep_name + static_cpp_suffix, 161 ], 162 targets_without_lto = [requested_target_name + static_cpp_suffix], 163 ) 164 165 return test_name 166 167def _test_deps_of_shared_deps_no_lto_if_disabled(): 168 name = "deps_of_shared_deps_no_lto_if_disabled" 169 requested_target_name = name + "_requested_target" 170 shared_dep_name = name + "_shared_dep" 171 static_dep_of_shared_dep_name = name + "_static_dep_of_shared_dep" 172 test_name = name + "_test" 173 174 cc_library_static( 175 name = requested_target_name, 176 srcs = ["foo.cpp"], 177 dynamic_deps = [shared_dep_name], 178 features = ["android_thin_lto"], 179 tags = ["manual"], 180 ) 181 182 cc_library_shared( 183 name = shared_dep_name, 184 srcs = ["bar.cpp"], 185 deps = [static_dep_of_shared_dep_name], 186 tags = ["manual"], 187 ) 188 189 cc_library_static( 190 name = static_dep_of_shared_dep_name, 191 srcs = ["baz.cpp"], 192 tags = ["manual"], 193 ) 194 195 lto_deps_test( 196 name = test_name, 197 target_under_test = requested_target_name, 198 targets_with_lto = [requested_target_name + static_cpp_suffix], 199 targets_without_lto = [ 200 shared_dep_name + shared_cpp_suffix, 201 static_dep_of_shared_dep_name + static_cpp_suffix, 202 ], 203 ) 204 205 return test_name 206 207def _test_binary_propagates_to_static_deps(): 208 name = "binary_propagates_to_static_deps" 209 requested_target_name = name + "_requested_target" 210 dep_name = name + "_dep" 211 test_name = name + "_test" 212 213 cc_binary( 214 name = requested_target_name, 215 srcs = ["foo.cpp"], 216 deps = [dep_name], 217 features = ["android_thin_lto"], 218 tags = ["manual"], 219 ) 220 221 cc_library_static( 222 name = dep_name, 223 srcs = ["bar.cpp"], 224 tags = ["manual"], 225 ) 226 227 lto_deps_test( 228 name = test_name, 229 target_under_test = requested_target_name, 230 targets_with_lto = [ 231 requested_target_name + binary_suffix + static_cpp_suffix, 232 dep_name + static_cpp_suffix, 233 ], 234 ) 235 236 return test_name 237 238def lto_transition_test_suite(name): 239 native.test_suite( 240 name = name, 241 tests = [ 242 _test_static_deps_have_lto(), 243 _test_deps_of_shared_have_lto_if_enabled(), 244 _test_deps_of_shared_deps_no_lto_if_disabled(), 245 _test_binary_propagates_to_static_deps(), 246 ], 247 ) 248