1"""Unittests for rust rules.""" 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_proc_macro", "rust_shared_library", "rust_static_library") 6 7def _is_dylib_on_windows(ctx): 8 return ctx.target_platform_has_constraint(ctx.attr._windows[platform_common.ConstraintValueInfo]) 9 10def _assert_cc_info_has_library_to_link(env, tut, type, ccinfo_count): 11 asserts.true(env, CcInfo in tut, "rust_library should provide CcInfo") 12 cc_info = tut[CcInfo] 13 linker_inputs = cc_info.linking_context.linker_inputs.to_list() 14 asserts.equals(env, ccinfo_count, len(linker_inputs)) 15 library_to_link = linker_inputs[0].libraries[0] 16 asserts.equals(env, False, library_to_link.alwayslink) 17 18 asserts.equals(env, [], library_to_link.lto_bitcode_files) 19 asserts.equals(env, [], library_to_link.pic_lto_bitcode_files) 20 21 asserts.equals(env, [], library_to_link.objects) 22 asserts.equals(env, [], library_to_link.pic_objects) 23 24 if type == "cdylib": 25 asserts.true(env, library_to_link.dynamic_library != None) 26 if _is_dylib_on_windows(env.ctx): 27 asserts.true(env, library_to_link.interface_library != None) 28 asserts.true(env, library_to_link.resolved_symlink_dynamic_library == None) 29 else: 30 asserts.equals(env, None, library_to_link.interface_library) 31 asserts.true(env, library_to_link.resolved_symlink_dynamic_library != None) 32 asserts.equals(env, None, library_to_link.resolved_symlink_interface_library) 33 asserts.equals(env, None, library_to_link.static_library) 34 asserts.equals(env, None, library_to_link.pic_static_library) 35 else: 36 asserts.equals(env, None, library_to_link.dynamic_library) 37 asserts.equals(env, None, library_to_link.interface_library) 38 asserts.equals(env, None, library_to_link.resolved_symlink_dynamic_library) 39 asserts.equals(env, None, library_to_link.resolved_symlink_interface_library) 40 asserts.true(env, library_to_link.static_library != None) 41 if type in ("rlib", "lib"): 42 asserts.true(env, library_to_link.static_library.basename.startswith("lib" + tut.label.name)) 43 asserts.true(env, library_to_link.pic_static_library != None) 44 asserts.equals(env, library_to_link.static_library, library_to_link.pic_static_library) 45 46def _collect_user_link_flags(env, tut): 47 asserts.true(env, CcInfo in tut, "rust_library should provide CcInfo") 48 cc_info = tut[CcInfo] 49 linker_inputs = cc_info.linking_context.linker_inputs.to_list() 50 return [f for i in linker_inputs for f in i.user_link_flags] 51 52def _rlib_provides_cc_info_test_impl(ctx): 53 env = analysistest.begin(ctx) 54 tut = analysistest.target_under_test(env) 55 _assert_cc_info_has_library_to_link(env, tut, "rlib", 4) 56 return analysistest.end(env) 57 58def _rlib_with_dep_only_has_stdlib_linkflags_once_test_impl(ctx): 59 env = analysistest.begin(ctx) 60 tut = analysistest.target_under_test(env) 61 user_link_flags = _collect_user_link_flags(env, tut) 62 asserts.equals( 63 env, 64 depset(user_link_flags).to_list(), 65 user_link_flags, 66 "user_link_flags_should_not_have_duplicates_here", 67 ) 68 return analysistest.end(env) 69 70def _bin_does_not_provide_cc_info_test_impl(ctx): 71 env = analysistest.begin(ctx) 72 tut = analysistest.target_under_test(env) 73 asserts.false(env, CcInfo in tut, "rust_binary should not provide CcInfo") 74 return analysistest.end(env) 75 76def _proc_macro_does_not_provide_cc_info_test_impl(ctx): 77 env = analysistest.begin(ctx) 78 tut = analysistest.target_under_test(env) 79 asserts.false(env, CcInfo in tut, "rust_proc_macro should not provide CcInfo") 80 return analysistest.end(env) 81 82def _cdylib_provides_cc_info_test_impl(ctx): 83 env = analysistest.begin(ctx) 84 tut = analysistest.target_under_test(env) 85 _assert_cc_info_has_library_to_link(env, tut, "cdylib", 2) 86 return analysistest.end(env) 87 88def _staticlib_provides_cc_info_test_impl(ctx): 89 env = analysistest.begin(ctx) 90 tut = analysistest.target_under_test(env) 91 _assert_cc_info_has_library_to_link(env, tut, "staticlib", 2) 92 return analysistest.end(env) 93 94def _crate_group_info_provides_cc_info_test_impl(ctx): 95 env = analysistest.begin(ctx) 96 tut = analysistest.target_under_test(env) 97 asserts.true( 98 env, 99 len(tut[rust_common.dep_info].transitive_noncrates.to_list()) == 1, 100 "crate_group_info should provide 1 non-crate transitive dependency", 101 ) 102 return analysistest.end(env) 103 104rlib_provides_cc_info_test = analysistest.make(_rlib_provides_cc_info_test_impl) 105rlib_with_dep_only_has_stdlib_linkflags_once_test = analysistest.make( 106 _rlib_with_dep_only_has_stdlib_linkflags_once_test_impl, 107) 108bin_does_not_provide_cc_info_test = analysistest.make(_bin_does_not_provide_cc_info_test_impl) 109staticlib_provides_cc_info_test = analysistest.make(_staticlib_provides_cc_info_test_impl) 110cdylib_provides_cc_info_test = analysistest.make(_cdylib_provides_cc_info_test_impl, attrs = { 111 "_windows": attr.label(default = Label("@platforms//os:windows")), 112}) 113proc_macro_does_not_provide_cc_info_test = analysistest.make(_proc_macro_does_not_provide_cc_info_test_impl) 114 115crate_group_info_provides_cc_info_test = analysistest.make(_crate_group_info_provides_cc_info_test_impl) 116 117def _rust_cc_injection_impl(ctx): 118 dep_variant_info = rust_common.dep_variant_info( 119 cc_info = ctx.attr.cc_dep[CcInfo], 120 crate_info = None, 121 dep_info = None, 122 ) 123 return [ 124 rust_common.crate_group_info( 125 dep_variant_infos = depset([dep_variant_info]), 126 ), 127 ] 128 129rust_cc_injection = rule( 130 attrs = { 131 "cc_dep": attr.label( 132 providers = [CcInfo], 133 ), 134 }, 135 implementation = _rust_cc_injection_impl, 136) 137 138def _cc_info_test(): 139 rust_library( 140 name = "rlib", 141 srcs = ["foo.rs"], 142 edition = "2018", 143 ) 144 145 rust_library( 146 name = "rlib_with_dep", 147 srcs = ["foo.rs"], 148 edition = "2018", 149 deps = [":rlib"], 150 ) 151 152 rust_binary( 153 name = "bin", 154 srcs = ["foo.rs"], 155 edition = "2018", 156 ) 157 158 rust_static_library( 159 name = "staticlib", 160 srcs = ["foo.rs"], 161 edition = "2018", 162 ) 163 164 rust_shared_library( 165 name = "cdylib", 166 srcs = ["foo.rs"], 167 edition = "2018", 168 ) 169 170 rust_proc_macro( 171 name = "proc_macro", 172 srcs = ["proc_macro.rs"], 173 edition = "2018", 174 deps = ["//test/unit/native_deps:native_dep"], 175 ) 176 177 cc_library( 178 name = "cc_lib", 179 srcs = ["foo.cc"], 180 ) 181 182 rust_cc_injection( 183 name = "cc_lib_injected", 184 cc_dep = ":cc_lib", 185 ) 186 187 rust_library( 188 name = "rust_lib_with_cc_lib_injected", 189 srcs = ["foo.rs"], 190 deps = [":cc_lib_injected"], 191 edition = "2018", 192 ) 193 194 rlib_provides_cc_info_test( 195 name = "rlib_provides_cc_info_test", 196 target_under_test = ":rlib", 197 ) 198 rlib_with_dep_only_has_stdlib_linkflags_once_test( 199 name = "rlib_with_dep_only_has_stdlib_linkflags_once_test", 200 target_under_test = ":rlib_with_dep", 201 ) 202 bin_does_not_provide_cc_info_test( 203 name = "bin_does_not_provide_cc_info_test", 204 target_under_test = ":bin", 205 ) 206 cdylib_provides_cc_info_test( 207 name = "cdylib_provides_cc_info_test", 208 target_under_test = ":cdylib", 209 ) 210 staticlib_provides_cc_info_test( 211 name = "staticlib_provides_cc_info_test", 212 target_under_test = ":staticlib", 213 ) 214 proc_macro_does_not_provide_cc_info_test( 215 name = "proc_macro_does_not_provide_cc_info_test", 216 target_under_test = ":proc_macro", 217 ) 218 crate_group_info_provides_cc_info_test( 219 name = "crate_group_info_provides_cc_info_test", 220 target_under_test = ":rust_lib_with_cc_lib_injected", 221 ) 222 223def cc_info_test_suite(name): 224 """Entry-point macro called from the BUILD file. 225 226 Args: 227 name: Name of the macro. 228 """ 229 _cc_info_test() 230 231 native.test_suite( 232 name = name, 233 tests = [ 234 ":rlib_provides_cc_info_test", 235 ":rlib_with_dep_only_has_stdlib_linkflags_once_test", 236 ":staticlib_provides_cc_info_test", 237 ":cdylib_provides_cc_info_test", 238 ":proc_macro_does_not_provide_cc_info_test", 239 ":bin_does_not_provide_cc_info_test", 240 ":crate_group_info_provides_cc_info_test", 241 ], 242 ) 243