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