1"""End to end tests for rust toolchains.""" 2 3load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") 4load("@bazel_skylib//rules:write_file.bzl", "write_file") 5load("//rust:defs.bzl", "rust_library", "rust_shared_library") 6load("//rust:toolchain.bzl", "rust_stdlib_filegroup", "rust_toolchain") 7 8EXEC_TOOLCHAIN_FLAG = "missing" 9TOOLCHAIN_FLAG = "before" 10CONFIG_FLAG = "after" 11CRATE_FLAGS = {"cdylib": ["cdylib_flag"], "rlib": ["rlib_flag"]} 12 13def _toolchain_adds_rustc_flags_impl(ctx, crate_type): 14 """ Tests adding extra_rustc_flags on the toolchain, asserts that: 15 16 - extra_rustc_flags added by the toolchain are applied BEFORE flags added by a config on the commandline 17 - The exec flags from the toolchain don't go on the commandline for a non-exec target 18 - crate type rustc flags are added 19 """ 20 env = analysistest.begin(ctx) 21 target = analysistest.target_under_test(env) 22 action = target[DepActionsInfo].actions[0] 23 24 asserts.equals(env, "Rustc", action.mnemonic) 25 26 asserts.true( 27 env, 28 action.argv[-2:] == [TOOLCHAIN_FLAG, CONFIG_FLAG], 29 "Unexpected rustc flags: {}\nShould have ended with: {}".format( 30 action.argv, 31 [TOOLCHAIN_FLAG, CONFIG_FLAG], 32 ), 33 ) 34 35 asserts.true( 36 env, 37 action.argv[-3] == CRATE_FLAGS[crate_type][0], 38 "Unexpected rustc flags: {}\nShould have contained: {}".format( 39 action.argv, 40 CRATE_FLAGS["rlib"], 41 ), 42 ) 43 44 for type in CRATE_FLAGS.keys(): 45 if type == crate_type: 46 continue 47 asserts.false( 48 env, 49 CRATE_FLAGS[type][0] in action.argv, 50 "Unexpected rustc flags: {}\nShould not contain: {}".format( 51 action.argv, 52 CRATE_FLAGS[type], 53 ), 54 ) 55 56 asserts.true( 57 env, 58 EXEC_TOOLCHAIN_FLAG not in action.argv, 59 "Found exec toolchain flag ({}) in rustc flags: {}".format(EXEC_TOOLCHAIN_FLAG, action.argv), 60 ) 61 62 found_sysroot = False 63 for arg in action.argv: 64 if arg.startswith("--sysroot") and arg.endswith("test/toolchain/rust_extra_flags_toolchain"): 65 found_sysroot = True 66 asserts.true( 67 env, 68 found_sysroot, 69 "Missing --sysroot flag or --sysroot does not point to correct sysroot directory", 70 ) 71 72 return analysistest.end(env) 73 74def _toolchain_adds_rustc_flags_lib_impl(ctx): 75 return _toolchain_adds_rustc_flags_impl(ctx, "rlib") 76 77def _toolchain_adds_rustc_flags_shared_lib_impl(ctx): 78 return _toolchain_adds_rustc_flags_impl(ctx, "cdylib") 79 80toolchain_adds_rustc_flags_lib_test = analysistest.make( 81 _toolchain_adds_rustc_flags_lib_impl, 82 config_settings = { 83 str(Label("//:extra_rustc_flags")): [CONFIG_FLAG], 84 str(Label("//rust/settings:experimental_toolchain_generated_sysroot")): True, 85 }, 86) 87 88toolchain_adds_rustc_flags_shared_lib_test = analysistest.make( 89 _toolchain_adds_rustc_flags_shared_lib_impl, 90 config_settings = { 91 str(Label("//:extra_rustc_flags")): [CONFIG_FLAG], 92 str(Label("//rust/settings:experimental_toolchain_generated_sysroot")): True, 93 }, 94) 95 96def _extra_toolchain_transition_impl(settings, _attr): 97 return {"//command_line_option:extra_toolchains": [ 98 "@rules_rust//test/toolchain:extra_flags_toolchain", 99 ] + settings["//command_line_option:extra_toolchains"]} 100 101_extra_toolchain_transition = transition( 102 implementation = _extra_toolchain_transition_impl, 103 inputs = ["//command_line_option:extra_toolchains"], 104 outputs = ["//command_line_option:extra_toolchains"], 105) 106 107DepActionsInfo = provider( 108 "Contains information about dependencies actions.", 109 fields = {"actions": "List[Action]"}, 110) 111 112def _collect_dep_actions_aspect_impl(target, ctx): 113 actions = [] 114 actions.extend(target.actions) 115 for dep in ctx.rule.attr.deps: 116 actions.extend(dep[DepActionsInfo].actions) 117 return [DepActionsInfo(actions = actions)] 118 119collect_dep_actions_aspect = aspect( 120 implementation = _collect_dep_actions_aspect_impl, 121 attr_aspects = ["deps"], 122) 123 124def _extra_toolchain_wrapper_impl(ctx): 125 return [ctx.attr.dep[DepActionsInfo]] 126 127extra_toolchain_wrapper = rule( 128 implementation = _extra_toolchain_wrapper_impl, 129 attrs = { 130 "dep": attr.label(aspects = [collect_dep_actions_aspect]), 131 "_allowlist_function_transition": attr.label( 132 default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 133 ), 134 }, 135 cfg = _extra_toolchain_transition, 136) 137 138def _define_targets(): 139 rust_library( 140 name = "lib", 141 srcs = ["lib.rs"], 142 edition = "2021", 143 ) 144 145 rust_shared_library( 146 name = "shared_lib", 147 srcs = ["lib.rs"], 148 edition = "2021", 149 ) 150 151 native.filegroup( 152 name = "stdlib_srcs", 153 srcs = ["config.txt"], 154 ) 155 rust_stdlib_filegroup( 156 name = "std_libs", 157 srcs = [":stdlib_srcs"], 158 ) 159 write_file( 160 name = "mock_rustc", 161 out = "mock_rustc.exe", 162 content = [], 163 is_executable = True, 164 ) 165 write_file( 166 name = "mock_rustdoc", 167 out = "mock_rustdoc.exe", 168 content = [], 169 is_executable = True, 170 ) 171 172 rust_toolchain( 173 name = "rust_extra_flags_toolchain", 174 binary_ext = "", 175 dylib_ext = ".so", 176 exec_triple = "x86_64-unknown-none", 177 target_triple = "x86_64-unknown-none", 178 rust_doc = ":mock_rustdoc", 179 rust_std = ":std_libs", 180 rustc = ":mock_rustc", 181 staticlib_ext = ".a", 182 stdlib_linkflags = [], 183 extra_rustc_flags = [TOOLCHAIN_FLAG], 184 extra_exec_rustc_flags = [EXEC_TOOLCHAIN_FLAG], 185 extra_rustc_flags_for_crate_types = CRATE_FLAGS, 186 visibility = ["//visibility:public"], 187 ) 188 189 native.toolchain( 190 name = "extra_flags_toolchain", 191 toolchain = ":rust_extra_flags_toolchain", 192 toolchain_type = "@rules_rust//rust:toolchain", 193 ) 194 195 extra_toolchain_wrapper( 196 name = "lib_with_extra_toolchain", 197 dep = ":lib", 198 ) 199 200 extra_toolchain_wrapper( 201 name = "shared_lib_with_extra_toolchain", 202 dep = ":shared_lib", 203 ) 204 205def _rust_stdlib_filegroup_provides_runfiles_test_impl(ctx): 206 env = analysistest.begin(ctx) 207 target = analysistest.target_under_test(env) 208 runfiles = target[DefaultInfo].default_runfiles 209 asserts.true(env, len(runfiles.files.to_list()) > 0) 210 211 return analysistest.end(env) 212 213rust_stdlib_filegroup_provides_runfiles_test = analysistest.make( 214 _rust_stdlib_filegroup_provides_runfiles_test_impl, 215) 216 217def toolchain_test_suite(name): 218 """ Instantiates tests for rust toolchains. 219 220 Args: 221 name: a name for the test suite 222 """ 223 _define_targets() 224 225 toolchain_adds_rustc_flags_lib_test( 226 name = "toolchain_adds_rustc_flags_lib_test", 227 target_under_test = ":lib_with_extra_toolchain", 228 ) 229 230 toolchain_adds_rustc_flags_shared_lib_test( 231 name = "toolchain_adds_rustc_flags_shared_lib_test", 232 target_under_test = ":shared_lib_with_extra_toolchain", 233 ) 234 235 rust_stdlib_filegroup_provides_runfiles_test( 236 name = "rust_stdlib_filegroup_provides_runfiles_test", 237 target_under_test = ":std_libs", 238 ) 239 240 native.test_suite( 241 name = name, 242 tests = [ 243 ":toolchain_adds_rustc_flags_lib_test", 244 ":toolchain_adds_rustc_flags_shared_lib_test", 245 ":rust_stdlib_filegroup_provides_runfiles_test", 246 ], 247 ) 248