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.label.package, 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 cargo_clippy = None, 381 llvm_tools = None, 382 rust_std = None, 383 rustfmt = None): 384 """Generate a rust sysroot from collection of toolchain components 385 386 Args: 387 ctx (ctx): A context object from a `rust_toolchain` rule. 388 rustc (File): The path to a `rustc` executable. 389 rustdoc (File): The path to a `rustdoc` executable. 390 rustc_lib (Target): A collection of Files containing dependencies of `rustc`. 391 cargo (File, optional): The path to a `cargo` executable. 392 cargo_clippy (File, optional): The path to a `cargo-clippy` executable. 393 clippy (File, optional): The path to a `clippy-driver` executable. 394 llvm_tools (Target, optional): A collection of llvm tools used by `rustc`. 395 rust_std (Target, optional): A collection of Files containing Rust standard library components. 396 rustfmt (File, optional): The path to a `rustfmt` executable. 397 398 Returns: 399 struct: A struct of generated files representing the new sysroot 400 """ 401 name = ctx.label.name 402 403 # Define runfiles 404 direct_files = [] 405 transitive_file_sets = [] 406 407 # Rustc 408 sysroot_rustc = _symlink_sysroot_bin(ctx, name, "bin", rustc) 409 direct_files.extend([sysroot_rustc]) 410 411 # Rustc dependencies 412 sysroot_rustc_lib = None 413 if rustc_lib: 414 sysroot_rustc_lib = _symlink_sysroot_tree(ctx, name, rustc_lib) 415 transitive_file_sets.extend([sysroot_rustc_lib]) 416 417 # Rustdoc 418 sysroot_rustdoc = _symlink_sysroot_bin(ctx, name, "bin", rustdoc) 419 direct_files.extend([sysroot_rustdoc]) 420 421 # Clippy 422 sysroot_clippy = None 423 if clippy: 424 sysroot_clippy = _symlink_sysroot_bin(ctx, name, "bin", clippy) 425 direct_files.extend([sysroot_clippy]) 426 427 # Cargo 428 sysroot_cargo = None 429 if cargo: 430 sysroot_cargo = _symlink_sysroot_bin(ctx, name, "bin", cargo) 431 direct_files.extend([sysroot_cargo]) 432 433 # Cargo-clippy 434 sysroot_cargo_clippy = None 435 if cargo_clippy: 436 sysroot_cargo_clippy = _symlink_sysroot_bin(ctx, name, "bin", cargo_clippy) 437 direct_files.extend([sysroot_cargo_clippy]) 438 439 # Rustfmt 440 sysroot_rustfmt = None 441 if rustfmt: 442 sysroot_rustfmt = _symlink_sysroot_bin(ctx, name, "bin", rustfmt) 443 direct_files.extend([sysroot_rustfmt]) 444 445 # Llvm tools 446 sysroot_llvm_tools = None 447 if llvm_tools: 448 sysroot_llvm_tools = _symlink_sysroot_tree(ctx, name, llvm_tools) 449 transitive_file_sets.extend([sysroot_llvm_tools]) 450 451 # Rust standard library 452 sysroot_rust_std = None 453 if rust_std: 454 sysroot_rust_std = _symlink_sysroot_tree(ctx, name, rust_std) 455 transitive_file_sets.extend([sysroot_rust_std]) 456 457 # Made available to support $(location) expansion in stdlib_linkflags and extra_rustc_flags. 458 transitive_file_sets.append(depset(ctx.files.rust_std)) 459 460 # Declare a file in the root of the sysroot to make locating the sysroot easy 461 sysroot_anchor = ctx.actions.declare_file("{}/rust.sysroot".format(name)) 462 ctx.actions.write( 463 output = sysroot_anchor, 464 content = "\n".join([ 465 "cargo: {}".format(cargo), 466 "clippy: {}".format(clippy), 467 "cargo-clippy: {}".format(cargo_clippy), 468 "llvm_tools: {}".format(llvm_tools), 469 "rust_std: {}".format(rust_std), 470 "rustc_lib: {}".format(rustc_lib), 471 "rustc: {}".format(rustc), 472 "rustdoc: {}".format(rustdoc), 473 "rustfmt: {}".format(rustfmt), 474 ]), 475 ) 476 477 # Create a depset of all sysroot files (symlinks and their real paths) 478 all_files = depset(direct_files, transitive = transitive_file_sets) 479 480 return struct( 481 all_files = all_files, 482 cargo = sysroot_cargo, 483 clippy = sysroot_clippy, 484 cargo_clippy = sysroot_cargo_clippy, 485 rust_std = sysroot_rust_std, 486 rustc = sysroot_rustc, 487 rustc_lib = sysroot_rustc_lib, 488 rustdoc = sysroot_rustdoc, 489 rustfmt = sysroot_rustfmt, 490 sysroot_anchor = sysroot_anchor, 491 ) 492 493def _experimental_use_cc_common_link(ctx): 494 return ctx.attr.experimental_use_cc_common_link[BuildSettingInfo].value 495 496def _rust_toolchain_impl(ctx): 497 """The rust_toolchain implementation 498 499 Args: 500 ctx (ctx): The rule's context object 501 502 Returns: 503 list: A list containing the target's toolchain Provider info 504 """ 505 compilation_mode_opts = {} 506 for k, opt_level in ctx.attr.opt_level.items(): 507 if not k in ctx.attr.debug_info: 508 fail("Compilation mode {} is not defined in debug_info but is defined opt_level".format(k)) 509 if not k in ctx.attr.strip_level: 510 fail("Compilation mode {} is not defined in strip_level but is defined opt_level".format(k)) 511 compilation_mode_opts[k] = struct(debug_info = ctx.attr.debug_info[k], opt_level = opt_level, strip_level = ctx.attr.strip_level[k]) 512 for k in ctx.attr.debug_info.keys(): 513 if not k in ctx.attr.opt_level: 514 fail("Compilation mode {} is not defined in opt_level but is defined debug_info".format(k)) 515 516 rename_first_party_crates = ctx.attr._rename_first_party_crates[BuildSettingInfo].value 517 third_party_dir = ctx.attr._third_party_dir[BuildSettingInfo].value 518 pipelined_compilation = ctx.attr._pipelined_compilation[BuildSettingInfo].value 519 no_std = ctx.attr._no_std[BuildSettingInfo].value 520 521 experimental_use_global_allocator = ctx.attr._experimental_use_global_allocator[BuildSettingInfo].value 522 if _experimental_use_cc_common_link(ctx): 523 if experimental_use_global_allocator and not ctx.attr.global_allocator_library: 524 fail("rust_toolchain.experimental_use_cc_common_link with --@rules_rust//rust/settings:experimental_use_global_allocator " + 525 "requires rust_toolchain.global_allocator_library to be set") 526 if not ctx.attr.allocator_library: 527 fail("rust_toolchain.experimental_use_cc_common_link requires rust_toolchain.allocator_library to be set") 528 if experimental_use_global_allocator and not _experimental_use_cc_common_link(ctx): 529 fail( 530 "Using @rules_rust//rust/settings:experimental_use_global_allocator requires" + 531 "--@rules_rust//rust/settings:experimental_use_cc_common_link to be set", 532 ) 533 534 rust_std = ctx.attr.rust_std 535 536 sysroot = _generate_sysroot( 537 ctx = ctx, 538 rustc = ctx.file.rustc, 539 rustdoc = ctx.file.rust_doc, 540 rustc_lib = ctx.attr.rustc_lib, 541 rust_std = rust_std, 542 rustfmt = ctx.file.rustfmt, 543 clippy = ctx.file.clippy_driver, 544 cargo = ctx.file.cargo, 545 cargo_clippy = ctx.file.cargo_clippy, 546 llvm_tools = ctx.attr.llvm_tools, 547 ) 548 549 expanded_stdlib_linkflags = [] 550 for flag in ctx.attr.stdlib_linkflags: 551 expanded_stdlib_linkflags.append( 552 dedup_expand_location( 553 ctx, 554 flag, 555 targets = rust_std[rust_common.stdlib_info].srcs, 556 ), 557 ) 558 559 expanded_extra_rustc_flags = [] 560 for flag in ctx.attr.extra_rustc_flags: 561 expanded_extra_rustc_flags.append( 562 dedup_expand_location( 563 ctx, 564 flag, 565 targets = rust_std[rust_common.stdlib_info].srcs, 566 ), 567 ) 568 569 linking_context = cc_common.create_linking_context( 570 linker_inputs = depset([ 571 cc_common.create_linker_input( 572 owner = ctx.label, 573 user_link_flags = depset(expanded_stdlib_linkflags), 574 ), 575 ]), 576 ) 577 578 # Contains linker flags needed to link Rust standard library. 579 # These need to be added to linker command lines when the linker is not rustc 580 # (rustc does this automatically). Linker flags wrapped in an otherwise empty 581 # `CcInfo` to provide the flags in a way that doesn't duplicate them per target 582 # providing a `CcInfo`. 583 stdlib_linkflags_cc_info = CcInfo( 584 compilation_context = cc_common.create_compilation_context(), 585 linking_context = linking_context, 586 ) 587 588 # Determine the path and short_path of the sysroot 589 sysroot_path = sysroot.sysroot_anchor.dirname 590 sysroot_short_path, _, _ = sysroot.sysroot_anchor.short_path.rpartition("/") 591 592 # Variables for make variable expansion 593 make_variables = { 594 "RUSTC": sysroot.rustc.path, 595 "RUSTDOC": sysroot.rustdoc.path, 596 "RUST_DEFAULT_EDITION": ctx.attr.default_edition or "", 597 "RUST_SYSROOT": sysroot_path, 598 "RUST_SYSROOT_SHORT": sysroot_short_path, 599 } 600 601 if sysroot.cargo: 602 make_variables.update({ 603 "CARGO": sysroot.cargo.path, 604 }) 605 606 if sysroot.rustfmt: 607 make_variables.update({ 608 "RUSTFMT": sysroot.rustfmt.path, 609 }) 610 611 make_variable_info = platform_common.TemplateVariableInfo(make_variables) 612 613 exec_triple = triple(ctx.attr.exec_triple) 614 615 if not exec_triple.system: 616 fail("No system was provided for the execution platform. Please update {}".format( 617 ctx.label, 618 )) 619 620 if ctx.attr.target_triple and ctx.attr.target_json: 621 fail("Do not specify both target_triple and target_json, either use a builtin triple or provide a custom specification file. Please update {}".format( 622 ctx.label, 623 )) 624 625 target_triple = None 626 target_json = None 627 target_arch = None 628 target_os = None 629 630 if ctx.attr.target_triple: 631 target_triple = triple(ctx.attr.target_triple) 632 target_arch = target_triple.arch 633 target_os = target_triple.system 634 635 elif ctx.attr.target_json: 636 # Ensure the data provided is valid json 637 target_json_content = json.decode(ctx.attr.target_json) 638 target_json = ctx.actions.declare_file("{}.target.json".format(ctx.label.name)) 639 640 ctx.actions.write( 641 output = target_json, 642 content = json.encode_indent(target_json_content, indent = " " * 4), 643 ) 644 645 if "arch" in target_json_content: 646 target_arch = target_json_content["arch"] 647 if "os" in target_json_content: 648 target_os = target_json_content["os"] 649 else: 650 fail("Either `target_triple` or `target_json` must be provided. Please update {}".format( 651 ctx.label, 652 )) 653 654 toolchain = platform_common.ToolchainInfo( 655 all_files = sysroot.all_files, 656 binary_ext = ctx.attr.binary_ext, 657 cargo = sysroot.cargo, 658 clippy_driver = sysroot.clippy, 659 cargo_clippy = sysroot.cargo_clippy, 660 compilation_mode_opts = compilation_mode_opts, 661 crosstool_files = ctx.files._cc_toolchain, 662 default_edition = ctx.attr.default_edition, 663 dylib_ext = ctx.attr.dylib_ext, 664 env = ctx.attr.env, 665 exec_triple = exec_triple, 666 libstd_and_allocator_ccinfo = _make_libstd_and_allocator_ccinfo(ctx, rust_std, ctx.attr.allocator_library, "std"), 667 libstd_and_global_allocator_ccinfo = _make_libstd_and_allocator_ccinfo(ctx, rust_std, ctx.attr.global_allocator_library, "std"), 668 nostd_and_global_allocator_cc_info = _make_libstd_and_allocator_ccinfo(ctx, rust_std, ctx.attr.global_allocator_library, "no_std_with_alloc"), 669 llvm_cov = ctx.file.llvm_cov, 670 llvm_profdata = ctx.file.llvm_profdata, 671 make_variables = make_variable_info, 672 rust_doc = sysroot.rustdoc, 673 rust_std = sysroot.rust_std, 674 rust_std_paths = depset([file.dirname for file in sysroot.rust_std.to_list()]), 675 rustc = sysroot.rustc, 676 rustc_lib = sysroot.rustc_lib, 677 rustfmt = sysroot.rustfmt, 678 staticlib_ext = ctx.attr.staticlib_ext, 679 stdlib_linkflags = stdlib_linkflags_cc_info, 680 extra_rustc_flags = expanded_extra_rustc_flags, 681 extra_rustc_flags_for_crate_types = ctx.attr.extra_rustc_flags_for_crate_types, 682 extra_exec_rustc_flags = ctx.attr.extra_exec_rustc_flags, 683 per_crate_rustc_flags = ctx.attr.per_crate_rustc_flags, 684 sysroot = sysroot_path, 685 sysroot_short_path = sysroot_short_path, 686 target_arch = target_arch, 687 target_flag_value = target_json.path if target_json else target_triple.str, 688 target_json = target_json, 689 target_os = target_os, 690 target_triple = target_triple, 691 692 # Experimental and incompatible flags 693 _rename_first_party_crates = rename_first_party_crates, 694 _third_party_dir = third_party_dir, 695 _pipelined_compilation = pipelined_compilation, 696 _experimental_link_std_dylib = _experimental_link_std_dylib(ctx), 697 _experimental_use_cc_common_link = _experimental_use_cc_common_link(ctx), 698 _experimental_use_global_allocator = experimental_use_global_allocator, 699 _experimental_use_coverage_metadata_files = ctx.attr._experimental_use_coverage_metadata_files[BuildSettingInfo].value, 700 _experimental_toolchain_generated_sysroot = ctx.attr._experimental_toolchain_generated_sysroot[IncompatibleFlagInfo].enabled, 701 _incompatible_no_rustc_sysroot_env = ctx.attr._incompatible_no_rustc_sysroot_env[IncompatibleFlagInfo].enabled, 702 _no_std = no_std, 703 ) 704 return [ 705 toolchain, 706 make_variable_info, 707 ] 708 709def _experimental_link_std_dylib(ctx): 710 return not is_exec_configuration(ctx) and \ 711 ctx.attr.experimental_link_std_dylib[BuildSettingInfo].value and \ 712 ctx.attr.rust_std[rust_common.stdlib_info].std_dylib != None 713 714rust_toolchain = rule( 715 implementation = _rust_toolchain_impl, 716 fragments = ["cpp"], 717 attrs = { 718 "allocator_library": attr.label( 719 doc = "Target that provides allocator functions when rust_library targets are embedded in a cc_binary.", 720 default = "@rules_rust//ffi/cc/allocator_library", 721 ), 722 "binary_ext": attr.string( 723 doc = "The extension for binaries created from rustc.", 724 mandatory = True, 725 ), 726 "cargo": attr.label( 727 doc = "The location of the `cargo` binary. Can be a direct source or a filegroup containing one item.", 728 allow_single_file = True, 729 cfg = "exec", 730 ), 731 "cargo_clippy": attr.label( 732 doc = "The location of the `cargo_clippy` binary. Can be a direct source or a filegroup containing one item.", 733 allow_single_file = True, 734 cfg = "exec", 735 ), 736 "clippy_driver": attr.label( 737 doc = "The location of the `clippy-driver` binary. Can be a direct source or a filegroup containing one item.", 738 allow_single_file = True, 739 cfg = "exec", 740 ), 741 "debug_info": attr.string_dict( 742 doc = "Rustc debug info levels per opt level", 743 default = { 744 "dbg": "2", 745 "fastbuild": "0", 746 "opt": "0", 747 }, 748 ), 749 "default_edition": attr.string( 750 doc = ( 751 "The edition to use for rust_* rules that don't specify an edition. " + 752 "If absent, every rule is required to specify its `edition` attribute." 753 ), 754 ), 755 "dylib_ext": attr.string( 756 doc = "The extension for dynamic libraries created from rustc.", 757 mandatory = True, 758 ), 759 "env": attr.string_dict( 760 doc = "Environment variables to set in actions.", 761 ), 762 "exec_triple": attr.string( 763 doc = ( 764 "The platform triple for the toolchains execution environment. " + 765 "For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations" 766 ), 767 mandatory = True, 768 ), 769 "experimental_link_std_dylib": attr.label( 770 default = Label("@rules_rust//rust/settings:experimental_link_std_dylib"), 771 doc = "Label to a boolean build setting that controls whether whether to link libstd dynamically.", 772 ), 773 "experimental_use_cc_common_link": attr.label( 774 default = Label("//rust/settings:experimental_use_cc_common_link"), 775 doc = "Label to a boolean build setting that controls whether cc_common.link is used to link rust binaries.", 776 ), 777 "extra_exec_rustc_flags": attr.string_list( 778 doc = "Extra flags to pass to rustc in exec configuration", 779 ), 780 "extra_rustc_flags": attr.string_list( 781 doc = "Extra flags to pass to rustc in non-exec configuration. Subject to location expansion with respect to the srcs of the `rust_std` attribute.", 782 ), 783 "extra_rustc_flags_for_crate_types": attr.string_list_dict( 784 doc = "Extra flags to pass to rustc based on crate type", 785 ), 786 "global_allocator_library": attr.label( 787 doc = "Target that provides allocator functions for when a global allocator is present.", 788 default = "@rules_rust//ffi/cc/global_allocator_library", 789 ), 790 "llvm_cov": attr.label( 791 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.", 792 allow_single_file = True, 793 cfg = "exec", 794 ), 795 "llvm_profdata": attr.label( 796 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.", 797 allow_single_file = True, 798 cfg = "exec", 799 ), 800 "llvm_tools": attr.label( 801 doc = "LLVM tools that are shipped with the Rust toolchain.", 802 allow_files = True, 803 ), 804 "opt_level": attr.string_dict( 805 doc = "Rustc optimization levels.", 806 default = { 807 "dbg": "0", 808 "fastbuild": "0", 809 "opt": "3", 810 }, 811 ), 812 "per_crate_rustc_flags": attr.string_list( 813 doc = "Extra flags to pass to rustc in non-exec configuration", 814 ), 815 "rust_doc": attr.label( 816 doc = "The location of the `rustdoc` binary. Can be a direct source or a filegroup containing one item.", 817 allow_single_file = True, 818 cfg = "exec", 819 mandatory = True, 820 ), 821 "rust_std": attr.label( 822 doc = "The Rust standard library.", 823 mandatory = True, 824 ), 825 "rustc": attr.label( 826 doc = "The location of the `rustc` binary. Can be a direct source or a filegroup containing one item.", 827 allow_single_file = True, 828 cfg = "exec", 829 mandatory = True, 830 ), 831 "rustc_lib": attr.label( 832 doc = "The libraries used by rustc during compilation.", 833 cfg = "exec", 834 ), 835 "rustfmt": attr.label( 836 doc = "**Deprecated**: Instead see [rustfmt_toolchain](#rustfmt_toolchain)", 837 allow_single_file = True, 838 cfg = "exec", 839 ), 840 "staticlib_ext": attr.string( 841 doc = "The extension for static libraries created from rustc.", 842 mandatory = True, 843 ), 844 "stdlib_linkflags": attr.string_list( 845 doc = ( 846 "Additional linker flags to use when Rust standard library is linked by a C++ linker " + 847 "(rustc will deal with these automatically). Subject to location expansion with respect " + 848 "to the srcs of the `rust_std` attribute." 849 ), 850 mandatory = True, 851 ), 852 "strip_level": attr.string_dict( 853 doc = ( 854 "Rustc strip levels. For all potential options, see " + 855 "https://doc.rust-lang.org/rustc/codegen-options/index.html#strip" 856 ), 857 default = { 858 "dbg": "none", 859 "fastbuild": "none", 860 "opt": "debuginfo", 861 }, 862 ), 863 "target_json": attr.string( 864 doc = ("Override the target_triple with a custom target specification. " + 865 "For more details see: https://doc.rust-lang.org/rustc/targets/custom.html"), 866 ), 867 "target_triple": attr.string( 868 doc = ( 869 "The platform triple for the toolchains target environment. " + 870 "For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations" 871 ), 872 ), 873 "_cc_toolchain": attr.label( 874 default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), 875 ), 876 "_experimental_toolchain_generated_sysroot": attr.label( 877 default = Label("//rust/settings:experimental_toolchain_generated_sysroot"), 878 doc = ( 879 "Label to a boolean build setting that lets the rule knows wheter to set --sysroot to rustc" + 880 "This flag is only relevant when used together with --@rules_rust//rust/settings:experimental_toolchain_generated_sysroot." 881 ), 882 ), 883 "_experimental_use_coverage_metadata_files": attr.label( 884 default = Label("//rust/settings:experimental_use_coverage_metadata_files"), 885 ), 886 "_experimental_use_global_allocator": attr.label( 887 default = Label("//rust/settings:experimental_use_global_allocator"), 888 doc = ( 889 "Label to a boolean build setting that informs the target build whether a global allocator is being used." + 890 "This flag is only relevant when used together with --@rules_rust//rust/settings:experimental_use_global_allocator." 891 ), 892 ), 893 "_incompatible_no_rustc_sysroot_env": attr.label( 894 default = Label("//rust/settings:incompatible_no_rustc_sysroot_env"), 895 ), 896 "_no_std": attr.label( 897 default = Label("//:no_std"), 898 ), 899 "_pipelined_compilation": attr.label( 900 default = Label("//rust/settings:pipelined_compilation"), 901 ), 902 "_rename_first_party_crates": attr.label( 903 default = Label("//rust/settings:rename_first_party_crates"), 904 ), 905 "_third_party_dir": attr.label( 906 default = Label("//rust/settings:third_party_dir"), 907 ), 908 }, 909 toolchains = [ 910 "@bazel_tools//tools/cpp:toolchain_type", 911 ], 912 doc = """Declares a Rust toolchain for use. 913 914This is for declaring a custom toolchain, eg. for configuring a particular version of rust or supporting a new platform. 915 916Example: 917 918Suppose the core rust team has ported the compiler to a new target CPU, called `cpuX`. This \ 919support can be used in Bazel by defining a new toolchain definition and declaration: 920 921```python 922load('@rules_rust//rust:toolchain.bzl', 'rust_toolchain') 923 924rust_toolchain( 925 name = "rust_cpuX_impl", 926 binary_ext = "", 927 dylib_ext = ".so", 928 exec_triple = "cpuX-unknown-linux-gnu", 929 rust_doc = "@rust_cpuX//:rustdoc", 930 rust_std = "@rust_cpuX//:rust_std", 931 rustc = "@rust_cpuX//:rustc", 932 rustc_lib = "@rust_cpuX//:rustc_lib", 933 staticlib_ext = ".a", 934 stdlib_linkflags = ["-lpthread", "-ldl"], 935 target_triple = "cpuX-unknown-linux-gnu", 936) 937 938toolchain( 939 name = "rust_cpuX", 940 exec_compatible_with = [ 941 "@platforms//cpu:cpuX", 942 "@platforms//os:linux", 943 ], 944 target_compatible_with = [ 945 "@platforms//cpu:cpuX", 946 "@platforms//os:linux", 947 ], 948 toolchain = ":rust_cpuX_impl", 949) 950``` 951 952Then, either add the label of the toolchain rule to `register_toolchains` in the WORKSPACE, or pass \ 953it to the `"--extra_toolchains"` flag for Bazel, and it will be used. 954 955See `@rules_rust//rust:repositories.bzl` for examples of defining the `@rust_cpuX` repository \ 956with the actual binaries and libraries. 957""", 958) 959