xref: /aosp_15_r20/build/bazel/toolchains/clang/host/linux-x86/cc_toolchain_clang_version_test.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
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_library_static.bzl", "cc_library_static")
17load("//build/bazel/rules/test_common:rules.bzl", "expect_failure_test")
18load(":cc_toolchain_config.bzl", "clang_version_info")
19
20def _clang_version_path_test_impl(ctx):
21    env = analysistest.begin(ctx)
22    actions = analysistest.target_actions(env)
23
24    compile_actions = [a for a in actions if a.mnemonic == "CppCompile"]
25    if len(compile_actions) != 1:
26        asserts.equals(
27            env,
28            1,
29            len(compile_actions),
30            "expected 1 compile action; found: " + str(compile_actions),
31        )
32        return analysistest.end(env)
33
34    inputs = compile_actions[0].inputs.to_list()
35    clang_binary_files = [f for f in inputs if f.short_path.endswith("clang")]
36    if len(clang_binary_files) != 1:
37        asserts.equals(
38            env,
39            1,
40            len(clang_binary_files),
41            "expected 1 clang binary file; found: " + str(clang_binary_files),
42        )
43        return analysistest.end(env)
44    clang_path = clang_binary_files[0]
45    asserts.equals(
46        env,
47        ctx.attr.expected_clang_path,
48        clang_path.path,
49        "expected clang binary path to be `%s`, but got `%s`" % (
50            ctx.attr.expected_clang_path,
51            clang_path.path,
52        ),
53    )
54
55    link_actions = [a for a in actions if a.mnemonic == "CppLink"]
56    if len(link_actions) != 1:
57        asserts.equals(
58            env,
59            1,
60            len(link_actions),
61            "expected 1 link action; found: " + str(link_actions),
62        )
63        return analysistest.end(env)
64    inputs = link_actions[0].inputs.to_list()
65
66    libclang_rt_files = [f for f in inputs if "libclang_rt" in f.short_path]
67    if len(libclang_rt_files) != 1:
68        asserts.equals(
69            env,
70            1,
71            len(libclang_rt_files),
72            "expected 1 libclang_rt file; found: " + str(libclang_rt_files),
73        )
74        return analysistest.end(env)
75    libclang_rt_path = libclang_rt_files[0]
76    asserts.equals(
77        env,
78        ctx.attr.expected_libclang_rt_path,
79        libclang_rt_path.path,
80        "expected libclang_rt path to be `%s`, but got `%s`" % (
81            ctx.attr.expected_libclang_rt_path,
82            libclang_rt_path.path,
83        ),
84    )
85
86    return analysistest.end(env)
87
88def _clang_version_path_test(clang_version, clang_short_version):
89    return analysistest.make(
90        _clang_version_path_test_impl,
91        attrs = {
92            "expected_clang_path": attr.string(
93                mandatory = True,
94            ),
95            "expected_libclang_rt_path": attr.string(
96                mandatory = True,
97            ),
98        },
99        config_settings = {
100            "@//prebuilts/clang/host/linux-x86:clang_version": clang_version,
101            "@//prebuilts/clang/host/linux-x86:clang_short_version": clang_short_version,
102        },
103    )
104
105_clang_16_0_2_path_test = _clang_version_path_test("clang-r475365b", "16.0.2")
106
107def _test_clang_version_paths(
108        os,
109        arch,
110        clang_short_version,
111        clang_version_test,
112        expected_clang_path,
113        expected_libclang_rt_builtins_path):
114    name = "clang_version_paths_%s_%s_%s" % (
115        os,
116        arch,
117        clang_short_version,
118    )
119    test_name = name + "_test"
120    native.cc_binary(
121        name = name,
122        srcs = ["a.cpp"],
123        tags = ["manual"],
124    )
125    clang_version_test(
126        name = test_name,
127        target_under_test = name,
128        expected_clang_path = expected_clang_path,
129        expected_libclang_rt_path = expected_libclang_rt_builtins_path,
130        target_compatible_with = [
131            "//build/bazel_common_rules/platforms/os:" + os,
132            "//build/bazel_common_rules/platforms/arch:" + arch,
133        ],
134    )
135    return test_name
136
137def _create_clang_version_tests():
138    test_cases = [
139        {
140            "os": "android",
141            "arch": "arm64",
142            "clang_short_version": "16.0.2",
143            "clang_version_test": _clang_16_0_2_path_test,
144            "expected_clang_path": "prebuilts/clang/host/linux-x86/clang-r475365b/bin/clang",
145            "expected_libclang_rt_builtins_path": "prebuilts/clang/host/linux-x86/clang-r475365b/lib/clang/16.0.2/lib/linux/libclang_rt.builtins-aarch64-android.a",
146        },
147    ]
148    return [
149        _test_clang_version_paths(**tc)
150        for tc in test_cases
151    ]
152
153def _filegroup_has_expected_files_test_impl(ctx):
154    env = analysistest.begin(ctx)
155    target_under_test = analysistest.target_under_test(env)
156
157    asserts.equals(
158        env,
159        ctx.attr.expected_files,
160        [f.short_path for f in target_under_test.files.to_list()],
161    )
162
163    return analysistest.end(env)
164
165def _filegroup_has_expected_files_test(clang_version, clang_short_version):
166    return analysistest.make(
167        _filegroup_has_expected_files_test_impl,
168        attrs = {
169            "expected_files": attr.string_list(
170                mandatory = True,
171            ),
172        },
173        config_settings = {
174            "@//prebuilts/clang/host/linux-x86:clang_version": clang_version,
175            "@//prebuilts/clang/host/linux-x86:clang_short_version": clang_short_version,
176        },
177    )
178
179_clang_16_0_2_filegroup_test = _filegroup_has_expected_files_test("clang-r475365b", "16.0.2")
180
181def _test_clang_version_filegroups(
182        os,
183        arch,
184        clang_short_version,
185        clang_version_filegroup_test,
186        expected_libclang_rt_builtins_path,
187        expected_libclang_rt_ubsan_minimal_path):
188    """
189    These filegroup tests should give a clearer signal if the cc_toolchain
190    fails in analysis due to missing files from these filegroups.
191    """
192    name = "clang_version_filegroups_%s_%s_%s" % (
193        os,
194        arch,
195        clang_short_version,
196    )
197    libclang_rt_builtins_test_name = name + "_test_libclang_rt_builtins"
198    libclang_rt_ubsan_minimal_test_name = name + "_test_libclang_rt_ubsan_minimal"
199
200    clang_version_filegroup_test(
201        name = libclang_rt_builtins_test_name,
202        target_under_test = "//prebuilts/clang/host/linux-x86:libclang_rt_builtins_%s_%s" % (os, arch),
203        expected_files = [expected_libclang_rt_builtins_path],
204    )
205    clang_version_filegroup_test(
206        name = libclang_rt_ubsan_minimal_test_name,
207        target_under_test = "//prebuilts/clang/host/linux-x86:libclang_rt_ubsan_minimal_%s_%s" % (os, arch),
208        expected_files = [expected_libclang_rt_ubsan_minimal_path],
209    )
210
211    return [
212        libclang_rt_builtins_test_name,
213        libclang_rt_ubsan_minimal_test_name,
214    ]
215
216def _create_clang_version_filegroup_tests():
217    test_cases = [
218        {
219            "os": "android",
220            "arch": "arm64",
221            "clang_short_version": "16.0.2",
222            "clang_version_filegroup_test": _clang_16_0_2_filegroup_test,
223            "expected_libclang_rt_builtins_path": "prebuilts/clang/host/linux-x86/clang-r475365b/lib/clang/16.0.2/lib/linux/libclang_rt.builtins-aarch64-android.a",
224            "expected_libclang_rt_ubsan_minimal_path": "prebuilts/clang/host/linux-x86/clang-r475365b/lib/clang/16.0.2/lib/linux/libclang_rt.ubsan_minimal-aarch64-android.a",
225        },
226    ]
227    return [
228        t
229        for tc in test_cases
230        for t in _test_clang_version_filegroups(**tc)
231    ]
232
233def _test_clang_version_errors_for_missing_files(clang_version, clang_short_version):
234    name = "clang_version_errors_for_missing_files_%s-%s" % (
235        clang_version,
236        clang_short_version,
237    )
238    test_name = name + "_test"
239
240    clang_version_info(
241        name = name,
242        clang_files = native.glob(["**/*"]),
243        clang_short_version = clang_short_version,
244        clang_version = clang_version,
245        tags = ["manual"],
246    )
247    expect_failure_test(
248        name = test_name,
249        target_under_test = name,
250        failure_message = "rule '//build/bazel/toolchains/clang/host/linux-x86:NOT-A-VERSION' does not exist",
251    )
252    return test_name
253
254def _create_clang_version_missing_file_tests():
255    test_cases = [
256        {
257            "clang_version": "r487747",
258            "clang_short_version": "NOT-A-VERSION",
259        },
260        {
261            "clang_version": "NOT-A-VERSION",
262            "clang_short_version": "16.0.2",
263        },
264    ]
265    return [
266        _test_clang_version_errors_for_missing_files(**tc)
267        for tc in test_cases
268    ]
269
270def cc_toolchain_clang_version_test_suite(name):
271    native.test_suite(
272        name = name,
273        tests = (
274            _create_clang_version_tests() +
275            _create_clang_version_filegroup_tests() +
276            _create_clang_version_missing_file_tests()
277        ),
278    )
279