1"""The rust_toolchain rule definition and implementation.""" 2 3load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 4load("//rust/platform:triple.bzl", "triple") 5load("//rust/private:common.bzl", "rust_common") 6load("//rust/private:rust_analyzer.bzl", _rust_analyzer_toolchain = "rust_analyzer_toolchain") 7load( 8 "//rust/private:rustfmt.bzl", 9 _current_rustfmt_toolchain = "current_rustfmt_toolchain", 10 _rustfmt_toolchain = "rustfmt_toolchain", 11) 12load( 13 "//rust/private:utils.bzl", 14 "dedent", 15 "dedup_expand_location", 16 "find_cc_toolchain", 17 "is_exec_configuration", 18 "is_std_dylib", 19 "make_static_lib_symlink", 20) 21load("//rust/settings:incompatible.bzl", "IncompatibleFlagInfo") 22 23rust_analyzer_toolchain = _rust_analyzer_toolchain 24rustfmt_toolchain = _rustfmt_toolchain 25current_rustfmt_toolchain = _current_rustfmt_toolchain 26 27def _rust_stdlib_filegroup_impl(ctx): 28 rust_std = ctx.files.srcs 29 dot_a_files = [] 30 between_alloc_and_core_files = [] 31 core_files = [] 32 between_core_and_std_files = [] 33 std_files = [] 34 test_files = [] 35 memchr_files = [] 36 alloc_files = [] 37 self_contained_files = [ 38 file 39 for file in rust_std 40 if file.basename.endswith(".o") and "self-contained" in file.path 41 ] 42 panic_files = [] 43 44 std_rlibs = [f for f in rust_std if f.basename.endswith(".rlib")] 45 if std_rlibs: 46 # test depends on std 47 # std depends on everything except test 48 # 49 # core only depends on alloc, but we poke adler in there 50 # because that needs to be before miniz_oxide 51 # 52 # panic_unwind depends on unwind, alloc, cfg_if, compiler_builtins, core, libc 53 # panic_abort depends on alloc, cfg_if, compiler_builtins, core, libc 54 # 55 # alloc depends on the allocator_library if it's configured, but we 56 # do that later. 57 dot_a_files = [make_static_lib_symlink(ctx.actions, f) for f in std_rlibs] 58 59 alloc_files = [f for f in dot_a_files if "alloc" in f.basename and "std" not in f.basename] 60 between_alloc_and_core_files = [f for f in dot_a_files if "compiler_builtins" in f.basename] 61 core_files = [f for f in dot_a_files if ("core" in f.basename or "adler" in f.basename) and "std" not in f.basename] 62 panic_files = [f for f in dot_a_files if f.basename in ["cfg_if", "libc", "panic_abort", "panic_unwind", "unwind"]] 63 between_core_and_std_files = [ 64 f 65 for f in dot_a_files 66 if "alloc" not in f.basename and "compiler_builtins" not in f.basename and "core" not in f.basename and "adler" not in f.basename and "std" not in f.basename and "memchr" not in f.basename and "test" not in f.basename 67 ] 68 memchr_files = [f for f in dot_a_files if "memchr" in f.basename] 69 std_files = [f for f in dot_a_files if "std" in f.basename] 70 test_files = [f for f in dot_a_files if "test" in f.basename] 71 72 partitioned_files_len = len(alloc_files) + len(between_alloc_and_core_files) + len(core_files) + len(between_core_and_std_files) + len(memchr_files) + len(std_files) + len(test_files) 73 if partitioned_files_len != len(dot_a_files): 74 partitioned = alloc_files + between_alloc_and_core_files + core_files + between_core_and_std_files + memchr_files + std_files + test_files 75 for f in sorted(partitioned): 76 # buildifier: disable=print 77 print("File partitioned: {}".format(f.basename)) 78 fail("rust_toolchain couldn't properly partition rlibs in rust_std. Partitioned {} out of {} files. This is probably a bug in the rule implementation.".format(partitioned_files_len, len(dot_a_files))) 79 80 std_dylib = None 81 82 for file in rust_std: 83 if is_std_dylib(file): 84 std_dylib = file 85 break 86 87 return [ 88 DefaultInfo( 89 files = depset(ctx.files.srcs), 90 runfiles = ctx.runfiles(ctx.files.srcs), 91 ), 92 rust_common.stdlib_info( 93 std_rlibs = std_rlibs, 94 dot_a_files = dot_a_files, 95 between_alloc_and_core_files = between_alloc_and_core_files, 96 core_files = core_files, 97 between_core_and_std_files = between_core_and_std_files, 98 std_files = std_files, 99 std_dylib = std_dylib, 100 test_files = test_files, 101 memchr_files = memchr_files, 102 alloc_files = alloc_files, 103 self_contained_files = self_contained_files, 104 panic_files = panic_files, 105 srcs = ctx.attr.srcs, 106 ), 107 ] 108 109rust_stdlib_filegroup = rule( 110 doc = "A dedicated filegroup-like rule for Rust stdlib artifacts.", 111 implementation = _rust_stdlib_filegroup_impl, 112 attrs = { 113 "srcs": attr.label_list( 114 allow_files = True, 115 doc = "The list of targets/files that are components of the rust-stdlib file group", 116 mandatory = True, 117 ), 118 }, 119) 120 121def _ltl(library, ctx, cc_toolchain, feature_configuration): 122 """A helper to generate `LibraryToLink` objects 123 124 Args: 125 library (File): A rust library file to link. 126 ctx (ctx): The rule's context object. 127 cc_toolchain (CcToolchainInfo): A cc toolchain provider to be used. 128 feature_configuration (feature_configuration): feature_configuration to be queried. 129 130 Returns: 131 LibraryToLink: A provider containing information about libraries to link. 132 """ 133 return cc_common.create_library_to_link( 134 actions = ctx.actions, 135 feature_configuration = feature_configuration, 136 cc_toolchain = cc_toolchain, 137 static_library = library, 138 pic_static_library = library, 139 ) 140 141def _make_libstd_and_allocator_ccinfo(ctx, rust_std, allocator_library, std = "std"): 142 """Make the CcInfo (if possible) for libstd and allocator libraries. 143 144 Args: 145 ctx (ctx): The rule's context object. 146 rust_std: The Rust standard library. 147 allocator_library: The target to use for providing allocator functions. 148 std: Standard library flavor. Currently only "std" and "no_std_with_alloc" are supported, 149 accompanied with the default panic behavior. 150 151 152 Returns: 153 A CcInfo object for the required libraries, or None if no such libraries are available. 154 """ 155 cc_toolchain, feature_configuration = find_cc_toolchain(ctx) 156 cc_infos = [] 157 158 if not rust_common.stdlib_info in rust_std: 159 fail(dedent("""\ 160 {} -- 161 The `rust_lib` ({}) must be a target providing `rust_common.stdlib_info` 162 (typically `rust_stdlib_filegroup` rule from @rules_rust//rust:defs.bzl). 163 See https://github.com/bazelbuild/rules_rust/pull/802 for more information. 164 """).format(ctx.label, rust_std)) 165 rust_stdlib_info = rust_std[rust_common.stdlib_info] 166 167 if rust_stdlib_info.self_contained_files: 168 compilation_outputs = cc_common.create_compilation_outputs( 169 objects = depset(rust_stdlib_info.self_contained_files), 170 ) 171 172 linking_context, _linking_outputs = cc_common.create_linking_context_from_compilation_outputs( 173 name = ctx.label.name, 174 actions = ctx.actions, 175 feature_configuration = feature_configuration, 176 cc_toolchain = cc_toolchain, 177 compilation_outputs = compilation_outputs, 178 ) 179 180 cc_infos.append(CcInfo( 181 linking_context = linking_context, 182 )) 183 184 if rust_stdlib_info.std_rlibs: 185 alloc_inputs = depset( 186 [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.alloc_files], 187 ) 188 between_alloc_and_core_inputs = depset( 189 [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.between_alloc_and_core_files], 190 transitive = [alloc_inputs], 191 order = "topological", 192 ) 193 core_inputs = depset( 194 [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.core_files], 195 transitive = [between_alloc_and_core_inputs], 196 order = "topological", 197 ) 198 199 # The libraries panic_abort and panic_unwind are alternatives. 200 # The std by default requires panic_unwind. 201 # Exclude panic_abort if panic_unwind is present. 202 # TODO: Provide a setting to choose between panic_abort and panic_unwind. 203 filtered_between_core_and_std_files = rust_stdlib_info.between_core_and_std_files 204 has_panic_unwind = [ 205 f 206 for f in filtered_between_core_and_std_files 207 if "panic_unwind" in f.basename 208 ] 209 if has_panic_unwind: 210 filtered_between_core_and_std_files = [ 211 f 212 for f in filtered_between_core_and_std_files 213 if "abort" not in f.basename 214 ] 215 core_alloc_and_panic_inputs = depset( 216 [ 217 _ltl(f, ctx, cc_toolchain, feature_configuration) 218 for f in rust_stdlib_info.panic_files 219 if "unwind" not in f.basename 220 ], 221 transitive = [core_inputs], 222 order = "topological", 223 ) 224 else: 225 core_alloc_and_panic_inputs = depset( 226 [ 227 _ltl(f, ctx, cc_toolchain, feature_configuration) 228 for f in rust_stdlib_info.panic_files 229 if "unwind" not in f.basename 230 ], 231 transitive = [core_inputs], 232 order = "topological", 233 ) 234 memchr_inputs = depset( 235 [ 236 _ltl(f, ctx, cc_toolchain, feature_configuration) 237 for f in rust_stdlib_info.memchr_files 238 ], 239 transitive = [core_inputs], 240 order = "topological", 241 ) 242 between_core_and_std_inputs = depset( 243 [ 244 _ltl(f, ctx, cc_toolchain, feature_configuration) 245 for f in filtered_between_core_and_std_files 246 ], 247 transitive = [memchr_inputs], 248 order = "topological", 249 ) 250 251 if _experimental_link_std_dylib(ctx): 252 # std dylib has everything so that we do not need to include all std_files 253 std_inputs = depset( 254 [cc_common.create_library_to_link( 255 actions = ctx.actions, 256 feature_configuration = feature_configuration, 257 cc_toolchain = cc_toolchain, 258 dynamic_library = rust_stdlib_info.std_dylib, 259 )], 260 ) 261 else: 262 std_inputs = depset( 263 [ 264 _ltl(f, ctx, cc_toolchain, feature_configuration) 265 for f in rust_stdlib_info.std_files 266 ], 267 transitive = [between_core_and_std_inputs], 268 order = "topological", 269 ) 270 271 test_inputs = depset( 272 [ 273 _ltl(f, ctx, cc_toolchain, feature_configuration) 274 for f in rust_stdlib_info.test_files 275 ], 276 transitive = [std_inputs], 277 order = "topological", 278 ) 279 280 if std == "std": 281 link_inputs = cc_common.create_linker_input( 282 owner = rust_std.label, 283 libraries = test_inputs, 284 ) 285 elif std == "no_std_with_alloc": 286 link_inputs = cc_common.create_linker_input( 287 owner = rust_std.label, 288 libraries = core_alloc_and_panic_inputs, 289 ) 290 else: 291 fail("Requested '{}' std mode is currently not supported.".format(std)) 292 293 allocator_inputs = None 294 if allocator_library: 295 allocator_inputs = [allocator_library[CcInfo].linking_context.linker_inputs] 296 297 cc_infos.append(CcInfo( 298 linking_context = cc_common.create_linking_context( 299 linker_inputs = depset( 300 [link_inputs], 301 transitive = allocator_inputs, 302 order = "topological", 303 ), 304 ), 305 )) 306 307 if cc_infos: 308 return cc_common.merge_cc_infos( 309 direct_cc_infos = cc_infos, 310 ) 311 return None 312 313def _symlink_sysroot_tree(ctx, name, target): 314 """Generate a set of symlinks to files from another target 315 316 Args: 317 ctx (ctx): The toolchain's context object 318 name (str): The name of the sysroot directory (typically `ctx.label.name`) 319 target (Target): A target owning files to symlink 320 321 Returns: 322 depset[File]: A depset of the generated symlink files 323 """ 324 tree_files = [] 325 for file in target.files.to_list(): 326 # Parse the path to the file relative to the workspace root so a 327 # symlink matching this path can be created within the sysroot. 328 329 # The code blow attempts to parse any workspace names out of the 330 # path. For local targets, this code is a noop. 331 if target.label.workspace_root: 332 file_path = file.path.split(target.label.workspace_root, 1)[-1] 333 else: 334 file_path = file.path 335 336 symlink = ctx.actions.declare_file("{}/{}".format(name, file_path.lstrip("/"))) 337 338 ctx.actions.symlink( 339 output = symlink, 340 target_file = file, 341 ) 342 343 tree_files.append(symlink) 344 345 return depset(tree_files) 346 347def _symlink_sysroot_bin(ctx, name, directory, target): 348 """Crete a symlink to a target file. 349 350 Args: 351 ctx (ctx): The rule's context object 352 name (str): A common name for the output directory 353 directory (str): The directory under `name` to put the file in 354 target (File): A File object to symlink to 355 356 Returns: 357 File: A newly generated symlink file 358 """ 359 symlink = ctx.actions.declare_file("{}/{}/{}".format( 360 name, 361 directory, 362 target.basename, 363 )) 364 365 ctx.actions.symlink( 366 output = symlink, 367 target_file = target, 368 is_executable = True, 369 ) 370 371 return symlink 372 373def _generate_sysroot( 374 ctx, 375 rustc, 376 rustdoc, 377 rustc_lib, 378 cargo = None, 379 clippy = None, 380 llvm_tools = None, 381 rust_std = None, 382 rustfmt = None): 383 """Generate a rust sysroot from collection of toolchain components 384 385 Args: 386 ctx (ctx): A context object from a `rust_toolchain` rule. 387 rustc (File): The path to a `rustc` executable. 388 rustdoc (File): The path to a `rustdoc` executable. 389 rustc_lib (Target): A collection of Files containing dependencies of `rustc`. 390 cargo (File, optional): The path to a `cargo` executable. 391 clippy (File, optional): The path to a `clippy-driver` executable. 392 llvm_tools (Target, optional): A collection of llvm tools used by `rustc`. 393 rust_std (Target, optional): A collection of Files containing Rust standard library components. 394 rustfmt (File, optional): The path to a `rustfmt` executable. 395 396 Returns: 397 struct: A struct of generated files representing the new sysroot 398 """ 399 name = ctx.label.name 400 401 # Define runfiles 402 direct_files = [] 403 transitive_file_sets = [] 404 405 # Rustc 406 sysroot_rustc = _symlink_sysroot_bin(ctx, name, "bin", rustc) 407 direct_files.extend([sysroot_rustc]) 408 409 # Rustc dependencies 410 sysroot_rustc_lib = None 411 if rustc_lib: 412 sysroot_rustc_lib = _symlink_sysroot_tree(ctx, name, rustc_lib) 413 transitive_file_sets.extend([sysroot_rustc_lib]) 414 415 # Rustdoc 416 sysroot_rustdoc = _symlink_sysroot_bin(ctx, name, "bin", rustdoc) 417 direct_files.extend([sysroot_rustdoc]) 418 419 # Clippy 420 sysroot_clippy = None 421 if clippy: 422 sysroot_clippy = _symlink_sysroot_bin(ctx, name, "bin", clippy) 423 direct_files.extend([sysroot_clippy]) 424 425 # Cargo 426 sysroot_cargo = None 427 if cargo: 428 sysroot_cargo = _symlink_sysroot_bin(ctx, name, "bin", cargo) 429 direct_files.extend([sysroot_cargo]) 430 431 # Rustfmt 432 sysroot_rustfmt = None 433 if rustfmt: 434 sysroot_rustfmt = _symlink_sysroot_bin(ctx, name, "bin", rustfmt) 435 direct_files.extend([sysroot_rustfmt]) 436 437 # Llvm tools 438 sysroot_llvm_tools = None 439 if llvm_tools: 440 sysroot_llvm_tools = _symlink_sysroot_tree(ctx, name, llvm_tools) 441 transitive_file_sets.extend([sysroot_llvm_tools]) 442 443 # Rust standard library 444 sysroot_rust_std = None 445 if rust_std: 446 sysroot_rust_std = _symlink_sysroot_tree(ctx, name, rust_std) 447 transitive_file_sets.extend([sysroot_rust_std]) 448 449 # Declare a file in the root of the sysroot to make locating the sysroot easy 450 sysroot_anchor = ctx.actions.declare_file("{}/rust.sysroot".format(name)) 451 ctx.actions.write( 452 output = sysroot_anchor, 453 content = "\n".join([ 454 "cargo: {}".format(cargo), 455 "clippy: {}".format(clippy), 456 "llvm_tools: {}".format(llvm_tools), 457 "rust_std: {}".format(rust_std), 458 "rustc_lib: {}".format(rustc_lib), 459 "rustc: {}".format(rustc), 460 "rustdoc: {}".format(rustdoc), 461 "rustfmt: {}".format(rustfmt), 462 ]), 463 ) 464 465 # Create a depset of all sysroot files (symlinks and their real paths) 466 all_files = depset(direct_files, transitive = transitive_file_sets) 467 468 return struct( 469 all_files = all_files, 470 cargo = sysroot_cargo, 471 clippy = sysroot_clippy, 472 rust_std = sysroot_rust_std, 473 rustc = sysroot_rustc, 474 rustc_lib = sysroot_rustc_lib, 475 rustdoc = sysroot_rustdoc, 476 rustfmt = sysroot_rustfmt, 477 sysroot_anchor = sysroot_anchor, 478 ) 479 480def _experimental_use_cc_common_link(ctx): 481 return ctx.attr.experimental_use_cc_common_link[BuildSettingInfo].value 482 483def _rust_toolchain_impl(ctx): 484 """The rust_toolchain implementation 485 486 Args: 487 ctx (ctx): The rule's context object 488 489 Returns: 490 list: A list containing the target's toolchain Provider info 491 """ 492 compilation_mode_opts = {} 493 for k, v in ctx.attr.opt_level.items(): 494 if not k in ctx.attr.debug_info: 495 fail("Compilation mode {} is not defined in debug_info but is defined opt_level".format(k)) 496 compilation_mode_opts[k] = struct(debug_info = ctx.attr.debug_info[k], opt_level = v) 497 for k, v in ctx.attr.debug_info.items(): 498 if not k in ctx.attr.opt_level: 499 fail("Compilation mode {} is not defined in opt_level but is defined debug_info".format(k)) 500 501 rename_first_party_crates = ctx.attr._rename_first_party_crates[BuildSettingInfo].value 502 third_party_dir = ctx.attr._third_party_dir[BuildSettingInfo].value 503 pipelined_compilation = ctx.attr._pipelined_compilation[BuildSettingInfo].value 504 no_std = ctx.attr._no_std[BuildSettingInfo].value 505 506 experimental_use_global_allocator = ctx.attr._experimental_use_global_allocator[BuildSettingInfo].value 507 if _experimental_use_cc_common_link(ctx): 508 if experimental_use_global_allocator and not ctx.attr.global_allocator_library: 509 fail("rust_toolchain.experimental_use_cc_common_link with --@rules_rust//rust/settings:experimental_use_global_allocator " + 510 "requires rust_toolchain.global_allocator_library to be set") 511 if not ctx.attr.allocator_library: 512 fail("rust_toolchain.experimental_use_cc_common_link requires rust_toolchain.allocator_library to be set") 513 if experimental_use_global_allocator and not _experimental_use_cc_common_link(ctx): 514 fail( 515 "Using @rules_rust//rust/settings:experimental_use_global_allocator requires" + 516 "--@rules_rust//rust/settings:experimental_use_cc_common_link to be set", 517 ) 518 519 rust_std = ctx.attr.rust_std 520 521 sysroot = _generate_sysroot( 522 ctx = ctx, 523 rustc = ctx.file.rustc, 524 rustdoc = ctx.file.rust_doc, 525 rustc_lib = ctx.attr.rustc_lib, 526 rust_std = rust_std, 527 rustfmt = ctx.file.rustfmt, 528 clippy = ctx.file.clippy_driver, 529 cargo = ctx.file.cargo, 530 llvm_tools = ctx.attr.llvm_tools, 531 ) 532 533 expanded_stdlib_linkflags = [] 534 for flag in ctx.attr.stdlib_linkflags: 535 expanded_stdlib_linkflags.append( 536 dedup_expand_location( 537 ctx, 538 flag, 539 targets = rust_std[rust_common.stdlib_info].srcs, 540 ), 541 ) 542 543 linking_context = cc_common.create_linking_context( 544 linker_inputs = depset([ 545 cc_common.create_linker_input( 546 owner = ctx.label, 547 user_link_flags = depset(expanded_stdlib_linkflags), 548 ), 549 ]), 550 ) 551 552 # Contains linker flags needed to link Rust standard library. 553 # These need to be added to linker command lines when the linker is not rustc 554 # (rustc does this automatically). Linker flags wrapped in an otherwise empty 555 # `CcInfo` to provide the flags in a way that doesn't duplicate them per target 556 # providing a `CcInfo`. 557 stdlib_linkflags_cc_info = CcInfo( 558 compilation_context = cc_common.create_compilation_context(), 559 linking_context = linking_context, 560 ) 561 562 # Determine the path and short_path of the sysroot 563 sysroot_path = sysroot.sysroot_anchor.dirname 564 sysroot_short_path, _, _ = sysroot.sysroot_anchor.short_path.rpartition("/") 565 566 # Variables for make variable expansion 567 make_variables = { 568 "RUSTC": sysroot.rustc.path, 569 "RUSTDOC": sysroot.rustdoc.path, 570 "RUST_DEFAULT_EDITION": ctx.attr.default_edition or "", 571 "RUST_SYSROOT": sysroot_path, 572 } 573 574 if sysroot.cargo: 575 make_variables.update({ 576 "CARGO": sysroot.cargo.path, 577 }) 578 579 if sysroot.rustfmt: 580 make_variables.update({ 581 "RUSTFMT": sysroot.rustfmt.path, 582 }) 583 584 make_variable_info = platform_common.TemplateVariableInfo(make_variables) 585 586 exec_triple = triple(ctx.attr.exec_triple) 587 588 if not exec_triple.system: 589 fail("No system was provided for the execution platform. Please update {}".format( 590 ctx.label, 591 )) 592 593 if ctx.attr.target_triple and ctx.attr.target_json: 594 fail("Do not specify both target_triple and target_json, either use a builtin triple or provide a custom specification file. Please update {}".format( 595 ctx.label, 596 )) 597 598 target_triple = None 599 target_json = None 600 target_arch = None 601 target_os = None 602 603 if ctx.attr.target_triple: 604 target_triple = triple(ctx.attr.target_triple) 605 target_arch = target_triple.arch 606 target_os = target_triple.system 607 608 elif ctx.attr.target_json: 609 # Ensure the data provided is valid json 610 target_json_content = json.decode(ctx.attr.target_json) 611 target_json = ctx.actions.declare_file("{}.target.json".format(ctx.label.name)) 612 613 ctx.actions.write( 614 output = target_json, 615 content = json.encode_indent(target_json_content, indent = " " * 4), 616 ) 617 618 if "arch" in target_json_content: 619 target_arch = target_json_content["arch"] 620 if "os" in target_json_content: 621 target_os = target_json_content["os"] 622 else: 623 fail("Either `target_triple` or `target_json` must be provided. Please update {}".format( 624 ctx.label, 625 )) 626 627 toolchain = platform_common.ToolchainInfo( 628 all_files = sysroot.all_files, 629 binary_ext = ctx.attr.binary_ext, 630 cargo = sysroot.cargo, 631 clippy_driver = sysroot.clippy, 632 compilation_mode_opts = compilation_mode_opts, 633 crosstool_files = ctx.files._cc_toolchain, 634 default_edition = ctx.attr.default_edition, 635 dylib_ext = ctx.attr.dylib_ext, 636 env = ctx.attr.env, 637 exec_triple = exec_triple, 638 libstd_and_allocator_ccinfo = _make_libstd_and_allocator_ccinfo(ctx, rust_std, ctx.attr.allocator_library, "std"), 639 libstd_and_global_allocator_ccinfo = _make_libstd_and_allocator_ccinfo(ctx, rust_std, ctx.attr.global_allocator_library, "std"), 640 nostd_and_global_allocator_cc_info = _make_libstd_and_allocator_ccinfo(ctx, rust_std, ctx.attr.global_allocator_library, "no_std_with_alloc"), 641 llvm_cov = ctx.file.llvm_cov, 642 llvm_profdata = ctx.file.llvm_profdata, 643 make_variables = make_variable_info, 644 rust_doc = sysroot.rustdoc, 645 rust_std = sysroot.rust_std, 646 rust_std_paths = depset([file.dirname for file in sysroot.rust_std.to_list()]), 647 rustc = sysroot.rustc, 648 rustc_lib = sysroot.rustc_lib, 649 rustfmt = sysroot.rustfmt, 650 staticlib_ext = ctx.attr.staticlib_ext, 651 stdlib_linkflags = stdlib_linkflags_cc_info, 652 extra_rustc_flags = ctx.attr.extra_rustc_flags, 653 extra_exec_rustc_flags = ctx.attr.extra_exec_rustc_flags, 654 per_crate_rustc_flags = ctx.attr.per_crate_rustc_flags, 655 sysroot = sysroot_path, 656 sysroot_short_path = sysroot_short_path, 657 target_arch = target_arch, 658 target_flag_value = target_json.path if target_json else target_triple.str, 659 target_json = target_json, 660 target_os = target_os, 661 target_triple = target_triple, 662 663 # Experimental and incompatible flags 664 _rename_first_party_crates = rename_first_party_crates, 665 _third_party_dir = third_party_dir, 666 _pipelined_compilation = pipelined_compilation, 667 _experimental_link_std_dylib = _experimental_link_std_dylib(ctx), 668 _experimental_use_cc_common_link = _experimental_use_cc_common_link(ctx), 669 _experimental_use_global_allocator = experimental_use_global_allocator, 670 _experimental_use_coverage_metadata_files = ctx.attr._experimental_use_coverage_metadata_files[BuildSettingInfo].value, 671 _experimental_toolchain_generated_sysroot = ctx.attr._experimental_toolchain_generated_sysroot[IncompatibleFlagInfo].enabled, 672 _incompatible_no_rustc_sysroot_env = ctx.attr._incompatible_no_rustc_sysroot_env[IncompatibleFlagInfo].enabled, 673 _incompatible_test_attr_crate_and_srcs_mutually_exclusive = ctx.attr._incompatible_test_attr_crate_and_srcs_mutually_exclusive[IncompatibleFlagInfo].enabled, 674 _no_std = no_std, 675 ) 676 return [ 677 toolchain, 678 make_variable_info, 679 ] 680 681def _experimental_link_std_dylib(ctx): 682 return not is_exec_configuration(ctx) and \ 683 ctx.attr.experimental_link_std_dylib[BuildSettingInfo].value and \ 684 ctx.attr.rust_std[rust_common.stdlib_info].std_dylib != None 685 686rust_toolchain = rule( 687 implementation = _rust_toolchain_impl, 688 fragments = ["cpp"], 689 attrs = { 690 "allocator_library": attr.label( 691 doc = "Target that provides allocator functions when rust_library targets are embedded in a cc_binary.", 692 default = "@rules_rust//ffi/cc/allocator_library", 693 ), 694 "binary_ext": attr.string( 695 doc = "The extension for binaries created from rustc.", 696 mandatory = True, 697 ), 698 "cargo": attr.label( 699 doc = "The location of the `cargo` binary. Can be a direct source or a filegroup containing one item.", 700 allow_single_file = True, 701 cfg = "exec", 702 ), 703 "clippy_driver": attr.label( 704 doc = "The location of the `clippy-driver` binary. Can be a direct source or a filegroup containing one item.", 705 allow_single_file = True, 706 cfg = "exec", 707 ), 708 "debug_info": attr.string_dict( 709 doc = "Rustc debug info levels per opt level", 710 default = { 711 "dbg": "2", 712 "fastbuild": "0", 713 "opt": "0", 714 }, 715 ), 716 "default_edition": attr.string( 717 doc = ( 718 "The edition to use for rust_* rules that don't specify an edition. " + 719 "If absent, every rule is required to specify its `edition` attribute." 720 ), 721 ), 722 "dylib_ext": attr.string( 723 doc = "The extension for dynamic libraries created from rustc.", 724 mandatory = True, 725 ), 726 "env": attr.string_dict( 727 doc = "Environment variables to set in actions.", 728 ), 729 "exec_triple": attr.string( 730 doc = ( 731 "The platform triple for the toolchains execution environment. " + 732 "For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations" 733 ), 734 mandatory = True, 735 ), 736 "experimental_link_std_dylib": attr.label( 737 default = Label("@rules_rust//rust/settings:experimental_link_std_dylib"), 738 doc = "Label to a boolean build setting that controls whether whether to link libstd dynamically.", 739 ), 740 "experimental_use_cc_common_link": attr.label( 741 default = Label("//rust/settings:experimental_use_cc_common_link"), 742 doc = "Label to a boolean build setting that controls whether cc_common.link is used to link rust binaries.", 743 ), 744 "extra_exec_rustc_flags": attr.string_list( 745 doc = "Extra flags to pass to rustc in exec configuration", 746 ), 747 "extra_rustc_flags": attr.string_list( 748 doc = "Extra flags to pass to rustc in non-exec configuration", 749 ), 750 "global_allocator_library": attr.label( 751 doc = "Target that provides allocator functions for when a global allocator is present.", 752 default = "@rules_rust//ffi/cc/global_allocator_library", 753 ), 754 "llvm_cov": attr.label( 755 doc = "The location of the `llvm-cov` binary. Can be a direct source or a filegroup containing one item. If None, rust code is not instrumented for coverage.", 756 allow_single_file = True, 757 cfg = "exec", 758 ), 759 "llvm_profdata": attr.label( 760 doc = "The location of the `llvm-profdata` binary. Can be a direct source or a filegroup containing one item. If `llvm_cov` is None, this can be None as well and rust code is not instrumented for coverage.", 761 allow_single_file = True, 762 cfg = "exec", 763 ), 764 "llvm_tools": attr.label( 765 doc = "LLVM tools that are shipped with the Rust toolchain.", 766 allow_files = True, 767 ), 768 "opt_level": attr.string_dict( 769 doc = "Rustc optimization levels.", 770 default = { 771 "dbg": "0", 772 "fastbuild": "0", 773 "opt": "3", 774 }, 775 ), 776 "per_crate_rustc_flags": attr.string_list( 777 doc = "Extra flags to pass to rustc in non-exec configuration", 778 ), 779 "rust_doc": attr.label( 780 doc = "The location of the `rustdoc` binary. Can be a direct source or a filegroup containing one item.", 781 allow_single_file = True, 782 cfg = "exec", 783 mandatory = True, 784 ), 785 "rust_std": attr.label( 786 doc = "The Rust standard library.", 787 mandatory = True, 788 ), 789 "rustc": attr.label( 790 doc = "The location of the `rustc` binary. Can be a direct source or a filegroup containing one item.", 791 allow_single_file = True, 792 cfg = "exec", 793 mandatory = True, 794 ), 795 "rustc_lib": attr.label( 796 doc = "The libraries used by rustc during compilation.", 797 cfg = "exec", 798 ), 799 "rustfmt": attr.label( 800 doc = "**Deprecated**: Instead see [rustfmt_toolchain](#rustfmt_toolchain)", 801 allow_single_file = True, 802 cfg = "exec", 803 ), 804 "staticlib_ext": attr.string( 805 doc = "The extension for static libraries created from rustc.", 806 mandatory = True, 807 ), 808 "stdlib_linkflags": attr.string_list( 809 doc = ( 810 "Additional linker flags to use when Rust standard library is linked by a C++ linker " + 811 "(rustc will deal with these automatically). Subject to location expansion with respect " + 812 "to the srcs of the `rust_std` attribute." 813 ), 814 mandatory = True, 815 ), 816 "target_json": attr.string( 817 doc = ("Override the target_triple with a custom target specification. " + 818 "For more details see: https://doc.rust-lang.org/rustc/targets/custom.html"), 819 ), 820 "target_triple": attr.string( 821 doc = ( 822 "The platform triple for the toolchains target environment. " + 823 "For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations" 824 ), 825 ), 826 "_cc_toolchain": attr.label( 827 default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), 828 ), 829 "_experimental_toolchain_generated_sysroot": attr.label( 830 default = Label("//rust/settings:experimental_toolchain_generated_sysroot"), 831 doc = ( 832 "Label to a boolean build setting that lets the rule knows wheter to set --sysroot to rustc" + 833 "This flag is only relevant when used together with --@rules_rust//rust/settings:experimental_toolchain_generated_sysroot." 834 ), 835 ), 836 "_experimental_use_coverage_metadata_files": attr.label( 837 default = Label("//rust/settings:experimental_use_coverage_metadata_files"), 838 ), 839 "_experimental_use_global_allocator": attr.label( 840 default = Label("//rust/settings:experimental_use_global_allocator"), 841 doc = ( 842 "Label to a boolean build setting that informs the target build whether a global allocator is being used." + 843 "This flag is only relevant when used together with --@rules_rust//rust/settings:experimental_use_global_allocator." 844 ), 845 ), 846 "_incompatible_no_rustc_sysroot_env": attr.label( 847 default = Label("//rust/settings:incompatible_no_rustc_sysroot_env"), 848 ), 849 "_incompatible_test_attr_crate_and_srcs_mutually_exclusive": attr.label( 850 default = Label("//rust/settings:incompatible_test_attr_crate_and_srcs_mutually_exclusive"), 851 ), 852 "_no_std": attr.label( 853 default = Label("//:no_std"), 854 ), 855 "_pipelined_compilation": attr.label( 856 default = Label("//rust/settings:pipelined_compilation"), 857 ), 858 "_rename_first_party_crates": attr.label( 859 default = Label("//rust/settings:rename_first_party_crates"), 860 ), 861 "_third_party_dir": attr.label( 862 default = Label("//rust/settings:third_party_dir"), 863 ), 864 }, 865 toolchains = [ 866 "@bazel_tools//tools/cpp:toolchain_type", 867 ], 868 doc = """Declares a Rust toolchain for use. 869 870This is for declaring a custom toolchain, eg. for configuring a particular version of rust or supporting a new platform. 871 872Example: 873 874Suppose the core rust team has ported the compiler to a new target CPU, called `cpuX`. This \ 875support can be used in Bazel by defining a new toolchain definition and declaration: 876 877```python 878load('@rules_rust//rust:toolchain.bzl', 'rust_toolchain') 879 880rust_toolchain( 881 name = "rust_cpuX_impl", 882 binary_ext = "", 883 dylib_ext = ".so", 884 exec_triple = "cpuX-unknown-linux-gnu", 885 rust_doc = "@rust_cpuX//:rustdoc", 886 rust_std = "@rust_cpuX//:rust_std", 887 rustc = "@rust_cpuX//:rustc", 888 rustc_lib = "@rust_cpuX//:rustc_lib", 889 staticlib_ext = ".a", 890 stdlib_linkflags = ["-lpthread", "-ldl"], 891 target_triple = "cpuX-unknown-linux-gnu", 892) 893 894toolchain( 895 name = "rust_cpuX", 896 exec_compatible_with = [ 897 "@platforms//cpu:cpuX", 898 "@platforms//os:linux", 899 ], 900 target_compatible_with = [ 901 "@platforms//cpu:cpuX", 902 "@platforms//os:linux", 903 ], 904 toolchain = ":rust_cpuX_impl", 905) 906``` 907 908Then, either add the label of the toolchain rule to `register_toolchains` in the WORKSPACE, or pass \ 909it to the `"--extra_toolchains"` flag for Bazel, and it will be used. 910 911See `@rules_rust//rust:repositories.bzl` for examples of defining the `@rust_cpuX` repository \ 912with the actual binaries and libraries. 913""", 914) 915