1*d4726bddSHONG Yifan# Copyright 2015 The Bazel Authors. All rights reserved. 2*d4726bddSHONG Yifan# 3*d4726bddSHONG Yifan# Licensed under the Apache License, Version 2.0 (the "License"); 4*d4726bddSHONG Yifan# you may not use this file except in compliance with the License. 5*d4726bddSHONG Yifan# You may obtain a copy of the License at 6*d4726bddSHONG Yifan# 7*d4726bddSHONG Yifan# http://www.apache.org/licenses/LICENSE-2.0 8*d4726bddSHONG Yifan# 9*d4726bddSHONG Yifan# Unless required by applicable law or agreed to in writing, software 10*d4726bddSHONG Yifan# distributed under the License is distributed on an "AS IS" BASIS, 11*d4726bddSHONG Yifan# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*d4726bddSHONG Yifan# See the License for the specific language governing permissions and 13*d4726bddSHONG Yifan# limitations under the License. 14*d4726bddSHONG Yifan 15*d4726bddSHONG Yifan"""Rust rule implementations""" 16*d4726bddSHONG Yifan 17*d4726bddSHONG Yifanload("@bazel_skylib//lib:paths.bzl", "paths") 18*d4726bddSHONG Yifanload("//rust/private:common.bzl", "COMMON_PROVIDERS", "rust_common") 19*d4726bddSHONG Yifanload("//rust/private:providers.bzl", "BuildInfo") 20*d4726bddSHONG Yifanload("//rust/private:rustc.bzl", "rustc_compile_action") 21*d4726bddSHONG Yifanload( 22*d4726bddSHONG Yifan "//rust/private:utils.bzl", 23*d4726bddSHONG Yifan "can_build_metadata", 24*d4726bddSHONG Yifan "compute_crate_name", 25*d4726bddSHONG Yifan "crate_root_src", 26*d4726bddSHONG Yifan "dedent", 27*d4726bddSHONG Yifan "determine_lib_name", 28*d4726bddSHONG Yifan "determine_output_hash", 29*d4726bddSHONG Yifan "expand_dict_value_locations", 30*d4726bddSHONG Yifan "find_toolchain", 31*d4726bddSHONG Yifan "generate_output_diagnostics", 32*d4726bddSHONG Yifan "get_edition", 33*d4726bddSHONG Yifan "get_import_macro_deps", 34*d4726bddSHONG Yifan "transform_deps", 35*d4726bddSHONG Yifan "transform_sources", 36*d4726bddSHONG Yifan) 37*d4726bddSHONG Yifan 38*d4726bddSHONG Yifan# TODO(marco): Separate each rule into its own file. 39*d4726bddSHONG Yifan 40*d4726bddSHONG Yifandef _assert_no_deprecated_attributes(_ctx): 41*d4726bddSHONG Yifan """Forces a failure if any deprecated attributes were specified 42*d4726bddSHONG Yifan 43*d4726bddSHONG Yifan Args: 44*d4726bddSHONG Yifan _ctx (ctx): The current rule's context object 45*d4726bddSHONG Yifan """ 46*d4726bddSHONG Yifan pass 47*d4726bddSHONG Yifan 48*d4726bddSHONG Yifandef _assert_correct_dep_mapping(ctx): 49*d4726bddSHONG Yifan """Forces a failure if proc_macro_deps and deps are mixed inappropriately 50*d4726bddSHONG Yifan 51*d4726bddSHONG Yifan Args: 52*d4726bddSHONG Yifan ctx (ctx): The current rule's context object 53*d4726bddSHONG Yifan """ 54*d4726bddSHONG Yifan for dep in ctx.attr.deps: 55*d4726bddSHONG Yifan if rust_common.crate_info in dep: 56*d4726bddSHONG Yifan if dep[rust_common.crate_info].type == "proc-macro": 57*d4726bddSHONG Yifan fail( 58*d4726bddSHONG Yifan "{} listed {} in its deps, but it is a proc-macro. It should instead be in the bazel property proc_macro_deps.".format( 59*d4726bddSHONG Yifan ctx.label, 60*d4726bddSHONG Yifan dep.label, 61*d4726bddSHONG Yifan ), 62*d4726bddSHONG Yifan ) 63*d4726bddSHONG Yifan for dep in ctx.attr.proc_macro_deps: 64*d4726bddSHONG Yifan type = dep[rust_common.crate_info].type 65*d4726bddSHONG Yifan if type != "proc-macro": 66*d4726bddSHONG Yifan fail( 67*d4726bddSHONG Yifan "{} listed {} in its proc_macro_deps, but it is not proc-macro, it is a {}. It should probably instead be listed in deps.".format( 68*d4726bddSHONG Yifan ctx.label, 69*d4726bddSHONG Yifan dep.label, 70*d4726bddSHONG Yifan type, 71*d4726bddSHONG Yifan ), 72*d4726bddSHONG Yifan ) 73*d4726bddSHONG Yifan 74*d4726bddSHONG Yifandef _rust_library_impl(ctx): 75*d4726bddSHONG Yifan """The implementation of the `rust_library` rule. 76*d4726bddSHONG Yifan 77*d4726bddSHONG Yifan This rule provides CcInfo, so it can be used everywhere Bazel 78*d4726bddSHONG Yifan expects rules_cc, but care must be taken to have the correct 79*d4726bddSHONG Yifan dependencies on an allocator and std implemetation as needed. 80*d4726bddSHONG Yifan 81*d4726bddSHONG Yifan Args: 82*d4726bddSHONG Yifan ctx (ctx): The rule's context object 83*d4726bddSHONG Yifan 84*d4726bddSHONG Yifan Returns: 85*d4726bddSHONG Yifan list: A list of providers. 86*d4726bddSHONG Yifan """ 87*d4726bddSHONG Yifan return _rust_library_common(ctx, "rlib") 88*d4726bddSHONG Yifan 89*d4726bddSHONG Yifandef _rust_static_library_impl(ctx): 90*d4726bddSHONG Yifan """The implementation of the `rust_static_library` rule. 91*d4726bddSHONG Yifan 92*d4726bddSHONG Yifan This rule provides CcInfo, so it can be used everywhere Bazel 93*d4726bddSHONG Yifan expects rules_cc. 94*d4726bddSHONG Yifan 95*d4726bddSHONG Yifan Args: 96*d4726bddSHONG Yifan ctx (ctx): The rule's context object 97*d4726bddSHONG Yifan 98*d4726bddSHONG Yifan Returns: 99*d4726bddSHONG Yifan list: A list of providers. 100*d4726bddSHONG Yifan """ 101*d4726bddSHONG Yifan return _rust_library_common(ctx, "staticlib") 102*d4726bddSHONG Yifan 103*d4726bddSHONG Yifandef _rust_shared_library_impl(ctx): 104*d4726bddSHONG Yifan """The implementation of the `rust_shared_library` rule. 105*d4726bddSHONG Yifan 106*d4726bddSHONG Yifan This rule provides CcInfo, so it can be used everywhere Bazel 107*d4726bddSHONG Yifan expects rules_cc. 108*d4726bddSHONG Yifan 109*d4726bddSHONG Yifan On Windows, a PDB file containing debugging information is available under 110*d4726bddSHONG Yifan the key `pdb_file` in `OutputGroupInfo`. Similarly on macOS, a dSYM folder 111*d4726bddSHONG Yifan is available under the key `dsym_folder` in `OutputGroupInfo`. 112*d4726bddSHONG Yifan 113*d4726bddSHONG Yifan Args: 114*d4726bddSHONG Yifan ctx (ctx): The rule's context object 115*d4726bddSHONG Yifan 116*d4726bddSHONG Yifan Returns: 117*d4726bddSHONG Yifan list: A list of providers. 118*d4726bddSHONG Yifan """ 119*d4726bddSHONG Yifan return _rust_library_common(ctx, "cdylib") 120*d4726bddSHONG Yifan 121*d4726bddSHONG Yifandef _rust_proc_macro_impl(ctx): 122*d4726bddSHONG Yifan """The implementation of the `rust_proc_macro` rule. 123*d4726bddSHONG Yifan 124*d4726bddSHONG Yifan Args: 125*d4726bddSHONG Yifan ctx (ctx): The rule's context object 126*d4726bddSHONG Yifan 127*d4726bddSHONG Yifan Returns: 128*d4726bddSHONG Yifan list: A list of providers. 129*d4726bddSHONG Yifan """ 130*d4726bddSHONG Yifan return _rust_library_common(ctx, "proc-macro") 131*d4726bddSHONG Yifan 132*d4726bddSHONG Yifandef _rust_library_common(ctx, crate_type): 133*d4726bddSHONG Yifan """The common implementation of the library-like rules. 134*d4726bddSHONG Yifan 135*d4726bddSHONG Yifan Args: 136*d4726bddSHONG Yifan ctx (ctx): The rule's context object 137*d4726bddSHONG Yifan crate_type (String): one of lib|rlib|dylib|staticlib|cdylib|proc-macro 138*d4726bddSHONG Yifan 139*d4726bddSHONG Yifan Returns: 140*d4726bddSHONG Yifan list: A list of providers. See `rustc_compile_action` 141*d4726bddSHONG Yifan """ 142*d4726bddSHONG Yifan _assert_no_deprecated_attributes(ctx) 143*d4726bddSHONG Yifan _assert_correct_dep_mapping(ctx) 144*d4726bddSHONG Yifan 145*d4726bddSHONG Yifan toolchain = find_toolchain(ctx) 146*d4726bddSHONG Yifan 147*d4726bddSHONG Yifan crate_name = compute_crate_name(ctx.workspace_name, ctx.label, toolchain, ctx.attr.crate_name) 148*d4726bddSHONG Yifan 149*d4726bddSHONG Yifan crate_root = getattr(ctx.file, "crate_root", None) 150*d4726bddSHONG Yifan if not crate_root: 151*d4726bddSHONG Yifan crate_root = crate_root_src(ctx.attr.name, ctx.files.srcs, crate_type) 152*d4726bddSHONG Yifan srcs, crate_root = transform_sources(ctx, ctx.files.srcs, crate_root) 153*d4726bddSHONG Yifan 154*d4726bddSHONG Yifan # Determine unique hash for this rlib. 155*d4726bddSHONG Yifan # Note that we don't include a hash for `cdylib` and `staticlib` since they are meant to be consumed externally 156*d4726bddSHONG Yifan # and having a deterministic name is important since it ends up embedded in the executable. This is problematic 157*d4726bddSHONG Yifan # when one needs to include the library with a specific filename into a larger application. 158*d4726bddSHONG Yifan # (see https://github.com/bazelbuild/rules_rust/issues/405#issuecomment-993089889 for more details) 159*d4726bddSHONG Yifan if crate_type in ["cdylib", "staticlib"]: 160*d4726bddSHONG Yifan output_hash = None 161*d4726bddSHONG Yifan else: 162*d4726bddSHONG Yifan output_hash = determine_output_hash(crate_root, ctx.label) 163*d4726bddSHONG Yifan 164*d4726bddSHONG Yifan rust_lib_name = determine_lib_name( 165*d4726bddSHONG Yifan crate_name, 166*d4726bddSHONG Yifan crate_type, 167*d4726bddSHONG Yifan toolchain, 168*d4726bddSHONG Yifan output_hash, 169*d4726bddSHONG Yifan ) 170*d4726bddSHONG Yifan rust_lib = ctx.actions.declare_file(rust_lib_name) 171*d4726bddSHONG Yifan rust_metadata = None 172*d4726bddSHONG Yifan rustc_rmeta_output = None 173*d4726bddSHONG Yifan if can_build_metadata(toolchain, ctx, crate_type) and not ctx.attr.disable_pipelining: 174*d4726bddSHONG Yifan rust_metadata = ctx.actions.declare_file( 175*d4726bddSHONG Yifan paths.replace_extension(rust_lib_name, ".rmeta"), 176*d4726bddSHONG Yifan sibling = rust_lib, 177*d4726bddSHONG Yifan ) 178*d4726bddSHONG Yifan rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) 179*d4726bddSHONG Yifan 180*d4726bddSHONG Yifan deps = transform_deps(ctx.attr.deps) 181*d4726bddSHONG Yifan proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx)) 182*d4726bddSHONG Yifan 183*d4726bddSHONG Yifan return rustc_compile_action( 184*d4726bddSHONG Yifan ctx = ctx, 185*d4726bddSHONG Yifan attr = ctx.attr, 186*d4726bddSHONG Yifan toolchain = toolchain, 187*d4726bddSHONG Yifan output_hash = output_hash, 188*d4726bddSHONG Yifan crate_info_dict = dict( 189*d4726bddSHONG Yifan name = crate_name, 190*d4726bddSHONG Yifan type = crate_type, 191*d4726bddSHONG Yifan root = crate_root, 192*d4726bddSHONG Yifan srcs = depset(srcs), 193*d4726bddSHONG Yifan deps = depset(deps), 194*d4726bddSHONG Yifan proc_macro_deps = depset(proc_macro_deps), 195*d4726bddSHONG Yifan aliases = ctx.attr.aliases, 196*d4726bddSHONG Yifan output = rust_lib, 197*d4726bddSHONG Yifan rustc_output = generate_output_diagnostics(ctx, rust_lib), 198*d4726bddSHONG Yifan metadata = rust_metadata, 199*d4726bddSHONG Yifan rustc_rmeta_output = rustc_rmeta_output, 200*d4726bddSHONG Yifan edition = get_edition(ctx.attr, toolchain, ctx.label), 201*d4726bddSHONG Yifan rustc_env = ctx.attr.rustc_env, 202*d4726bddSHONG Yifan rustc_env_files = ctx.files.rustc_env_files, 203*d4726bddSHONG Yifan is_test = False, 204*d4726bddSHONG Yifan data = depset(ctx.files.data), 205*d4726bddSHONG Yifan compile_data = depset(ctx.files.compile_data), 206*d4726bddSHONG Yifan compile_data_targets = depset(ctx.attr.compile_data), 207*d4726bddSHONG Yifan owner = ctx.label, 208*d4726bddSHONG Yifan ), 209*d4726bddSHONG Yifan ) 210*d4726bddSHONG Yifan 211*d4726bddSHONG Yifandef _rust_binary_impl(ctx): 212*d4726bddSHONG Yifan """The implementation of the `rust_binary` rule 213*d4726bddSHONG Yifan 214*d4726bddSHONG Yifan Args: 215*d4726bddSHONG Yifan ctx (ctx): The rule's context object 216*d4726bddSHONG Yifan 217*d4726bddSHONG Yifan Returns: 218*d4726bddSHONG Yifan list: A list of providers. See `rustc_compile_action` 219*d4726bddSHONG Yifan """ 220*d4726bddSHONG Yifan toolchain = find_toolchain(ctx) 221*d4726bddSHONG Yifan crate_name = compute_crate_name(ctx.workspace_name, ctx.label, toolchain, ctx.attr.crate_name) 222*d4726bddSHONG Yifan _assert_correct_dep_mapping(ctx) 223*d4726bddSHONG Yifan 224*d4726bddSHONG Yifan output = ctx.actions.declare_file(ctx.label.name + toolchain.binary_ext) 225*d4726bddSHONG Yifan 226*d4726bddSHONG Yifan deps = transform_deps(ctx.attr.deps) 227*d4726bddSHONG Yifan proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx)) 228*d4726bddSHONG Yifan 229*d4726bddSHONG Yifan crate_root = getattr(ctx.file, "crate_root", None) 230*d4726bddSHONG Yifan if not crate_root: 231*d4726bddSHONG Yifan crate_root = crate_root_src(ctx.attr.name, ctx.files.srcs, ctx.attr.crate_type) 232*d4726bddSHONG Yifan srcs, crate_root = transform_sources(ctx, ctx.files.srcs, crate_root) 233*d4726bddSHONG Yifan 234*d4726bddSHONG Yifan providers = rustc_compile_action( 235*d4726bddSHONG Yifan ctx = ctx, 236*d4726bddSHONG Yifan attr = ctx.attr, 237*d4726bddSHONG Yifan toolchain = toolchain, 238*d4726bddSHONG Yifan crate_info_dict = dict( 239*d4726bddSHONG Yifan name = crate_name, 240*d4726bddSHONG Yifan type = ctx.attr.crate_type, 241*d4726bddSHONG Yifan root = crate_root, 242*d4726bddSHONG Yifan srcs = depset(srcs), 243*d4726bddSHONG Yifan deps = depset(deps), 244*d4726bddSHONG Yifan proc_macro_deps = depset(proc_macro_deps), 245*d4726bddSHONG Yifan aliases = ctx.attr.aliases, 246*d4726bddSHONG Yifan output = output, 247*d4726bddSHONG Yifan rustc_output = generate_output_diagnostics(ctx, output), 248*d4726bddSHONG Yifan edition = get_edition(ctx.attr, toolchain, ctx.label), 249*d4726bddSHONG Yifan rustc_env = ctx.attr.rustc_env, 250*d4726bddSHONG Yifan rustc_env_files = ctx.files.rustc_env_files, 251*d4726bddSHONG Yifan is_test = False, 252*d4726bddSHONG Yifan data = depset(ctx.files.data), 253*d4726bddSHONG Yifan compile_data = depset(ctx.files.compile_data), 254*d4726bddSHONG Yifan compile_data_targets = depset(ctx.attr.compile_data), 255*d4726bddSHONG Yifan owner = ctx.label, 256*d4726bddSHONG Yifan ), 257*d4726bddSHONG Yifan ) 258*d4726bddSHONG Yifan 259*d4726bddSHONG Yifan providers.append(RunEnvironmentInfo( 260*d4726bddSHONG Yifan environment = expand_dict_value_locations( 261*d4726bddSHONG Yifan ctx, 262*d4726bddSHONG Yifan ctx.attr.env, 263*d4726bddSHONG Yifan ctx.attr.data, 264*d4726bddSHONG Yifan ), 265*d4726bddSHONG Yifan )) 266*d4726bddSHONG Yifan 267*d4726bddSHONG Yifan return providers 268*d4726bddSHONG Yifan 269*d4726bddSHONG Yifandef get_rust_test_flags(attr): 270*d4726bddSHONG Yifan """Determine the desired rustc flags for test targets. 271*d4726bddSHONG Yifan 272*d4726bddSHONG Yifan Args: 273*d4726bddSHONG Yifan attr (dict): Attributes of a rule 274*d4726bddSHONG Yifan 275*d4726bddSHONG Yifan Returns: 276*d4726bddSHONG Yifan List: A list of test flags 277*d4726bddSHONG Yifan """ 278*d4726bddSHONG Yifan if getattr(attr, "use_libtest_harness", True): 279*d4726bddSHONG Yifan rust_flags = ["--test"] 280*d4726bddSHONG Yifan else: 281*d4726bddSHONG Yifan rust_flags = ["--cfg", "test"] 282*d4726bddSHONG Yifan 283*d4726bddSHONG Yifan return rust_flags 284*d4726bddSHONG Yifan 285*d4726bddSHONG Yifandef _rust_test_impl(ctx): 286*d4726bddSHONG Yifan """The implementation of the `rust_test` rule. 287*d4726bddSHONG Yifan 288*d4726bddSHONG Yifan Args: 289*d4726bddSHONG Yifan ctx (ctx): The ctx object for the current target. 290*d4726bddSHONG Yifan 291*d4726bddSHONG Yifan Returns: 292*d4726bddSHONG Yifan list: The list of providers. See `rustc_compile_action` 293*d4726bddSHONG Yifan """ 294*d4726bddSHONG Yifan _assert_no_deprecated_attributes(ctx) 295*d4726bddSHONG Yifan _assert_correct_dep_mapping(ctx) 296*d4726bddSHONG Yifan 297*d4726bddSHONG Yifan toolchain = find_toolchain(ctx) 298*d4726bddSHONG Yifan 299*d4726bddSHONG Yifan crate_type = "bin" 300*d4726bddSHONG Yifan deps = transform_deps(ctx.attr.deps) 301*d4726bddSHONG Yifan proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx)) 302*d4726bddSHONG Yifan 303*d4726bddSHONG Yifan if ctx.attr.crate and ctx.attr.srcs: 304*d4726bddSHONG Yifan fail("rust_test.crate and rust_test.srcs are mutually exclusive. Update {} to use only one of these attributes".format( 305*d4726bddSHONG Yifan ctx.label, 306*d4726bddSHONG Yifan )) 307*d4726bddSHONG Yifan 308*d4726bddSHONG Yifan if ctx.attr.crate: 309*d4726bddSHONG Yifan # Target is building the crate in `test` config 310*d4726bddSHONG Yifan crate = ctx.attr.crate[rust_common.crate_info] if rust_common.crate_info in ctx.attr.crate else ctx.attr.crate[rust_common.test_crate_info].crate 311*d4726bddSHONG Yifan 312*d4726bddSHONG Yifan output_hash = determine_output_hash(crate.root, ctx.label) 313*d4726bddSHONG Yifan output = ctx.actions.declare_file( 314*d4726bddSHONG Yifan "test-%s/%s%s" % ( 315*d4726bddSHONG Yifan output_hash, 316*d4726bddSHONG Yifan ctx.label.name, 317*d4726bddSHONG Yifan toolchain.binary_ext, 318*d4726bddSHONG Yifan ), 319*d4726bddSHONG Yifan ) 320*d4726bddSHONG Yifan 321*d4726bddSHONG Yifan srcs, crate_root = transform_sources(ctx, ctx.files.srcs, getattr(ctx.file, "crate_root", None)) 322*d4726bddSHONG Yifan 323*d4726bddSHONG Yifan # Optionally join compile data 324*d4726bddSHONG Yifan if crate.compile_data: 325*d4726bddSHONG Yifan compile_data = depset(ctx.files.compile_data, transitive = [crate.compile_data]) 326*d4726bddSHONG Yifan else: 327*d4726bddSHONG Yifan compile_data = depset(ctx.files.compile_data) 328*d4726bddSHONG Yifan if crate.compile_data_targets: 329*d4726bddSHONG Yifan compile_data_targets = depset(ctx.attr.compile_data, transitive = [crate.compile_data_targets]) 330*d4726bddSHONG Yifan else: 331*d4726bddSHONG Yifan compile_data_targets = depset(ctx.attr.compile_data) 332*d4726bddSHONG Yifan rustc_env_files = ctx.files.rustc_env_files + crate.rustc_env_files 333*d4726bddSHONG Yifan 334*d4726bddSHONG Yifan # crate.rustc_env is already expanded upstream in rust_library rule implementation 335*d4726bddSHONG Yifan rustc_env = dict(crate.rustc_env) 336*d4726bddSHONG Yifan data_paths = depset(direct = getattr(ctx.attr, "data", [])).to_list() 337*d4726bddSHONG Yifan rustc_env.update(expand_dict_value_locations( 338*d4726bddSHONG Yifan ctx, 339*d4726bddSHONG Yifan ctx.attr.rustc_env, 340*d4726bddSHONG Yifan data_paths, 341*d4726bddSHONG Yifan )) 342*d4726bddSHONG Yifan 343*d4726bddSHONG Yifan # Build the test binary using the dependency's srcs. 344*d4726bddSHONG Yifan crate_info_dict = dict( 345*d4726bddSHONG Yifan name = crate.name, 346*d4726bddSHONG Yifan type = crate_type, 347*d4726bddSHONG Yifan root = crate.root, 348*d4726bddSHONG Yifan srcs = depset(srcs, transitive = [crate.srcs]), 349*d4726bddSHONG Yifan deps = depset(deps, transitive = [crate.deps]), 350*d4726bddSHONG Yifan proc_macro_deps = depset(proc_macro_deps, transitive = [crate.proc_macro_deps]), 351*d4726bddSHONG Yifan aliases = ctx.attr.aliases, 352*d4726bddSHONG Yifan output = output, 353*d4726bddSHONG Yifan rustc_output = generate_output_diagnostics(ctx, output), 354*d4726bddSHONG Yifan edition = crate.edition, 355*d4726bddSHONG Yifan rustc_env = rustc_env, 356*d4726bddSHONG Yifan rustc_env_files = rustc_env_files, 357*d4726bddSHONG Yifan is_test = True, 358*d4726bddSHONG Yifan compile_data = compile_data, 359*d4726bddSHONG Yifan compile_data_targets = compile_data_targets, 360*d4726bddSHONG Yifan wrapped_crate_type = crate.type, 361*d4726bddSHONG Yifan owner = ctx.label, 362*d4726bddSHONG Yifan ) 363*d4726bddSHONG Yifan else: 364*d4726bddSHONG Yifan crate_root = getattr(ctx.file, "crate_root", None) 365*d4726bddSHONG Yifan 366*d4726bddSHONG Yifan if not crate_root: 367*d4726bddSHONG Yifan crate_root_type = "lib" if ctx.attr.use_libtest_harness else "bin" 368*d4726bddSHONG Yifan crate_root = crate_root_src(ctx.attr.name, ctx.files.srcs, crate_root_type) 369*d4726bddSHONG Yifan srcs, crate_root = transform_sources(ctx, ctx.files.srcs, crate_root) 370*d4726bddSHONG Yifan 371*d4726bddSHONG Yifan output_hash = determine_output_hash(crate_root, ctx.label) 372*d4726bddSHONG Yifan output = ctx.actions.declare_file( 373*d4726bddSHONG Yifan "test-%s/%s%s" % ( 374*d4726bddSHONG Yifan output_hash, 375*d4726bddSHONG Yifan ctx.label.name, 376*d4726bddSHONG Yifan toolchain.binary_ext, 377*d4726bddSHONG Yifan ), 378*d4726bddSHONG Yifan ) 379*d4726bddSHONG Yifan 380*d4726bddSHONG Yifan data_paths = depset(direct = getattr(ctx.attr, "data", [])).to_list() 381*d4726bddSHONG Yifan rustc_env = expand_dict_value_locations( 382*d4726bddSHONG Yifan ctx, 383*d4726bddSHONG Yifan ctx.attr.rustc_env, 384*d4726bddSHONG Yifan data_paths, 385*d4726bddSHONG Yifan ) 386*d4726bddSHONG Yifan 387*d4726bddSHONG Yifan # Target is a standalone crate. Build the test binary as its own crate. 388*d4726bddSHONG Yifan crate_info_dict = dict( 389*d4726bddSHONG Yifan name = compute_crate_name(ctx.workspace_name, ctx.label, toolchain, ctx.attr.crate_name), 390*d4726bddSHONG Yifan type = crate_type, 391*d4726bddSHONG Yifan root = crate_root, 392*d4726bddSHONG Yifan srcs = depset(srcs), 393*d4726bddSHONG Yifan deps = depset(deps), 394*d4726bddSHONG Yifan proc_macro_deps = depset(proc_macro_deps), 395*d4726bddSHONG Yifan aliases = ctx.attr.aliases, 396*d4726bddSHONG Yifan output = output, 397*d4726bddSHONG Yifan rustc_output = generate_output_diagnostics(ctx, output), 398*d4726bddSHONG Yifan edition = get_edition(ctx.attr, toolchain, ctx.label), 399*d4726bddSHONG Yifan rustc_env = rustc_env, 400*d4726bddSHONG Yifan rustc_env_files = ctx.files.rustc_env_files, 401*d4726bddSHONG Yifan is_test = True, 402*d4726bddSHONG Yifan compile_data = depset(ctx.files.compile_data), 403*d4726bddSHONG Yifan compile_data_targets = depset(ctx.attr.compile_data), 404*d4726bddSHONG Yifan owner = ctx.label, 405*d4726bddSHONG Yifan ) 406*d4726bddSHONG Yifan 407*d4726bddSHONG Yifan providers = rustc_compile_action( 408*d4726bddSHONG Yifan ctx = ctx, 409*d4726bddSHONG Yifan attr = ctx.attr, 410*d4726bddSHONG Yifan toolchain = toolchain, 411*d4726bddSHONG Yifan crate_info_dict = crate_info_dict, 412*d4726bddSHONG Yifan rust_flags = get_rust_test_flags(ctx.attr), 413*d4726bddSHONG Yifan skip_expanding_rustc_env = True, 414*d4726bddSHONG Yifan ) 415*d4726bddSHONG Yifan data = getattr(ctx.attr, "data", []) 416*d4726bddSHONG Yifan 417*d4726bddSHONG Yifan env = expand_dict_value_locations( 418*d4726bddSHONG Yifan ctx, 419*d4726bddSHONG Yifan getattr(ctx.attr, "env", {}), 420*d4726bddSHONG Yifan data, 421*d4726bddSHONG Yifan ) 422*d4726bddSHONG Yifan if toolchain.llvm_cov and ctx.configuration.coverage_enabled: 423*d4726bddSHONG Yifan if not toolchain.llvm_profdata: 424*d4726bddSHONG Yifan fail("toolchain.llvm_profdata is required if toolchain.llvm_cov is set.") 425*d4726bddSHONG Yifan 426*d4726bddSHONG Yifan if toolchain._experimental_use_coverage_metadata_files: 427*d4726bddSHONG Yifan llvm_cov_path = toolchain.llvm_cov.path 428*d4726bddSHONG Yifan llvm_profdata_path = toolchain.llvm_profdata.path 429*d4726bddSHONG Yifan else: 430*d4726bddSHONG Yifan llvm_cov_path = toolchain.llvm_cov.short_path 431*d4726bddSHONG Yifan if llvm_cov_path.startswith("../"): 432*d4726bddSHONG Yifan llvm_cov_path = llvm_cov_path[len("../"):] 433*d4726bddSHONG Yifan 434*d4726bddSHONG Yifan llvm_profdata_path = toolchain.llvm_profdata.short_path 435*d4726bddSHONG Yifan if llvm_profdata_path.startswith("../"): 436*d4726bddSHONG Yifan llvm_profdata_path = llvm_profdata_path[len("../"):] 437*d4726bddSHONG Yifan 438*d4726bddSHONG Yifan env["RUST_LLVM_COV"] = llvm_cov_path 439*d4726bddSHONG Yifan env["RUST_LLVM_PROFDATA"] = llvm_profdata_path 440*d4726bddSHONG Yifan components = "{}/{}".format(ctx.label.workspace_root, ctx.label.package).split("/") 441*d4726bddSHONG Yifan env["CARGO_MANIFEST_DIR"] = "/".join([c for c in components if c]) 442*d4726bddSHONG Yifan providers.append(testing.TestEnvironment(env)) 443*d4726bddSHONG Yifan 444*d4726bddSHONG Yifan return providers 445*d4726bddSHONG Yifan 446*d4726bddSHONG Yifandef _rust_library_group_impl(ctx): 447*d4726bddSHONG Yifan dep_variant_infos = [] 448*d4726bddSHONG Yifan dep_variant_transitive_infos = [] 449*d4726bddSHONG Yifan runfiles = [] 450*d4726bddSHONG Yifan 451*d4726bddSHONG Yifan for dep in ctx.attr.deps: 452*d4726bddSHONG Yifan if rust_common.crate_info in dep: 453*d4726bddSHONG Yifan dep_variant_infos.append(rust_common.dep_variant_info( 454*d4726bddSHONG Yifan crate_info = dep[rust_common.crate_info] if rust_common.crate_info in dep else None, 455*d4726bddSHONG Yifan dep_info = dep[rust_common.dep_info] if rust_common.crate_info in dep else None, 456*d4726bddSHONG Yifan build_info = dep[BuildInfo] if BuildInfo in dep else None, 457*d4726bddSHONG Yifan cc_info = dep[CcInfo] if CcInfo in dep else None, 458*d4726bddSHONG Yifan crate_group_info = None, 459*d4726bddSHONG Yifan )) 460*d4726bddSHONG Yifan elif rust_common.crate_group_info in dep: 461*d4726bddSHONG Yifan dep_variant_transitive_infos.append(dep[rust_common.crate_group_info].dep_variant_infos) 462*d4726bddSHONG Yifan else: 463*d4726bddSHONG Yifan fail("crate_group_info targets can only depend on rust_library or rust_library_group targets.") 464*d4726bddSHONG Yifan 465*d4726bddSHONG Yifan if dep[DefaultInfo].default_runfiles != None: 466*d4726bddSHONG Yifan runfiles.append(dep[DefaultInfo].default_runfiles) 467*d4726bddSHONG Yifan 468*d4726bddSHONG Yifan return [ 469*d4726bddSHONG Yifan rust_common.crate_group_info( 470*d4726bddSHONG Yifan dep_variant_infos = depset(dep_variant_infos, transitive = dep_variant_transitive_infos), 471*d4726bddSHONG Yifan ), 472*d4726bddSHONG Yifan DefaultInfo(runfiles = ctx.runfiles().merge_all(runfiles)), 473*d4726bddSHONG Yifan coverage_common.instrumented_files_info( 474*d4726bddSHONG Yifan ctx, 475*d4726bddSHONG Yifan dependency_attributes = ["deps"], 476*d4726bddSHONG Yifan ), 477*d4726bddSHONG Yifan ] 478*d4726bddSHONG Yifan 479*d4726bddSHONG Yifandef _stamp_attribute(default_value): 480*d4726bddSHONG Yifan return attr.int( 481*d4726bddSHONG Yifan doc = dedent("""\ 482*d4726bddSHONG Yifan Whether to encode build information into the `Rustc` action. Possible values: 483*d4726bddSHONG Yifan 484*d4726bddSHONG Yifan - `stamp = 1`: Always stamp the build information into the `Rustc` action, even in \ 485*d4726bddSHONG Yifan [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. \ 486*d4726bddSHONG Yifan This setting should be avoided, since it potentially kills remote caching for the target and \ 487*d4726bddSHONG Yifan any downstream actions that depend on it. 488*d4726bddSHONG Yifan 489*d4726bddSHONG Yifan - `stamp = 0`: Always replace build information by constant values. This gives good build result caching. 490*d4726bddSHONG Yifan 491*d4726bddSHONG Yifan - `stamp = -1`: Embedding of build information is controlled by the \ 492*d4726bddSHONG Yifan [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag. 493*d4726bddSHONG Yifan 494*d4726bddSHONG Yifan Stamped targets are not rebuilt unless their dependencies change. 495*d4726bddSHONG Yifan 496*d4726bddSHONG Yifan For example if a `rust_library` is stamped, and a `rust_binary` depends on that library, the stamped 497*d4726bddSHONG Yifan library won't be rebuilt when we change sources of the `rust_binary`. This is different from how 498*d4726bddSHONG Yifan [`cc_library.linkstamps`](https://docs.bazel.build/versions/main/be/c-cpp.html#cc_library.linkstamp) 499*d4726bddSHONG Yifan behaves. 500*d4726bddSHONG Yifan """), 501*d4726bddSHONG Yifan default = default_value, 502*d4726bddSHONG Yifan values = [1, 0, -1], 503*d4726bddSHONG Yifan ) 504*d4726bddSHONG Yifan 505*d4726bddSHONG Yifan# Internal attributes core to Rustc actions. 506*d4726bddSHONG YifanRUSTC_ATTRS = { 507*d4726bddSHONG Yifan "_cc_toolchain": attr.label( 508*d4726bddSHONG Yifan doc = ( 509*d4726bddSHONG Yifan "In order to use find_cc_toolchain, your rule has to depend " + 510*d4726bddSHONG Yifan "on C++ toolchain. See `@rules_cc//cc:find_cc_toolchain.bzl` " + 511*d4726bddSHONG Yifan "docs for details." 512*d4726bddSHONG Yifan ), 513*d4726bddSHONG Yifan default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), 514*d4726bddSHONG Yifan ), 515*d4726bddSHONG Yifan "_error_format": attr.label( 516*d4726bddSHONG Yifan default = Label("//:error_format"), 517*d4726bddSHONG Yifan ), 518*d4726bddSHONG Yifan "_extra_exec_rustc_flag": attr.label( 519*d4726bddSHONG Yifan default = Label("//:extra_exec_rustc_flag"), 520*d4726bddSHONG Yifan ), 521*d4726bddSHONG Yifan "_extra_exec_rustc_flags": attr.label( 522*d4726bddSHONG Yifan default = Label("//:extra_exec_rustc_flags"), 523*d4726bddSHONG Yifan ), 524*d4726bddSHONG Yifan "_extra_rustc_flag": attr.label( 525*d4726bddSHONG Yifan default = Label("//:extra_rustc_flag"), 526*d4726bddSHONG Yifan ), 527*d4726bddSHONG Yifan "_extra_rustc_flags": attr.label( 528*d4726bddSHONG Yifan default = Label("//:extra_rustc_flags"), 529*d4726bddSHONG Yifan ), 530*d4726bddSHONG Yifan "_is_proc_macro_dep": attr.label( 531*d4726bddSHONG Yifan default = Label("//rust/private:is_proc_macro_dep"), 532*d4726bddSHONG Yifan ), 533*d4726bddSHONG Yifan "_is_proc_macro_dep_enabled": attr.label( 534*d4726bddSHONG Yifan default = Label("//rust/private:is_proc_macro_dep_enabled"), 535*d4726bddSHONG Yifan ), 536*d4726bddSHONG Yifan "_per_crate_rustc_flag": attr.label( 537*d4726bddSHONG Yifan default = Label("//:experimental_per_crate_rustc_flag"), 538*d4726bddSHONG Yifan ), 539*d4726bddSHONG Yifan "_process_wrapper": attr.label( 540*d4726bddSHONG Yifan doc = "A process wrapper for running rustc on all platforms.", 541*d4726bddSHONG Yifan default = Label("//util/process_wrapper"), 542*d4726bddSHONG Yifan executable = True, 543*d4726bddSHONG Yifan allow_single_file = True, 544*d4726bddSHONG Yifan cfg = "exec", 545*d4726bddSHONG Yifan ), 546*d4726bddSHONG Yifan "_rustc_output_diagnostics": attr.label( 547*d4726bddSHONG Yifan default = Label("//:rustc_output_diagnostics"), 548*d4726bddSHONG Yifan ), 549*d4726bddSHONG Yifan} 550*d4726bddSHONG Yifan 551*d4726bddSHONG Yifan_common_attrs = { 552*d4726bddSHONG Yifan "aliases": attr.label_keyed_string_dict( 553*d4726bddSHONG Yifan doc = dedent("""\ 554*d4726bddSHONG Yifan Remap crates to a new name or moniker for linkage to this target 555*d4726bddSHONG Yifan 556*d4726bddSHONG Yifan These are other `rust_library` targets and will be presented as the new name given. 557*d4726bddSHONG Yifan """), 558*d4726bddSHONG Yifan ), 559*d4726bddSHONG Yifan "alwayslink": attr.bool( 560*d4726bddSHONG Yifan doc = dedent("""\ 561*d4726bddSHONG Yifan If 1, any binary that depends (directly or indirectly) on this library 562*d4726bddSHONG Yifan will link in all the object files even if some contain no symbols referenced by the binary. 563*d4726bddSHONG Yifan 564*d4726bddSHONG Yifan This attribute is used by the C++ Starlark API when passing CcInfo providers. 565*d4726bddSHONG Yifan """), 566*d4726bddSHONG Yifan default = False, 567*d4726bddSHONG Yifan ), 568*d4726bddSHONG Yifan "compile_data": attr.label_list( 569*d4726bddSHONG Yifan doc = dedent("""\ 570*d4726bddSHONG Yifan List of files used by this rule at compile time. 571*d4726bddSHONG Yifan 572*d4726bddSHONG Yifan This attribute can be used to specify any data files that are embedded into 573*d4726bddSHONG Yifan the library, such as via the 574*d4726bddSHONG Yifan [`include_str!`](https://doc.rust-lang.org/std/macro.include_str!.html) 575*d4726bddSHONG Yifan macro. 576*d4726bddSHONG Yifan """), 577*d4726bddSHONG Yifan allow_files = True, 578*d4726bddSHONG Yifan ), 579*d4726bddSHONG Yifan "crate_features": attr.string_list( 580*d4726bddSHONG Yifan doc = dedent("""\ 581*d4726bddSHONG Yifan List of features to enable for this crate. 582*d4726bddSHONG Yifan 583*d4726bddSHONG Yifan Features are defined in the code using the `#[cfg(feature = "foo")]` 584*d4726bddSHONG Yifan configuration option. The features listed here will be passed to `rustc` 585*d4726bddSHONG Yifan with `--cfg feature="${feature_name}"` flags. 586*d4726bddSHONG Yifan """), 587*d4726bddSHONG Yifan ), 588*d4726bddSHONG Yifan "crate_name": attr.string( 589*d4726bddSHONG Yifan doc = dedent("""\ 590*d4726bddSHONG Yifan Crate name to use for this target. 591*d4726bddSHONG Yifan 592*d4726bddSHONG Yifan This must be a valid Rust identifier, i.e. it may contain only alphanumeric characters and underscores. 593*d4726bddSHONG Yifan Defaults to the target name, with any hyphens replaced by underscores. 594*d4726bddSHONG Yifan """), 595*d4726bddSHONG Yifan ), 596*d4726bddSHONG Yifan "crate_root": attr.label( 597*d4726bddSHONG Yifan doc = dedent("""\ 598*d4726bddSHONG Yifan The file that will be passed to `rustc` to be used for building this crate. 599*d4726bddSHONG Yifan 600*d4726bddSHONG Yifan If `crate_root` is not set, then this rule will look for a `lib.rs` file (or `main.rs` for rust_binary) 601*d4726bddSHONG Yifan or the single file in `srcs` if `srcs` contains only one file. 602*d4726bddSHONG Yifan """), 603*d4726bddSHONG Yifan allow_single_file = [".rs"], 604*d4726bddSHONG Yifan ), 605*d4726bddSHONG Yifan "data": attr.label_list( 606*d4726bddSHONG Yifan doc = dedent("""\ 607*d4726bddSHONG Yifan List of files used by this rule at compile time and runtime. 608*d4726bddSHONG Yifan 609*d4726bddSHONG Yifan If including data at compile time with include_str!() and similar, 610*d4726bddSHONG Yifan prefer `compile_data` over `data`, to prevent the data also being included 611*d4726bddSHONG Yifan in the runfiles. 612*d4726bddSHONG Yifan """), 613*d4726bddSHONG Yifan allow_files = True, 614*d4726bddSHONG Yifan ), 615*d4726bddSHONG Yifan "deps": attr.label_list( 616*d4726bddSHONG Yifan doc = dedent("""\ 617*d4726bddSHONG Yifan List of other libraries to be linked to this library target. 618*d4726bddSHONG Yifan 619*d4726bddSHONG Yifan These can be either other `rust_library` targets or `cc_library` targets if 620*d4726bddSHONG Yifan linking a native library. 621*d4726bddSHONG Yifan """), 622*d4726bddSHONG Yifan ), 623*d4726bddSHONG Yifan "edition": attr.string( 624*d4726bddSHONG Yifan doc = "The rust edition to use for this crate. Defaults to the edition specified in the rust_toolchain.", 625*d4726bddSHONG Yifan ), 626*d4726bddSHONG Yifan # Previously `proc_macro_deps` were a part of `deps`, and then proc_macro_host_transition was 627*d4726bddSHONG Yifan # used into cfg="host" using `@local_config_platform//:host`. 628*d4726bddSHONG Yifan # This fails for remote execution, which needs cfg="exec", and there isn't anything like 629*d4726bddSHONG Yifan # `@local_config_platform//:exec` exposed. 630*d4726bddSHONG Yifan "proc_macro_deps": attr.label_list( 631*d4726bddSHONG Yifan doc = dedent("""\ 632*d4726bddSHONG Yifan List of `rust_proc_macro` targets used to help build this library target. 633*d4726bddSHONG Yifan """), 634*d4726bddSHONG Yifan cfg = "exec", 635*d4726bddSHONG Yifan providers = [rust_common.crate_info], 636*d4726bddSHONG Yifan ), 637*d4726bddSHONG Yifan "rustc_env": attr.string_dict( 638*d4726bddSHONG Yifan doc = dedent("""\ 639*d4726bddSHONG Yifan Dictionary of additional `"key": "value"` environment variables to set for rustc. 640*d4726bddSHONG Yifan 641*d4726bddSHONG Yifan rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the 642*d4726bddSHONG Yifan location of a generated file or external tool. Cargo build scripts that wish to 643*d4726bddSHONG Yifan expand locations should use cargo_build_script()'s build_script_env argument instead, 644*d4726bddSHONG Yifan as build scripts are run in a different environment - see cargo_build_script()'s 645*d4726bddSHONG Yifan documentation for more. 646*d4726bddSHONG Yifan """), 647*d4726bddSHONG Yifan ), 648*d4726bddSHONG Yifan "rustc_env_files": attr.label_list( 649*d4726bddSHONG Yifan doc = dedent("""\ 650*d4726bddSHONG Yifan Files containing additional environment variables to set for rustc. 651*d4726bddSHONG Yifan 652*d4726bddSHONG Yifan These files should contain a single variable per line, of format 653*d4726bddSHONG Yifan `NAME=value`, and newlines may be included in a value by ending a 654*d4726bddSHONG Yifan line with a trailing back-slash (`\\\\`). 655*d4726bddSHONG Yifan 656*d4726bddSHONG Yifan The order that these files will be processed is unspecified, so 657*d4726bddSHONG Yifan multiple definitions of a particular variable are discouraged. 658*d4726bddSHONG Yifan 659*d4726bddSHONG Yifan Note that the variables here are subject to 660*d4726bddSHONG Yifan [workspace status](https://docs.bazel.build/versions/main/user-manual.html#workspace_status) 661*d4726bddSHONG Yifan stamping should the `stamp` attribute be enabled. Stamp variables 662*d4726bddSHONG Yifan should be wrapped in brackets in order to be resolved. E.g. 663*d4726bddSHONG Yifan `NAME={WORKSPACE_STATUS_VARIABLE}`. 664*d4726bddSHONG Yifan """), 665*d4726bddSHONG Yifan allow_files = True, 666*d4726bddSHONG Yifan ), 667*d4726bddSHONG Yifan "rustc_flags": attr.string_list( 668*d4726bddSHONG Yifan doc = dedent("""\ 669*d4726bddSHONG Yifan List of compiler flags passed to `rustc`. 670*d4726bddSHONG Yifan 671*d4726bddSHONG Yifan These strings are subject to Make variable expansion for predefined 672*d4726bddSHONG Yifan source/output path variables like `$location`, `$execpath`, and 673*d4726bddSHONG Yifan `$rootpath`. This expansion is useful if you wish to pass a generated 674*d4726bddSHONG Yifan file of arguments to rustc: `@$(location //package:target)`. 675*d4726bddSHONG Yifan """), 676*d4726bddSHONG Yifan ), 677*d4726bddSHONG Yifan # TODO(stardoc): How do we provide additional documentation to an inherited attribute? 678*d4726bddSHONG Yifan # "name": attr.string( 679*d4726bddSHONG Yifan # doc = "This name will also be used as the name of the crate built by this rule.", 680*d4726bddSHONG Yifan # `), 681*d4726bddSHONG Yifan "srcs": attr.label_list( 682*d4726bddSHONG Yifan doc = dedent("""\ 683*d4726bddSHONG Yifan List of Rust `.rs` source files used to build the library. 684*d4726bddSHONG Yifan 685*d4726bddSHONG Yifan If `srcs` contains more than one file, then there must be a file either 686*d4726bddSHONG Yifan named `lib.rs`. Otherwise, `crate_root` must be set to the source file that 687*d4726bddSHONG Yifan is the root of the crate to be passed to rustc to build this crate. 688*d4726bddSHONG Yifan """), 689*d4726bddSHONG Yifan allow_files = [".rs"], 690*d4726bddSHONG Yifan # Allow use of --compile_one_dependency with rust targets. Support for this feature for 691*d4726bddSHONG Yifan # non-builtin rulesets is undocumented outside of the bazel source: 692*d4726bddSHONG Yifan # https://github.com/bazelbuild/bazel/blob/7.1.1/src/main/java/com/google/devtools/build/lib/packages/Attribute.java#L102 693*d4726bddSHONG Yifan flags = ["DIRECT_COMPILE_TIME_INPUT"], 694*d4726bddSHONG Yifan ), 695*d4726bddSHONG Yifan "stamp": _stamp_attribute( 696*d4726bddSHONG Yifan default_value = 0, 697*d4726bddSHONG Yifan ), 698*d4726bddSHONG Yifan "version": attr.string( 699*d4726bddSHONG Yifan doc = "A version to inject in the cargo environment variable.", 700*d4726bddSHONG Yifan default = "0.0.0", 701*d4726bddSHONG Yifan ), 702*d4726bddSHONG Yifan "_stamp_flag": attr.label( 703*d4726bddSHONG Yifan doc = "A setting used to determine whether or not the `--stamp` flag is enabled", 704*d4726bddSHONG Yifan default = Label("//rust/private:stamp"), 705*d4726bddSHONG Yifan ), 706*d4726bddSHONG Yifan} | RUSTC_ATTRS 707*d4726bddSHONG Yifan 708*d4726bddSHONG Yifan_coverage_attrs = { 709*d4726bddSHONG Yifan "_collect_cc_coverage": attr.label( 710*d4726bddSHONG Yifan default = Label("//util/collect_coverage"), 711*d4726bddSHONG Yifan executable = True, 712*d4726bddSHONG Yifan cfg = "exec", 713*d4726bddSHONG Yifan ), 714*d4726bddSHONG Yifan # Bazel’s coverage runner 715*d4726bddSHONG Yifan # (https://github.com/bazelbuild/bazel/blob/6.0.0/tools/test/collect_coverage.sh) 716*d4726bddSHONG Yifan # needs a binary called “lcov_merge.” Its location is passed in the 717*d4726bddSHONG Yifan # LCOV_MERGER environmental variable. For builtin rules, this variable 718*d4726bddSHONG Yifan # is set automatically based on a magic “$lcov_merger” or 719*d4726bddSHONG Yifan # “:lcov_merger” attribute, but it’s not possible to create such 720*d4726bddSHONG Yifan # attributes in Starlark. Therefore we specify the variable ourselves. 721*d4726bddSHONG Yifan # Note that the coverage runner runs in the runfiles root instead of 722*d4726bddSHONG Yifan # the execution root, therefore we use “path” instead of “short_path.” 723*d4726bddSHONG Yifan "_lcov_merger": attr.label( 724*d4726bddSHONG Yifan default = configuration_field(fragment = "coverage", name = "output_generator"), 725*d4726bddSHONG Yifan executable = True, 726*d4726bddSHONG Yifan cfg = "exec", 727*d4726bddSHONG Yifan ), 728*d4726bddSHONG Yifan} 729*d4726bddSHONG Yifan 730*d4726bddSHONG Yifan_experimental_use_cc_common_link_attrs = { 731*d4726bddSHONG Yifan "experimental_use_cc_common_link": attr.int( 732*d4726bddSHONG Yifan doc = ( 733*d4726bddSHONG Yifan "Whether to use cc_common.link to link rust binaries. " + 734*d4726bddSHONG Yifan "Possible values: [-1, 0, 1]. " + 735*d4726bddSHONG Yifan "-1 means use the value of the toolchain.experimental_use_cc_common_link " + 736*d4726bddSHONG Yifan "boolean build setting to determine. " + 737*d4726bddSHONG Yifan "0 means do not use cc_common.link (use rustc instead). " + 738*d4726bddSHONG Yifan "1 means use cc_common.link." 739*d4726bddSHONG Yifan ), 740*d4726bddSHONG Yifan values = [-1, 0, 1], 741*d4726bddSHONG Yifan default = -1, 742*d4726bddSHONG Yifan ), 743*d4726bddSHONG Yifan "malloc": attr.label( 744*d4726bddSHONG Yifan default = Label("@bazel_tools//tools/cpp:malloc"), 745*d4726bddSHONG Yifan doc = """Override the default dependency on `malloc`. 746*d4726bddSHONG Yifan 747*d4726bddSHONG YifanBy default, Rust binaries linked with cc_common.link are linked against 748*d4726bddSHONG Yifan`@bazel_tools//tools/cpp:malloc"`, which is an empty library and the resulting binary will use 749*d4726bddSHONG Yifanlibc's `malloc`. This label must refer to a `cc_library` rule. 750*d4726bddSHONG Yifan""", 751*d4726bddSHONG Yifan mandatory = False, 752*d4726bddSHONG Yifan providers = [[CcInfo]], 753*d4726bddSHONG Yifan ), # A late-bound attribute denoting the value of the `--custom_malloc` 754*d4726bddSHONG Yifan # command line flag (or None if the flag is not provided). 755*d4726bddSHONG Yifan "_custom_malloc": attr.label( 756*d4726bddSHONG Yifan default = configuration_field( 757*d4726bddSHONG Yifan fragment = "cpp", 758*d4726bddSHONG Yifan name = "custom_malloc", 759*d4726bddSHONG Yifan ), 760*d4726bddSHONG Yifan providers = [[CcInfo]], 761*d4726bddSHONG Yifan ), 762*d4726bddSHONG Yifan} 763*d4726bddSHONG Yifan 764*d4726bddSHONG Yifan_rust_test_attrs = dict({ 765*d4726bddSHONG Yifan "crate": attr.label( 766*d4726bddSHONG Yifan mandatory = False, 767*d4726bddSHONG Yifan doc = dedent("""\ 768*d4726bddSHONG Yifan Target inline tests declared in the given crate 769*d4726bddSHONG Yifan 770*d4726bddSHONG Yifan These tests are typically those that would be held out under 771*d4726bddSHONG Yifan `#[cfg(test)]` declarations. 772*d4726bddSHONG Yifan """), 773*d4726bddSHONG Yifan ), 774*d4726bddSHONG Yifan "env": attr.string_dict( 775*d4726bddSHONG Yifan mandatory = False, 776*d4726bddSHONG Yifan doc = dedent("""\ 777*d4726bddSHONG Yifan Specifies additional environment variables to set when the test is executed by bazel test. 778*d4726bddSHONG Yifan Values are subject to `$(rootpath)`, `$(execpath)`, location, and 779*d4726bddSHONG Yifan ["Make variable"](https://docs.bazel.build/versions/master/be/make-variables.html) substitution. 780*d4726bddSHONG Yifan """), 781*d4726bddSHONG Yifan ), 782*d4726bddSHONG Yifan "use_libtest_harness": attr.bool( 783*d4726bddSHONG Yifan mandatory = False, 784*d4726bddSHONG Yifan default = True, 785*d4726bddSHONG Yifan doc = dedent("""\ 786*d4726bddSHONG Yifan Whether to use `libtest`. For targets using this flag, individual tests can be run by using the 787*d4726bddSHONG Yifan [--test_arg](https://docs.bazel.build/versions/4.0.0/command-line-reference.html#flag--test_arg) flag. 788*d4726bddSHONG Yifan E.g. `bazel test //src:rust_test --test_arg=foo::test::test_fn`. 789*d4726bddSHONG Yifan """), 790*d4726bddSHONG Yifan ), 791*d4726bddSHONG Yifan "_use_grep_includes": attr.bool(default = True), 792*d4726bddSHONG Yifan}.items() + _coverage_attrs.items() + _experimental_use_cc_common_link_attrs.items()) 793*d4726bddSHONG Yifan 794*d4726bddSHONG Yifanrust_library = rule( 795*d4726bddSHONG Yifan implementation = _rust_library_impl, 796*d4726bddSHONG Yifan provides = COMMON_PROVIDERS, 797*d4726bddSHONG Yifan attrs = dict(_common_attrs.items() + { 798*d4726bddSHONG Yifan "disable_pipelining": attr.bool( 799*d4726bddSHONG Yifan default = False, 800*d4726bddSHONG Yifan doc = dedent("""\ 801*d4726bddSHONG Yifan Disables pipelining for this rule if it is globally enabled. 802*d4726bddSHONG Yifan This will cause this rule to not produce a `.rmeta` file and all the dependent 803*d4726bddSHONG Yifan crates will instead use the `.rlib` file. 804*d4726bddSHONG Yifan """), 805*d4726bddSHONG Yifan ), 806*d4726bddSHONG Yifan }.items()), 807*d4726bddSHONG Yifan fragments = ["cpp"], 808*d4726bddSHONG Yifan toolchains = [ 809*d4726bddSHONG Yifan str(Label("//rust:toolchain_type")), 810*d4726bddSHONG Yifan "@bazel_tools//tools/cpp:toolchain_type", 811*d4726bddSHONG Yifan ], 812*d4726bddSHONG Yifan doc = dedent("""\ 813*d4726bddSHONG Yifan Builds a Rust library crate. 814*d4726bddSHONG Yifan 815*d4726bddSHONG Yifan Example: 816*d4726bddSHONG Yifan 817*d4726bddSHONG Yifan Suppose you have the following directory structure for a simple Rust library crate: 818*d4726bddSHONG Yifan 819*d4726bddSHONG Yifan ```output 820*d4726bddSHONG Yifan [workspace]/ 821*d4726bddSHONG Yifan WORKSPACE 822*d4726bddSHONG Yifan hello_lib/ 823*d4726bddSHONG Yifan BUILD 824*d4726bddSHONG Yifan src/ 825*d4726bddSHONG Yifan greeter.rs 826*d4726bddSHONG Yifan lib.rs 827*d4726bddSHONG Yifan ``` 828*d4726bddSHONG Yifan 829*d4726bddSHONG Yifan `hello_lib/src/greeter.rs`: 830*d4726bddSHONG Yifan ```rust 831*d4726bddSHONG Yifan pub struct Greeter { 832*d4726bddSHONG Yifan greeting: String, 833*d4726bddSHONG Yifan } 834*d4726bddSHONG Yifan 835*d4726bddSHONG Yifan impl Greeter { 836*d4726bddSHONG Yifan pub fn new(greeting: &str) -> Greeter { 837*d4726bddSHONG Yifan Greeter { greeting: greeting.to_string(), } 838*d4726bddSHONG Yifan } 839*d4726bddSHONG Yifan 840*d4726bddSHONG Yifan pub fn greet(&self, thing: &str) { 841*d4726bddSHONG Yifan println!("{} {}", &self.greeting, thing); 842*d4726bddSHONG Yifan } 843*d4726bddSHONG Yifan } 844*d4726bddSHONG Yifan ``` 845*d4726bddSHONG Yifan 846*d4726bddSHONG Yifan `hello_lib/src/lib.rs`: 847*d4726bddSHONG Yifan 848*d4726bddSHONG Yifan ```rust 849*d4726bddSHONG Yifan pub mod greeter; 850*d4726bddSHONG Yifan ``` 851*d4726bddSHONG Yifan 852*d4726bddSHONG Yifan `hello_lib/BUILD`: 853*d4726bddSHONG Yifan ```python 854*d4726bddSHONG Yifan package(default_visibility = ["//visibility:public"]) 855*d4726bddSHONG Yifan 856*d4726bddSHONG Yifan load("@rules_rust//rust:defs.bzl", "rust_library") 857*d4726bddSHONG Yifan 858*d4726bddSHONG Yifan rust_library( 859*d4726bddSHONG Yifan name = "hello_lib", 860*d4726bddSHONG Yifan srcs = [ 861*d4726bddSHONG Yifan "src/greeter.rs", 862*d4726bddSHONG Yifan "src/lib.rs", 863*d4726bddSHONG Yifan ], 864*d4726bddSHONG Yifan ) 865*d4726bddSHONG Yifan ``` 866*d4726bddSHONG Yifan 867*d4726bddSHONG Yifan Build the library: 868*d4726bddSHONG Yifan ```output 869*d4726bddSHONG Yifan $ bazel build //hello_lib 870*d4726bddSHONG Yifan INFO: Found 1 target... 871*d4726bddSHONG Yifan Target //examples/rust/hello_lib:hello_lib up-to-date: 872*d4726bddSHONG Yifan bazel-bin/examples/rust/hello_lib/libhello_lib.rlib 873*d4726bddSHONG Yifan INFO: Elapsed time: 1.245s, Critical Path: 1.01s 874*d4726bddSHONG Yifan ``` 875*d4726bddSHONG Yifan """), 876*d4726bddSHONG Yifan) 877*d4726bddSHONG Yifan 878*d4726bddSHONG Yifandef _rust_static_library_transition_impl(settings, attr): 879*d4726bddSHONG Yifan return { 880*d4726bddSHONG Yifan "//command_line_option:platforms": str(attr.platform) if attr.platform else settings["//command_line_option:platforms"], 881*d4726bddSHONG Yifan } 882*d4726bddSHONG Yifan 883*d4726bddSHONG Yifan_rust_static_library_transition = transition( 884*d4726bddSHONG Yifan implementation = _rust_static_library_transition_impl, 885*d4726bddSHONG Yifan inputs = [ 886*d4726bddSHONG Yifan "//command_line_option:platforms", 887*d4726bddSHONG Yifan ], 888*d4726bddSHONG Yifan outputs = [ 889*d4726bddSHONG Yifan "//command_line_option:platforms", 890*d4726bddSHONG Yifan ], 891*d4726bddSHONG Yifan) 892*d4726bddSHONG Yifan 893*d4726bddSHONG Yifanrust_static_library = rule( 894*d4726bddSHONG Yifan implementation = _rust_static_library_impl, 895*d4726bddSHONG Yifan attrs = dict(_common_attrs.items() + { 896*d4726bddSHONG Yifan "platform": attr.label( 897*d4726bddSHONG Yifan doc = "Optional platform to transition the static library to.", 898*d4726bddSHONG Yifan default = None, 899*d4726bddSHONG Yifan ), 900*d4726bddSHONG Yifan "_allowlist_function_transition": attr.label( 901*d4726bddSHONG Yifan default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 902*d4726bddSHONG Yifan ), 903*d4726bddSHONG Yifan }.items()), 904*d4726bddSHONG Yifan fragments = ["cpp"], 905*d4726bddSHONG Yifan cfg = _rust_static_library_transition, 906*d4726bddSHONG Yifan toolchains = [ 907*d4726bddSHONG Yifan str(Label("//rust:toolchain_type")), 908*d4726bddSHONG Yifan "@bazel_tools//tools/cpp:toolchain_type", 909*d4726bddSHONG Yifan ], 910*d4726bddSHONG Yifan provides = [CcInfo], 911*d4726bddSHONG Yifan doc = dedent("""\ 912*d4726bddSHONG Yifan Builds a Rust static library. 913*d4726bddSHONG Yifan 914*d4726bddSHONG Yifan This static library will contain all transitively reachable crates and native objects. 915*d4726bddSHONG Yifan It is meant to be used when producing an artifact that is then consumed by some other build system 916*d4726bddSHONG Yifan (for example to produce an archive that Python program links against). 917*d4726bddSHONG Yifan 918*d4726bddSHONG Yifan This rule provides CcInfo, so it can be used everywhere Bazel expects `rules_cc`. 919*d4726bddSHONG Yifan 920*d4726bddSHONG Yifan When building the whole binary in Bazel, use `rust_library` instead. 921*d4726bddSHONG Yifan """), 922*d4726bddSHONG Yifan) 923*d4726bddSHONG Yifan 924*d4726bddSHONG Yifandef _rust_shared_library_transition_impl(settings, attr): 925*d4726bddSHONG Yifan return { 926*d4726bddSHONG Yifan "//command_line_option:platforms": str(attr.platform) if attr.platform else settings["//command_line_option:platforms"], 927*d4726bddSHONG Yifan } 928*d4726bddSHONG Yifan 929*d4726bddSHONG Yifan_rust_shared_library_transition = transition( 930*d4726bddSHONG Yifan implementation = _rust_shared_library_transition_impl, 931*d4726bddSHONG Yifan inputs = [ 932*d4726bddSHONG Yifan "//command_line_option:platforms", 933*d4726bddSHONG Yifan ], 934*d4726bddSHONG Yifan outputs = [ 935*d4726bddSHONG Yifan "//command_line_option:platforms", 936*d4726bddSHONG Yifan ], 937*d4726bddSHONG Yifan) 938*d4726bddSHONG Yifan 939*d4726bddSHONG Yifanrust_shared_library = rule( 940*d4726bddSHONG Yifan implementation = _rust_shared_library_impl, 941*d4726bddSHONG Yifan attrs = dict(_common_attrs.items() + _experimental_use_cc_common_link_attrs.items() + { 942*d4726bddSHONG Yifan "platform": attr.label( 943*d4726bddSHONG Yifan doc = "Optional platform to transition the shared library to.", 944*d4726bddSHONG Yifan default = None, 945*d4726bddSHONG Yifan ), 946*d4726bddSHONG Yifan "_allowlist_function_transition": attr.label( 947*d4726bddSHONG Yifan default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 948*d4726bddSHONG Yifan ), 949*d4726bddSHONG Yifan "_use_grep_includes": attr.bool(default = True), 950*d4726bddSHONG Yifan }.items()), 951*d4726bddSHONG Yifan fragments = ["cpp"], 952*d4726bddSHONG Yifan cfg = _rust_shared_library_transition, 953*d4726bddSHONG Yifan toolchains = [ 954*d4726bddSHONG Yifan str(Label("//rust:toolchain_type")), 955*d4726bddSHONG Yifan "@bazel_tools//tools/cpp:toolchain_type", 956*d4726bddSHONG Yifan ], 957*d4726bddSHONG Yifan provides = [CcInfo], 958*d4726bddSHONG Yifan doc = dedent("""\ 959*d4726bddSHONG Yifan Builds a Rust shared library. 960*d4726bddSHONG Yifan 961*d4726bddSHONG Yifan This shared library will contain all transitively reachable crates and native objects. 962*d4726bddSHONG Yifan It is meant to be used when producing an artifact that is then consumed by some other build system 963*d4726bddSHONG Yifan (for example to produce a shared library that Python program links against). 964*d4726bddSHONG Yifan 965*d4726bddSHONG Yifan This rule provides CcInfo, so it can be used everywhere Bazel expects `rules_cc`. 966*d4726bddSHONG Yifan 967*d4726bddSHONG Yifan When building the whole binary in Bazel, use `rust_library` instead. 968*d4726bddSHONG Yifan """), 969*d4726bddSHONG Yifan) 970*d4726bddSHONG Yifan 971*d4726bddSHONG Yifandef _proc_macro_dep_transition_impl(settings, _attr): 972*d4726bddSHONG Yifan if settings["//rust/private:is_proc_macro_dep_enabled"]: 973*d4726bddSHONG Yifan return {"//rust/private:is_proc_macro_dep": True} 974*d4726bddSHONG Yifan else: 975*d4726bddSHONG Yifan return [] 976*d4726bddSHONG Yifan 977*d4726bddSHONG Yifan_proc_macro_dep_transition = transition( 978*d4726bddSHONG Yifan inputs = ["//rust/private:is_proc_macro_dep_enabled"], 979*d4726bddSHONG Yifan outputs = ["//rust/private:is_proc_macro_dep"], 980*d4726bddSHONG Yifan implementation = _proc_macro_dep_transition_impl, 981*d4726bddSHONG Yifan) 982*d4726bddSHONG Yifan 983*d4726bddSHONG Yifanrust_proc_macro = rule( 984*d4726bddSHONG Yifan implementation = _rust_proc_macro_impl, 985*d4726bddSHONG Yifan provides = COMMON_PROVIDERS, 986*d4726bddSHONG Yifan # Start by copying the common attributes, then override the `deps` attribute 987*d4726bddSHONG Yifan # to apply `_proc_macro_dep_transition`. To add this transition we additionally 988*d4726bddSHONG Yifan # need to declare `_allowlist_function_transition`, see 989*d4726bddSHONG Yifan # https://docs.bazel.build/versions/main/skylark/config.html#user-defined-transitions. 990*d4726bddSHONG Yifan attrs = dict( 991*d4726bddSHONG Yifan _common_attrs.items(), 992*d4726bddSHONG Yifan _allowlist_function_transition = attr.label( 993*d4726bddSHONG Yifan default = Label("//tools/allowlists/function_transition_allowlist"), 994*d4726bddSHONG Yifan ), 995*d4726bddSHONG Yifan deps = attr.label_list( 996*d4726bddSHONG Yifan doc = dedent("""\ 997*d4726bddSHONG Yifan List of other libraries to be linked to this library target. 998*d4726bddSHONG Yifan 999*d4726bddSHONG Yifan These can be either other `rust_library` targets or `cc_library` targets if 1000*d4726bddSHONG Yifan linking a native library. 1001*d4726bddSHONG Yifan """), 1002*d4726bddSHONG Yifan cfg = _proc_macro_dep_transition, 1003*d4726bddSHONG Yifan ), 1004*d4726bddSHONG Yifan ), 1005*d4726bddSHONG Yifan fragments = ["cpp"], 1006*d4726bddSHONG Yifan toolchains = [ 1007*d4726bddSHONG Yifan str(Label("//rust:toolchain_type")), 1008*d4726bddSHONG Yifan "@bazel_tools//tools/cpp:toolchain_type", 1009*d4726bddSHONG Yifan ], 1010*d4726bddSHONG Yifan doc = dedent("""\ 1011*d4726bddSHONG Yifan Builds a Rust proc-macro crate. 1012*d4726bddSHONG Yifan """), 1013*d4726bddSHONG Yifan) 1014*d4726bddSHONG Yifan 1015*d4726bddSHONG Yifan_rust_binary_attrs = dict({ 1016*d4726bddSHONG Yifan "crate_type": attr.string( 1017*d4726bddSHONG Yifan doc = dedent("""\ 1018*d4726bddSHONG Yifan Crate type that will be passed to `rustc` to be used for building this crate. 1019*d4726bddSHONG Yifan 1020*d4726bddSHONG Yifan This option is a temporary workaround and should be used only when building 1021*d4726bddSHONG Yifan for WebAssembly targets (//rust/platform:wasi and //rust/platform:wasm). 1022*d4726bddSHONG Yifan """), 1023*d4726bddSHONG Yifan default = "bin", 1024*d4726bddSHONG Yifan ), 1025*d4726bddSHONG Yifan "env": attr.string_dict( 1026*d4726bddSHONG Yifan mandatory = False, 1027*d4726bddSHONG Yifan doc = dedent("""\ 1028*d4726bddSHONG Yifan Specifies additional environment variables to set when the target is executed by bazel run. 1029*d4726bddSHONG Yifan Values are subject to `$(rootpath)`, `$(execpath)`, location, and 1030*d4726bddSHONG Yifan ["Make variable"](https://docs.bazel.build/versions/master/be/make-variables.html) substitution. 1031*d4726bddSHONG Yifan 1032*d4726bddSHONG Yifan Execpath returns absolute path, and in order to be able to construct the absolute path we 1033*d4726bddSHONG Yifan need to wrap the test binary in a launcher. Using a launcher comes with complications, such as 1034*d4726bddSHONG Yifan more complicated debugger attachment. 1035*d4726bddSHONG Yifan """), 1036*d4726bddSHONG Yifan ), 1037*d4726bddSHONG Yifan "linker_script": attr.label( 1038*d4726bddSHONG Yifan doc = dedent("""\ 1039*d4726bddSHONG Yifan Link script to forward into linker via rustc options. 1040*d4726bddSHONG Yifan """), 1041*d4726bddSHONG Yifan allow_single_file = True, 1042*d4726bddSHONG Yifan ), 1043*d4726bddSHONG Yifan "out_binary": attr.bool( 1044*d4726bddSHONG Yifan doc = ( 1045*d4726bddSHONG Yifan "Force a target, regardless of it's `crate_type`, to always mark the " + 1046*d4726bddSHONG Yifan "file as executable. This attribute is only used to support wasm targets but is " + 1047*d4726bddSHONG Yifan "expected to be removed following a resolution to https://github.com/bazelbuild/rules_rust/issues/771." 1048*d4726bddSHONG Yifan ), 1049*d4726bddSHONG Yifan default = False, 1050*d4726bddSHONG Yifan ), 1051*d4726bddSHONG Yifan "stamp": _stamp_attribute(default_value = -1), 1052*d4726bddSHONG Yifan "_use_grep_includes": attr.bool(default = True), 1053*d4726bddSHONG Yifan}.items() + _experimental_use_cc_common_link_attrs.items()) 1054*d4726bddSHONG Yifan 1055*d4726bddSHONG Yifandef _rust_binary_transition_impl(settings, attr): 1056*d4726bddSHONG Yifan return { 1057*d4726bddSHONG Yifan "//command_line_option:platforms": str(attr.platform) if attr.platform else settings["//command_line_option:platforms"], 1058*d4726bddSHONG Yifan } 1059*d4726bddSHONG Yifan 1060*d4726bddSHONG Yifan_rust_binary_transition = transition( 1061*d4726bddSHONG Yifan implementation = _rust_binary_transition_impl, 1062*d4726bddSHONG Yifan inputs = [ 1063*d4726bddSHONG Yifan "//command_line_option:platforms", 1064*d4726bddSHONG Yifan ], 1065*d4726bddSHONG Yifan outputs = [ 1066*d4726bddSHONG Yifan "//command_line_option:platforms", 1067*d4726bddSHONG Yifan ], 1068*d4726bddSHONG Yifan) 1069*d4726bddSHONG Yifan 1070*d4726bddSHONG Yifanrust_binary = rule( 1071*d4726bddSHONG Yifan implementation = _rust_binary_impl, 1072*d4726bddSHONG Yifan provides = COMMON_PROVIDERS, 1073*d4726bddSHONG Yifan attrs = dict(_common_attrs.items() + _rust_binary_attrs.items() + { 1074*d4726bddSHONG Yifan "platform": attr.label( 1075*d4726bddSHONG Yifan doc = "Optional platform to transition the binary to.", 1076*d4726bddSHONG Yifan default = None, 1077*d4726bddSHONG Yifan ), 1078*d4726bddSHONG Yifan "_allowlist_function_transition": attr.label( 1079*d4726bddSHONG Yifan default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 1080*d4726bddSHONG Yifan ), 1081*d4726bddSHONG Yifan }.items()), 1082*d4726bddSHONG Yifan executable = True, 1083*d4726bddSHONG Yifan fragments = ["cpp"], 1084*d4726bddSHONG Yifan cfg = _rust_binary_transition, 1085*d4726bddSHONG Yifan toolchains = [ 1086*d4726bddSHONG Yifan str(Label("//rust:toolchain_type")), 1087*d4726bddSHONG Yifan "@bazel_tools//tools/cpp:toolchain_type", 1088*d4726bddSHONG Yifan ], 1089*d4726bddSHONG Yifan doc = dedent("""\ 1090*d4726bddSHONG Yifan Builds a Rust binary crate. 1091*d4726bddSHONG Yifan 1092*d4726bddSHONG Yifan Example: 1093*d4726bddSHONG Yifan 1094*d4726bddSHONG Yifan Suppose you have the following directory structure for a Rust project with a 1095*d4726bddSHONG Yifan library crate, `hello_lib`, and a binary crate, `hello_world` that uses the 1096*d4726bddSHONG Yifan `hello_lib` library: 1097*d4726bddSHONG Yifan 1098*d4726bddSHONG Yifan ```output 1099*d4726bddSHONG Yifan [workspace]/ 1100*d4726bddSHONG Yifan WORKSPACE 1101*d4726bddSHONG Yifan hello_lib/ 1102*d4726bddSHONG Yifan BUILD 1103*d4726bddSHONG Yifan src/ 1104*d4726bddSHONG Yifan lib.rs 1105*d4726bddSHONG Yifan hello_world/ 1106*d4726bddSHONG Yifan BUILD 1107*d4726bddSHONG Yifan src/ 1108*d4726bddSHONG Yifan main.rs 1109*d4726bddSHONG Yifan ``` 1110*d4726bddSHONG Yifan 1111*d4726bddSHONG Yifan `hello_lib/src/lib.rs`: 1112*d4726bddSHONG Yifan ```rust 1113*d4726bddSHONG Yifan pub struct Greeter { 1114*d4726bddSHONG Yifan greeting: String, 1115*d4726bddSHONG Yifan } 1116*d4726bddSHONG Yifan 1117*d4726bddSHONG Yifan impl Greeter { 1118*d4726bddSHONG Yifan pub fn new(greeting: &str) -> Greeter { 1119*d4726bddSHONG Yifan Greeter { greeting: greeting.to_string(), } 1120*d4726bddSHONG Yifan } 1121*d4726bddSHONG Yifan 1122*d4726bddSHONG Yifan pub fn greet(&self, thing: &str) { 1123*d4726bddSHONG Yifan println!("{} {}", &self.greeting, thing); 1124*d4726bddSHONG Yifan } 1125*d4726bddSHONG Yifan } 1126*d4726bddSHONG Yifan ``` 1127*d4726bddSHONG Yifan 1128*d4726bddSHONG Yifan `hello_lib/BUILD`: 1129*d4726bddSHONG Yifan ```python 1130*d4726bddSHONG Yifan package(default_visibility = ["//visibility:public"]) 1131*d4726bddSHONG Yifan 1132*d4726bddSHONG Yifan load("@rules_rust//rust:defs.bzl", "rust_library") 1133*d4726bddSHONG Yifan 1134*d4726bddSHONG Yifan rust_library( 1135*d4726bddSHONG Yifan name = "hello_lib", 1136*d4726bddSHONG Yifan srcs = ["src/lib.rs"], 1137*d4726bddSHONG Yifan ) 1138*d4726bddSHONG Yifan ``` 1139*d4726bddSHONG Yifan 1140*d4726bddSHONG Yifan `hello_world/src/main.rs`: 1141*d4726bddSHONG Yifan ```rust 1142*d4726bddSHONG Yifan extern crate hello_lib; 1143*d4726bddSHONG Yifan 1144*d4726bddSHONG Yifan fn main() { 1145*d4726bddSHONG Yifan let hello = hello_lib::Greeter::new("Hello"); 1146*d4726bddSHONG Yifan hello.greet("world"); 1147*d4726bddSHONG Yifan } 1148*d4726bddSHONG Yifan ``` 1149*d4726bddSHONG Yifan 1150*d4726bddSHONG Yifan `hello_world/BUILD`: 1151*d4726bddSHONG Yifan ```python 1152*d4726bddSHONG Yifan load("@rules_rust//rust:defs.bzl", "rust_binary") 1153*d4726bddSHONG Yifan 1154*d4726bddSHONG Yifan rust_binary( 1155*d4726bddSHONG Yifan name = "hello_world", 1156*d4726bddSHONG Yifan srcs = ["src/main.rs"], 1157*d4726bddSHONG Yifan deps = ["//hello_lib"], 1158*d4726bddSHONG Yifan ) 1159*d4726bddSHONG Yifan ``` 1160*d4726bddSHONG Yifan 1161*d4726bddSHONG Yifan Build and run `hello_world`: 1162*d4726bddSHONG Yifan ``` 1163*d4726bddSHONG Yifan $ bazel run //hello_world 1164*d4726bddSHONG Yifan INFO: Found 1 target... 1165*d4726bddSHONG Yifan Target //examples/rust/hello_world:hello_world up-to-date: 1166*d4726bddSHONG Yifan bazel-bin/examples/rust/hello_world/hello_world 1167*d4726bddSHONG Yifan INFO: Elapsed time: 1.308s, Critical Path: 1.22s 1168*d4726bddSHONG Yifan 1169*d4726bddSHONG Yifan INFO: Running command line: bazel-bin/examples/rust/hello_world/hello_world 1170*d4726bddSHONG Yifan Hello world 1171*d4726bddSHONG Yifan ``` 1172*d4726bddSHONG Yifan 1173*d4726bddSHONG Yifan On Windows, a PDB file containing debugging information is available under 1174*d4726bddSHONG Yifan the key `pdb_file` in `OutputGroupInfo`. Similarly on macOS, a dSYM folder 1175*d4726bddSHONG Yifan is available under the key `dsym_folder` in `OutputGroupInfo`. 1176*d4726bddSHONG Yifan"""), 1177*d4726bddSHONG Yifan) 1178*d4726bddSHONG Yifan 1179*d4726bddSHONG Yifandef _common_attrs_for_binary_without_process_wrapper(attrs): 1180*d4726bddSHONG Yifan new_attr = dict(attrs) 1181*d4726bddSHONG Yifan 1182*d4726bddSHONG Yifan # use a fake process wrapper 1183*d4726bddSHONG Yifan new_attr["_process_wrapper"] = attr.label( 1184*d4726bddSHONG Yifan default = None, 1185*d4726bddSHONG Yifan executable = True, 1186*d4726bddSHONG Yifan allow_single_file = True, 1187*d4726bddSHONG Yifan cfg = "exec", 1188*d4726bddSHONG Yifan ) 1189*d4726bddSHONG Yifan 1190*d4726bddSHONG Yifan new_attr["_bootstrap_process_wrapper"] = attr.label( 1191*d4726bddSHONG Yifan default = Label("//util/process_wrapper:bootstrap_process_wrapper"), 1192*d4726bddSHONG Yifan executable = True, 1193*d4726bddSHONG Yifan allow_single_file = True, 1194*d4726bddSHONG Yifan cfg = "exec", 1195*d4726bddSHONG Yifan ) 1196*d4726bddSHONG Yifan 1197*d4726bddSHONG Yifan # fix stamp = 0 1198*d4726bddSHONG Yifan new_attr["stamp"] = attr.int( 1199*d4726bddSHONG Yifan doc = dedent("""\ 1200*d4726bddSHONG Yifan Fix `stamp = 0` as stamping is not supported when building without process_wrapper: 1201*d4726bddSHONG Yifan https://github.com/bazelbuild/rules_rust/blob/8df4517d370b0c543a01ba38b63e1d5a4104b035/rust/private/rustc.bzl#L955 1202*d4726bddSHONG Yifan """), 1203*d4726bddSHONG Yifan default = 0, 1204*d4726bddSHONG Yifan values = [0], 1205*d4726bddSHONG Yifan ) 1206*d4726bddSHONG Yifan 1207*d4726bddSHONG Yifan return new_attr 1208*d4726bddSHONG Yifan 1209*d4726bddSHONG Yifan# Provides an internal rust_{binary,library} to use that we can use to build the process 1210*d4726bddSHONG Yifan# wrapper, this breaks the dependency of rust_* on the process wrapper by 1211*d4726bddSHONG Yifan# setting it to None, which the functions in rustc detect and build accordingly. 1212*d4726bddSHONG Yifanrust_binary_without_process_wrapper = rule( 1213*d4726bddSHONG Yifan implementation = _rust_binary_impl, 1214*d4726bddSHONG Yifan provides = COMMON_PROVIDERS, 1215*d4726bddSHONG Yifan attrs = _common_attrs_for_binary_without_process_wrapper(_common_attrs.items() + _rust_binary_attrs.items() + { 1216*d4726bddSHONG Yifan "platform": attr.label( 1217*d4726bddSHONG Yifan doc = "Optional platform to transition the binary to.", 1218*d4726bddSHONG Yifan default = None, 1219*d4726bddSHONG Yifan ), 1220*d4726bddSHONG Yifan "_allowlist_function_transition": attr.label( 1221*d4726bddSHONG Yifan default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 1222*d4726bddSHONG Yifan ), 1223*d4726bddSHONG Yifan }.items()), 1224*d4726bddSHONG Yifan executable = True, 1225*d4726bddSHONG Yifan fragments = ["cpp"], 1226*d4726bddSHONG Yifan cfg = _rust_binary_transition, 1227*d4726bddSHONG Yifan toolchains = [ 1228*d4726bddSHONG Yifan str(Label("//rust:toolchain_type")), 1229*d4726bddSHONG Yifan "@bazel_tools//tools/cpp:toolchain_type", 1230*d4726bddSHONG Yifan ], 1231*d4726bddSHONG Yifan) 1232*d4726bddSHONG Yifan 1233*d4726bddSHONG Yifanrust_library_without_process_wrapper = rule( 1234*d4726bddSHONG Yifan implementation = _rust_library_impl, 1235*d4726bddSHONG Yifan provides = COMMON_PROVIDERS, 1236*d4726bddSHONG Yifan attrs = dict(_common_attrs_for_binary_without_process_wrapper(_common_attrs).items()), 1237*d4726bddSHONG Yifan fragments = ["cpp"], 1238*d4726bddSHONG Yifan toolchains = [ 1239*d4726bddSHONG Yifan str(Label("//rust:toolchain_type")), 1240*d4726bddSHONG Yifan "@bazel_tools//tools/cpp:toolchain_type", 1241*d4726bddSHONG Yifan ], 1242*d4726bddSHONG Yifan) 1243*d4726bddSHONG Yifan 1244*d4726bddSHONG Yifandef _rust_test_transition_impl(settings, attr): 1245*d4726bddSHONG Yifan return { 1246*d4726bddSHONG Yifan "//command_line_option:platforms": str(attr.platform) if attr.platform else settings["//command_line_option:platforms"], 1247*d4726bddSHONG Yifan } 1248*d4726bddSHONG Yifan 1249*d4726bddSHONG Yifan_rust_test_transition = transition( 1250*d4726bddSHONG Yifan implementation = _rust_test_transition_impl, 1251*d4726bddSHONG Yifan inputs = [ 1252*d4726bddSHONG Yifan "//command_line_option:platforms", 1253*d4726bddSHONG Yifan ], 1254*d4726bddSHONG Yifan outputs = [ 1255*d4726bddSHONG Yifan "//command_line_option:platforms", 1256*d4726bddSHONG Yifan ], 1257*d4726bddSHONG Yifan) 1258*d4726bddSHONG Yifan 1259*d4726bddSHONG Yifanrust_test = rule( 1260*d4726bddSHONG Yifan implementation = _rust_test_impl, 1261*d4726bddSHONG Yifan provides = COMMON_PROVIDERS, 1262*d4726bddSHONG Yifan attrs = dict(_common_attrs.items() + _rust_test_attrs.items() + { 1263*d4726bddSHONG Yifan "platform": attr.label( 1264*d4726bddSHONG Yifan doc = "Optional platform to transition the test to.", 1265*d4726bddSHONG Yifan default = None, 1266*d4726bddSHONG Yifan ), 1267*d4726bddSHONG Yifan "_allowlist_function_transition": attr.label( 1268*d4726bddSHONG Yifan default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 1269*d4726bddSHONG Yifan ), 1270*d4726bddSHONG Yifan }.items()), 1271*d4726bddSHONG Yifan executable = True, 1272*d4726bddSHONG Yifan fragments = ["cpp"], 1273*d4726bddSHONG Yifan cfg = _rust_test_transition, 1274*d4726bddSHONG Yifan test = True, 1275*d4726bddSHONG Yifan toolchains = [ 1276*d4726bddSHONG Yifan str(Label("//rust:toolchain_type")), 1277*d4726bddSHONG Yifan "@bazel_tools//tools/cpp:toolchain_type", 1278*d4726bddSHONG Yifan ], 1279*d4726bddSHONG Yifan doc = dedent("""\ 1280*d4726bddSHONG Yifan Builds a Rust test crate. 1281*d4726bddSHONG Yifan 1282*d4726bddSHONG Yifan Examples: 1283*d4726bddSHONG Yifan 1284*d4726bddSHONG Yifan Suppose you have the following directory structure for a Rust library crate \ 1285*d4726bddSHONG Yifan with unit test code in the library sources: 1286*d4726bddSHONG Yifan 1287*d4726bddSHONG Yifan ```output 1288*d4726bddSHONG Yifan [workspace]/ 1289*d4726bddSHONG Yifan WORKSPACE 1290*d4726bddSHONG Yifan hello_lib/ 1291*d4726bddSHONG Yifan BUILD 1292*d4726bddSHONG Yifan src/ 1293*d4726bddSHONG Yifan lib.rs 1294*d4726bddSHONG Yifan ``` 1295*d4726bddSHONG Yifan 1296*d4726bddSHONG Yifan `hello_lib/src/lib.rs`: 1297*d4726bddSHONG Yifan ```rust 1298*d4726bddSHONG Yifan pub struct Greeter { 1299*d4726bddSHONG Yifan greeting: String, 1300*d4726bddSHONG Yifan } 1301*d4726bddSHONG Yifan 1302*d4726bddSHONG Yifan impl Greeter { 1303*d4726bddSHONG Yifan pub fn new(greeting: &str) -> Greeter { 1304*d4726bddSHONG Yifan Greeter { greeting: greeting.to_string(), } 1305*d4726bddSHONG Yifan } 1306*d4726bddSHONG Yifan 1307*d4726bddSHONG Yifan pub fn greet(&self, thing: &str) -> String { 1308*d4726bddSHONG Yifan format!("{} {}", &self.greeting, thing) 1309*d4726bddSHONG Yifan } 1310*d4726bddSHONG Yifan } 1311*d4726bddSHONG Yifan 1312*d4726bddSHONG Yifan #[cfg(test)] 1313*d4726bddSHONG Yifan mod test { 1314*d4726bddSHONG Yifan use super::Greeter; 1315*d4726bddSHONG Yifan 1316*d4726bddSHONG Yifan #[test] 1317*d4726bddSHONG Yifan fn test_greeting() { 1318*d4726bddSHONG Yifan let hello = Greeter::new("Hi"); 1319*d4726bddSHONG Yifan assert_eq!("Hi Rust", hello.greet("Rust")); 1320*d4726bddSHONG Yifan } 1321*d4726bddSHONG Yifan } 1322*d4726bddSHONG Yifan ``` 1323*d4726bddSHONG Yifan 1324*d4726bddSHONG Yifan To build and run the tests, simply add a `rust_test` rule with no `srcs` 1325*d4726bddSHONG Yifan and only depends on the `hello_lib` `rust_library` target via the 1326*d4726bddSHONG Yifan `crate` attribute: 1327*d4726bddSHONG Yifan 1328*d4726bddSHONG Yifan `hello_lib/BUILD`: 1329*d4726bddSHONG Yifan ```python 1330*d4726bddSHONG Yifan load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test") 1331*d4726bddSHONG Yifan 1332*d4726bddSHONG Yifan rust_library( 1333*d4726bddSHONG Yifan name = "hello_lib", 1334*d4726bddSHONG Yifan srcs = ["src/lib.rs"], 1335*d4726bddSHONG Yifan ) 1336*d4726bddSHONG Yifan 1337*d4726bddSHONG Yifan rust_test( 1338*d4726bddSHONG Yifan name = "hello_lib_test", 1339*d4726bddSHONG Yifan crate = ":hello_lib", 1340*d4726bddSHONG Yifan # You may add other deps that are specific to the test configuration 1341*d4726bddSHONG Yifan deps = ["//some/dev/dep"], 1342*d4726bddSHONG Yifan ) 1343*d4726bddSHONG Yifan ``` 1344*d4726bddSHONG Yifan 1345*d4726bddSHONG Yifan Run the test with `bazel test //hello_lib:hello_lib_test`. The crate 1346*d4726bddSHONG Yifan will be built using the same crate name as the underlying ":hello_lib" 1347*d4726bddSHONG Yifan crate. 1348*d4726bddSHONG Yifan 1349*d4726bddSHONG Yifan ### Example: `test` directory 1350*d4726bddSHONG Yifan 1351*d4726bddSHONG Yifan Integration tests that live in the [`tests` directory][int-tests], they are \ 1352*d4726bddSHONG Yifan essentially built as separate crates. Suppose you have the following directory \ 1353*d4726bddSHONG Yifan structure where `greeting.rs` is an integration test for the `hello_lib` \ 1354*d4726bddSHONG Yifan library crate: 1355*d4726bddSHONG Yifan 1356*d4726bddSHONG Yifan [int-tests]: http://doc.rust-lang.org/book/testing.html#the-tests-directory 1357*d4726bddSHONG Yifan 1358*d4726bddSHONG Yifan ```output 1359*d4726bddSHONG Yifan [workspace]/ 1360*d4726bddSHONG Yifan WORKSPACE 1361*d4726bddSHONG Yifan hello_lib/ 1362*d4726bddSHONG Yifan BUILD 1363*d4726bddSHONG Yifan src/ 1364*d4726bddSHONG Yifan lib.rs 1365*d4726bddSHONG Yifan tests/ 1366*d4726bddSHONG Yifan greeting.rs 1367*d4726bddSHONG Yifan ``` 1368*d4726bddSHONG Yifan 1369*d4726bddSHONG Yifan `hello_lib/tests/greeting.rs`: 1370*d4726bddSHONG Yifan ```rust 1371*d4726bddSHONG Yifan extern crate hello_lib; 1372*d4726bddSHONG Yifan 1373*d4726bddSHONG Yifan use hello_lib; 1374*d4726bddSHONG Yifan 1375*d4726bddSHONG Yifan #[test] 1376*d4726bddSHONG Yifan fn test_greeting() { 1377*d4726bddSHONG Yifan let hello = greeter::Greeter::new("Hello"); 1378*d4726bddSHONG Yifan assert_eq!("Hello world", hello.greeting("world")); 1379*d4726bddSHONG Yifan } 1380*d4726bddSHONG Yifan ``` 1381*d4726bddSHONG Yifan 1382*d4726bddSHONG Yifan To build the `greeting.rs` integration test, simply add a `rust_test` target 1383*d4726bddSHONG Yifan with `greeting.rs` in `srcs` and a dependency on the `hello_lib` target: 1384*d4726bddSHONG Yifan 1385*d4726bddSHONG Yifan `hello_lib/BUILD`: 1386*d4726bddSHONG Yifan ```python 1387*d4726bddSHONG Yifan load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test") 1388*d4726bddSHONG Yifan 1389*d4726bddSHONG Yifan rust_library( 1390*d4726bddSHONG Yifan name = "hello_lib", 1391*d4726bddSHONG Yifan srcs = ["src/lib.rs"], 1392*d4726bddSHONG Yifan ) 1393*d4726bddSHONG Yifan 1394*d4726bddSHONG Yifan rust_test( 1395*d4726bddSHONG Yifan name = "greeting_test", 1396*d4726bddSHONG Yifan srcs = ["tests/greeting.rs"], 1397*d4726bddSHONG Yifan deps = [":hello_lib"], 1398*d4726bddSHONG Yifan ) 1399*d4726bddSHONG Yifan ``` 1400*d4726bddSHONG Yifan 1401*d4726bddSHONG Yifan Run the test with `bazel test //hello_lib:greeting_test`. 1402*d4726bddSHONG Yifan"""), 1403*d4726bddSHONG Yifan) 1404*d4726bddSHONG Yifan 1405*d4726bddSHONG Yifandef rust_test_suite(name, srcs, shared_srcs = [], **kwargs): 1406*d4726bddSHONG Yifan """A rule for creating a test suite for a set of `rust_test` targets. 1407*d4726bddSHONG Yifan 1408*d4726bddSHONG Yifan This rule can be used for setting up typical rust [integration tests][it]. Given the following 1409*d4726bddSHONG Yifan directory structure: 1410*d4726bddSHONG Yifan 1411*d4726bddSHONG Yifan ```text 1412*d4726bddSHONG Yifan [crate]/ 1413*d4726bddSHONG Yifan BUILD.bazel 1414*d4726bddSHONG Yifan src/ 1415*d4726bddSHONG Yifan lib.rs 1416*d4726bddSHONG Yifan main.rs 1417*d4726bddSHONG Yifan tests/ 1418*d4726bddSHONG Yifan integrated_test_a.rs 1419*d4726bddSHONG Yifan integrated_test_b.rs 1420*d4726bddSHONG Yifan integrated_test_c.rs 1421*d4726bddSHONG Yifan patterns/ 1422*d4726bddSHONG Yifan fibonacci_test.rs 1423*d4726bddSHONG Yifan helpers/ 1424*d4726bddSHONG Yifan mod.rs 1425*d4726bddSHONG Yifan ``` 1426*d4726bddSHONG Yifan 1427*d4726bddSHONG Yifan The rule can be used to generate [rust_test](#rust_test) targets for each source file under `tests` 1428*d4726bddSHONG Yifan and a [test_suite][ts] which encapsulates all tests. 1429*d4726bddSHONG Yifan 1430*d4726bddSHONG Yifan ```python 1431*d4726bddSHONG Yifan load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_test_suite") 1432*d4726bddSHONG Yifan 1433*d4726bddSHONG Yifan rust_library( 1434*d4726bddSHONG Yifan name = "math_lib", 1435*d4726bddSHONG Yifan srcs = ["src/lib.rs"], 1436*d4726bddSHONG Yifan ) 1437*d4726bddSHONG Yifan 1438*d4726bddSHONG Yifan rust_binary( 1439*d4726bddSHONG Yifan name = "math_bin", 1440*d4726bddSHONG Yifan srcs = ["src/main.rs"], 1441*d4726bddSHONG Yifan ) 1442*d4726bddSHONG Yifan 1443*d4726bddSHONG Yifan rust_test_suite( 1444*d4726bddSHONG Yifan name = "integrated_tests_suite", 1445*d4726bddSHONG Yifan srcs = glob(["tests/**"]), 1446*d4726bddSHONG Yifan shared_srcs=glob(["tests/helpers/**"]), 1447*d4726bddSHONG Yifan deps = [":math_lib"], 1448*d4726bddSHONG Yifan ) 1449*d4726bddSHONG Yifan ``` 1450*d4726bddSHONG Yifan 1451*d4726bddSHONG Yifan [it]: https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html 1452*d4726bddSHONG Yifan [ts]: https://docs.bazel.build/versions/master/be/general.html#test_suite 1453*d4726bddSHONG Yifan 1454*d4726bddSHONG Yifan Args: 1455*d4726bddSHONG Yifan name (str): The name of the `test_suite`. 1456*d4726bddSHONG Yifan srcs (list): All test sources, typically `glob(["tests/**/*.rs"])`. 1457*d4726bddSHONG Yifan shared_srcs (list): Optional argument for sources shared among tests, typically helper functions. 1458*d4726bddSHONG Yifan **kwargs (dict): Additional keyword arguments for the underyling [rust_test](#rust_test) targets. The 1459*d4726bddSHONG Yifan `tags` argument is also passed to the generated `test_suite` target. 1460*d4726bddSHONG Yifan """ 1461*d4726bddSHONG Yifan tests = [] 1462*d4726bddSHONG Yifan 1463*d4726bddSHONG Yifan for src in srcs: 1464*d4726bddSHONG Yifan if not src.endswith(".rs"): 1465*d4726bddSHONG Yifan fail("srcs should have `.rs` extensions") 1466*d4726bddSHONG Yifan 1467*d4726bddSHONG Yifan if src in shared_srcs: 1468*d4726bddSHONG Yifan continue 1469*d4726bddSHONG Yifan 1470*d4726bddSHONG Yifan # Prefixed with `name` to allow parameterization with macros 1471*d4726bddSHONG Yifan # The test name should not end with `.rs` 1472*d4726bddSHONG Yifan test_name = name + "_" + src[:-3] 1473*d4726bddSHONG Yifan rust_test( 1474*d4726bddSHONG Yifan name = test_name, 1475*d4726bddSHONG Yifan crate_root = src, 1476*d4726bddSHONG Yifan srcs = [src] + shared_srcs, 1477*d4726bddSHONG Yifan **kwargs 1478*d4726bddSHONG Yifan ) 1479*d4726bddSHONG Yifan tests.append(test_name) 1480*d4726bddSHONG Yifan 1481*d4726bddSHONG Yifan native.test_suite( 1482*d4726bddSHONG Yifan name = name, 1483*d4726bddSHONG Yifan tests = tests, 1484*d4726bddSHONG Yifan tags = kwargs.get("tags", None), 1485*d4726bddSHONG Yifan ) 1486*d4726bddSHONG Yifan 1487*d4726bddSHONG Yifanrust_library_group = rule( 1488*d4726bddSHONG Yifan implementation = _rust_library_group_impl, 1489*d4726bddSHONG Yifan provides = [rust_common.crate_group_info], 1490*d4726bddSHONG Yifan attrs = { 1491*d4726bddSHONG Yifan "deps": attr.label_list( 1492*d4726bddSHONG Yifan doc = "Other dependencies to forward through this crate group.", 1493*d4726bddSHONG Yifan providers = [[rust_common.crate_group_info], [rust_common.crate_info]], 1494*d4726bddSHONG Yifan ), 1495*d4726bddSHONG Yifan }, 1496*d4726bddSHONG Yifan doc = dedent("""\ 1497*d4726bddSHONG Yifan Functions as an alias for a set of dependencies. 1498*d4726bddSHONG Yifan 1499*d4726bddSHONG Yifan Specifically, the following are equivalent: 1500*d4726bddSHONG Yifan 1501*d4726bddSHONG Yifan ```starlark 1502*d4726bddSHONG Yifan rust_library_group( 1503*d4726bddSHONG Yifan name = "crate_group", 1504*d4726bddSHONG Yifan deps = [ 1505*d4726bddSHONG Yifan ":crate1", 1506*d4726bddSHONG Yifan ":crate2", 1507*d4726bddSHONG Yifan ], 1508*d4726bddSHONG Yifan ) 1509*d4726bddSHONG Yifan 1510*d4726bddSHONG Yifan rust_library( 1511*d4726bddSHONG Yifan name = "foobar", 1512*d4726bddSHONG Yifan deps = [":crate_group"], 1513*d4726bddSHONG Yifan ... 1514*d4726bddSHONG Yifan ) 1515*d4726bddSHONG Yifan ``` 1516*d4726bddSHONG Yifan 1517*d4726bddSHONG Yifan and 1518*d4726bddSHONG Yifan 1519*d4726bddSHONG Yifan ```starlark 1520*d4726bddSHONG Yifan rust_library( 1521*d4726bddSHONG Yifan name = "foobar", 1522*d4726bddSHONG Yifan deps = [ 1523*d4726bddSHONG Yifan ":crate1", 1524*d4726bddSHONG Yifan ":crate2", 1525*d4726bddSHONG Yifan ], 1526*d4726bddSHONG Yifan ... 1527*d4726bddSHONG Yifan ) 1528*d4726bddSHONG Yifan ``` 1529*d4726bddSHONG Yifan """), 1530*d4726bddSHONG Yifan) 1531