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