xref: /aosp_15_r20/external/bazelbuild-rules_rust/test/unit/linkstamps/linkstamps_test.bzl (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1"""Unittests for rust linkstamp support."""
2
3load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
4load("@rules_cc//cc:defs.bzl", "cc_library")
5load("//rust:defs.bzl", "rust_binary", "rust_common", "rust_library", "rust_test")
6load("//test/unit:common.bzl", "assert_action_mnemonic")
7
8def _is_running_on_linux(ctx):
9    return ctx.target_platform_has_constraint(ctx.attr._linux[platform_common.ConstraintValueInfo])
10
11def _supports_linkstamps_test(ctx):
12    env = analysistest.begin(ctx)
13    tut = analysistest.target_under_test(env)
14    if not _is_running_on_linux(ctx):
15        # Skipping linkstamps tests on an unsupported (non-Linux) platform
16        return analysistest.end(env)
17
18    linkstamp_action = tut.actions[0]
19    assert_action_mnemonic(env, linkstamp_action, "CppLinkstampCompile")
20    linkstamp_out = linkstamp_action.outputs.to_list()[0]
21    asserts.equals(env, linkstamp_out.basename, "linkstamp.o")
22    tut_out = tut.files.to_list()[0]
23    is_test = tut[rust_common.crate_info].is_test
24    workspace_prefix = "" if ctx.workspace_name == "rules_rust" else "/external/rules_rust"
25
26    # Rust compilation outputs coming from a test are put in test-{hash} directory
27    # which we need to remove in order to obtain the linkstamp file path.
28    dirname = "/".join(tut_out.dirname.split("/")[:-1]) if is_test else tut_out.dirname
29    expected_linkstamp_path = dirname + "/_objs/" + tut_out.basename + workspace_prefix + "/test/unit/linkstamps/linkstamp.o"
30    asserts.equals(
31        env,
32        linkstamp_out.path,
33        expected_linkstamp_path,
34        "Expected linkstamp output '{actual_path}' to match '{expected_path}'".format(
35            actual_path = linkstamp_out.path,
36            expected_path = expected_linkstamp_path,
37        ),
38    )
39
40    rustc_action = tut.actions[1]
41    assert_action_mnemonic(env, rustc_action, "Rustc")
42    rustc_inputs = rustc_action.inputs.to_list()
43    asserts.true(
44        env,
45        linkstamp_out in rustc_inputs,
46        "Expected linkstamp output '{output}' to be among the binary inputs '{inputs}'".format(
47            output = linkstamp_out,
48            inputs = rustc_inputs,
49        ),
50    )
51    return analysistest.end(env)
52
53supports_linkstamps_test = analysistest.make(
54    _supports_linkstamps_test,
55    attrs = {
56        "_linux": attr.label(default = Label("@platforms//os:linux")),
57    },
58)
59
60def _linkstamps_test():
61    # Native linkstamps are only supported by the builtin Linux C++ toolchain. Ideally,
62    # we would be able to inspect the feature_configuration of the target to see if
63    # it has the "linkstamp" feature, but there is no way to get that feature
64    # configuration.
65    cc_library(
66        name = "cc_lib_with_linkstamp",
67        linkstamp = select({
68            "//rust/platform:linux": "linkstamp.cc",
69            "//conditions:default": None,
70        }),
71    )
72
73    rust_binary(
74        name = "some_rust_binary",
75        srcs = ["foo.rs"],
76        edition = "2018",
77        deps = [":cc_lib_with_linkstamp"],
78    )
79
80    supports_linkstamps_test(
81        name = "rust_binary_supports_linkstamps_test",
82        target_under_test = ":some_rust_binary",
83    )
84
85    rust_library(
86        name = "some_rust_library_with_linkstamp_transitively",
87        srcs = ["foo.rs"],
88        edition = "2018",
89        deps = [":cc_lib_with_linkstamp"],
90    )
91
92    rust_binary(
93        name = "some_rust_binary_with_linkstamp_transitively",
94        srcs = ["foo.rs"],
95        edition = "2018",
96        deps = [":some_rust_library_with_linkstamp_transitively"],
97    )
98
99    supports_linkstamps_test(
100        name = "rust_binary_with_linkstamp_transitively",
101        target_under_test = ":some_rust_binary_with_linkstamp_transitively",
102    )
103
104    cc_library(
105        name = "cc_lib_with_linkstamp_transitively",
106        deps = [":cc_lib_with_linkstamp"],
107    )
108
109    rust_binary(
110        name = "some_rust_binary_with_multiple_paths_to_a_linkstamp",
111        srcs = ["foo.rs"],
112        edition = "2018",
113        deps = [":cc_lib_with_linkstamp", ":cc_lib_with_linkstamp_transitively"],
114    )
115
116    supports_linkstamps_test(
117        name = "rust_binary_supports_duplicated_linkstamps",
118        target_under_test = ":some_rust_binary_with_multiple_paths_to_a_linkstamp",
119    )
120
121    rust_test(
122        name = "some_rust_test1",
123        srcs = ["foo.rs"],
124        edition = "2018",
125        deps = [":cc_lib_with_linkstamp"],
126    )
127
128    supports_linkstamps_test(
129        name = "rust_test_supports_linkstamps_test1",
130        target_under_test = ":some_rust_test1",
131    )
132
133    rust_test(
134        name = "some_rust_test2",
135        srcs = ["foo.rs"],
136        edition = "2018",
137        deps = [":cc_lib_with_linkstamp"],
138    )
139
140    supports_linkstamps_test(
141        name = "rust_test_supports_linkstamps_test2",
142        target_under_test = ":some_rust_test2",
143    )
144
145def linkstamps_test_suite(name):
146    """Entry-point macro called from the BUILD file.
147
148    Args:
149      name: Name of the macro.
150    """
151
152    # Older versions of Bazel do not support Starlark linkstamps.
153    if not hasattr(cc_common, "register_linkstamp_compile_action"):
154        # buildifier: disable=print
155        print("Skipping linkstamps tests since this Bazel version does not support Starlark linkstamps.")
156        return
157
158    _linkstamps_test()
159
160    native.test_suite(
161        name = name,
162        tests = [
163            ":rust_binary_supports_linkstamps_test",
164            ":rust_binary_supports_duplicated_linkstamps",
165            ":rust_test_supports_linkstamps_test1",
166            ":rust_test_supports_linkstamps_test2",
167        ],
168    )
169