1"""Utility macros for use in rules_rust repository rules""" 2 3load("//rust:known_shas.bzl", "FILE_KEY_TO_SHA") 4load( 5 "//rust/platform:triple_mappings.bzl", 6 "system_to_binary_ext", 7 "system_to_dylib_ext", 8 "system_to_staticlib_ext", 9 "system_to_stdlib_linkflags", 10) 11load("//rust/private:common.bzl", "DEFAULT_NIGHTLY_ISO_DATE") 12 13DEFAULT_TOOLCHAIN_NAME_PREFIX = "toolchain_for" 14DEFAULT_STATIC_RUST_URL_TEMPLATES = ["https://static.rust-lang.org/dist/{}.tar.xz"] 15DEFAULT_NIGHTLY_VERSION = "nightly/{}".format(DEFAULT_NIGHTLY_ISO_DATE) 16DEFAULT_EXTRA_TARGET_TRIPLES = ["wasm32-unknown-unknown", "wasm32-wasi"] 17 18TINYJSON_KWARGS = dict( 19 name = "rules_rust_tinyjson", 20 sha256 = "9ab95735ea2c8fd51154d01e39cf13912a78071c2d89abc49a7ef102a7dd725a", 21 url = "https://crates.io/api/v1/crates/tinyjson/2.5.1/download", 22 strip_prefix = "tinyjson-2.5.1", 23 type = "tar.gz", 24 build_file = "@rules_rust//util/process_wrapper:BUILD.tinyjson.bazel", 25) 26 27_build_file_for_compiler_template = """\ 28filegroup( 29 name = "rustc", 30 srcs = ["bin/rustc{binary_ext}"], 31 visibility = ["//visibility:public"], 32) 33 34filegroup( 35 name = "rustc_lib", 36 srcs = glob( 37 [ 38 "bin/*{dylib_ext}", 39 "lib/*{dylib_ext}", 40 "lib/rustlib/{target_triple}/codegen-backends/*{dylib_ext}", 41 "lib/rustlib/{target_triple}/bin/rust-lld{binary_ext}", 42 "lib/rustlib/{target_triple}/lib/*{dylib_ext}", 43 ], 44 allow_empty = True, 45 ), 46 visibility = ["//visibility:public"], 47) 48 49filegroup( 50 name = "rustdoc", 51 srcs = ["bin/rustdoc{binary_ext}"], 52 visibility = ["//visibility:public"], 53) 54""" 55 56def BUILD_for_compiler(target_triple): 57 """Emits a BUILD file the compiler archive. 58 59 Args: 60 target_triple (str): The triple of the target platform 61 62 Returns: 63 str: The contents of a BUILD file 64 """ 65 return _build_file_for_compiler_template.format( 66 binary_ext = system_to_binary_ext(target_triple.system), 67 staticlib_ext = system_to_staticlib_ext(target_triple.system), 68 dylib_ext = system_to_dylib_ext(target_triple.system), 69 target_triple = target_triple.str, 70 ) 71 72_build_file_for_cargo_template = """\ 73filegroup( 74 name = "cargo", 75 srcs = ["bin/cargo{binary_ext}"], 76 visibility = ["//visibility:public"], 77)""" 78 79def BUILD_for_cargo(target_triple): 80 """Emits a BUILD file the cargo archive. 81 82 Args: 83 target_triple (str): The triple of the target platform 84 85 Returns: 86 str: The contents of a BUILD file 87 """ 88 return _build_file_for_cargo_template.format( 89 binary_ext = system_to_binary_ext(target_triple.system), 90 ) 91 92_build_file_for_rustfmt_template = """\ 93filegroup( 94 name = "rustfmt_bin", 95 srcs = ["bin/rustfmt{binary_ext}"], 96 visibility = ["//visibility:public"], 97) 98 99sh_binary( 100 name = "rustfmt", 101 srcs = [":rustfmt_bin"], 102 visibility = ["//visibility:public"], 103) 104""" 105 106def BUILD_for_rustfmt(target_triple): 107 """Emits a BUILD file the rustfmt archive. 108 109 Args: 110 target_triple (str): The triple of the target platform 111 112 Returns: 113 str: The contents of a BUILD file 114 """ 115 return _build_file_for_rustfmt_template.format( 116 binary_ext = system_to_binary_ext(target_triple.system), 117 ) 118 119_build_file_for_clippy_template = """\ 120filegroup( 121 name = "clippy_driver_bin", 122 srcs = ["bin/clippy-driver{binary_ext}"], 123 visibility = ["//visibility:public"], 124) 125""" 126 127_build_file_for_rust_analyzer_proc_macro_srv = """\ 128filegroup( 129 name = "rust_analyzer_proc_macro_srv", 130 srcs = ["libexec/rust-analyzer-proc-macro-srv{binary_ext}"], 131 visibility = ["//visibility:public"], 132) 133""" 134 135def BUILD_for_rust_analyzer_proc_macro_srv(exec_triple): 136 """Emits a BUILD file the rust_analyzer_proc_macro_srv archive. 137 138 Args: 139 exec_triple (str): The triple of the exec platform 140 Returns: 141 str: The contents of a BUILD file 142 """ 143 return _build_file_for_rust_analyzer_proc_macro_srv.format( 144 binary_ext = system_to_binary_ext(exec_triple.system), 145 ) 146 147def BUILD_for_clippy(target_triple): 148 """Emits a BUILD file the clippy archive. 149 150 Args: 151 target_triple (str): The triple of the target platform 152 153 Returns: 154 str: The contents of a BUILD file 155 """ 156 return _build_file_for_clippy_template.format( 157 binary_ext = system_to_binary_ext(target_triple.system), 158 ) 159 160_build_file_for_llvm_tools = """\ 161filegroup( 162 name = "llvm_cov_bin", 163 srcs = ["lib/rustlib/{target_triple}/bin/llvm-cov{binary_ext}"], 164 visibility = ["//visibility:public"], 165) 166 167filegroup( 168 name = "llvm_profdata_bin", 169 srcs = ["lib/rustlib/{target_triple}/bin/llvm-profdata{binary_ext}"], 170 visibility = ["//visibility:public"], 171) 172""" 173 174def BUILD_for_llvm_tools(target_triple): 175 """Emits a BUILD file the llvm-tools binaries. 176 177 Args: 178 target_triple (struct): The triple of the target platform 179 180 Returns: 181 str: The contents of a BUILD file 182 """ 183 return _build_file_for_llvm_tools.format( 184 binary_ext = system_to_binary_ext(target_triple.system), 185 target_triple = target_triple.str, 186 ) 187 188_build_file_for_stdlib_template = """\ 189load("@rules_rust//rust:toolchain.bzl", "rust_stdlib_filegroup") 190 191rust_stdlib_filegroup( 192 name = "rust_std-{target_triple}", 193 srcs = glob( 194 [ 195 "lib/rustlib/{target_triple}/lib/*.rlib", 196 "lib/rustlib/{target_triple}/lib/*{dylib_ext}", 197 "lib/rustlib/{target_triple}/lib/*{staticlib_ext}", 198 "lib/rustlib/{target_triple}/lib/self-contained/**", 199 ], 200 # Some patterns (e.g. `lib/*.a`) don't match anything, see https://github.com/bazelbuild/rules_rust/pull/245 201 allow_empty = True, 202 ), 203 visibility = ["//visibility:public"], 204) 205 206# For legacy support 207alias( 208 name = "rust_lib-{target_triple}", 209 actual = "rust_std-{target_triple}", 210 visibility = ["//visibility:public"], 211) 212""" 213 214def BUILD_for_stdlib(target_triple): 215 """Emits a BUILD file the stdlib archive. 216 217 Args: 218 target_triple (triple): The triple of the target platform 219 220 Returns: 221 str: The contents of a BUILD file 222 """ 223 return _build_file_for_stdlib_template.format( 224 binary_ext = system_to_binary_ext(target_triple.system), 225 staticlib_ext = system_to_staticlib_ext(target_triple.system), 226 dylib_ext = system_to_dylib_ext(target_triple.system), 227 target_triple = target_triple.str, 228 ) 229 230_build_file_for_rust_toolchain_template = """\ 231load("@rules_rust//rust:toolchain.bzl", "rust_toolchain") 232 233rust_toolchain( 234 name = "{toolchain_name}", 235 rust_doc = "//:rustdoc", 236 rust_std = "//:rust_std-{target_triple}", 237 rustc = "//:rustc", 238 rustfmt = {rustfmt_label}, 239 cargo = "//:cargo", 240 clippy_driver = "//:clippy_driver_bin", 241 llvm_cov = {llvm_cov_label}, 242 llvm_profdata = {llvm_profdata_label}, 243 rustc_lib = "//:rustc_lib", 244 allocator_library = {allocator_library}, 245 global_allocator_library = {global_allocator_library}, 246 binary_ext = "{binary_ext}", 247 staticlib_ext = "{staticlib_ext}", 248 dylib_ext = "{dylib_ext}", 249 stdlib_linkflags = [{stdlib_linkflags}], 250 default_edition = "{default_edition}", 251 exec_triple = "{exec_triple}", 252 target_triple = "{target_triple}", 253 visibility = ["//visibility:public"], 254 extra_rustc_flags = {extra_rustc_flags}, 255 extra_exec_rustc_flags = {extra_exec_rustc_flags}, 256 opt_level = {opt_level}, 257) 258""" 259 260def BUILD_for_rust_toolchain( 261 name, 262 exec_triple, 263 target_triple, 264 allocator_library, 265 global_allocator_library, 266 default_edition, 267 include_rustfmt, 268 include_llvm_tools, 269 stdlib_linkflags = None, 270 extra_rustc_flags = None, 271 extra_exec_rustc_flags = None, 272 opt_level = None): 273 """Emits a toolchain declaration to match an existing compiler and stdlib. 274 275 Args: 276 name (str): The name of the toolchain declaration 277 exec_triple (triple): The rust-style target that this compiler runs on 278 target_triple (triple): The rust-style target triple of the tool 279 allocator_library (str, optional): Target that provides allocator functions when rust_library targets are embedded in a cc_binary. 280 global_allocator_library (str, optional): Target that provides allocator functions when a global allocator is used with cc_common_link. 281 This target is only used in the target configuration; exec builds still use the symbols provided 282 by the `allocator_library` target. 283 default_edition (str): Default Rust edition. 284 include_rustfmt (bool): Whether rustfmt is present in the toolchain. 285 include_llvm_tools (bool): Whether llvm-tools are present in the toolchain. 286 stdlib_linkflags (list, optional): Overriden flags needed for linking to rust 287 stdlib, akin to BAZEL_LINKLIBS. Defaults to 288 None. 289 extra_rustc_flags (list, optional): Extra flags to pass to rustc in non-exec configuration. 290 extra_exec_rustc_flags (list, optional): Extra flags to pass to rustc in exec configuration. 291 opt_level (dict, optional): Optimization level config for this toolchain. 292 293 Returns: 294 str: A rendered template of a `rust_toolchain` declaration 295 """ 296 if stdlib_linkflags == None: 297 stdlib_linkflags = ", ".join(['"%s"' % x for x in system_to_stdlib_linkflags(target_triple.system)]) 298 299 rustfmt_label = "None" 300 if include_rustfmt: 301 rustfmt_label = "\"//:rustfmt_bin\"" 302 llvm_cov_label = "None" 303 llvm_profdata_label = "None" 304 if include_llvm_tools: 305 llvm_cov_label = "\"//:llvm_cov_bin\"" 306 llvm_profdata_label = "\"//:llvm_profdata_bin\"" 307 allocator_library_label = "None" 308 if allocator_library: 309 allocator_library_label = "\"{allocator_library}\"".format(allocator_library = allocator_library) 310 global_allocator_library_label = "None" 311 if global_allocator_library: 312 global_allocator_library_label = "\"{global_allocator_library}\"".format(global_allocator_library = global_allocator_library) 313 314 return _build_file_for_rust_toolchain_template.format( 315 toolchain_name = name, 316 binary_ext = system_to_binary_ext(target_triple.system), 317 staticlib_ext = system_to_staticlib_ext(target_triple.system), 318 dylib_ext = system_to_dylib_ext(target_triple.system), 319 allocator_library = allocator_library_label, 320 global_allocator_library = global_allocator_library_label, 321 stdlib_linkflags = stdlib_linkflags, 322 default_edition = default_edition, 323 exec_triple = exec_triple.str, 324 target_triple = target_triple.str, 325 rustfmt_label = rustfmt_label, 326 llvm_cov_label = llvm_cov_label, 327 llvm_profdata_label = llvm_profdata_label, 328 extra_rustc_flags = extra_rustc_flags, 329 extra_exec_rustc_flags = extra_exec_rustc_flags, 330 opt_level = opt_level, 331 ) 332 333_build_file_for_toolchain_template = """\ 334toolchain( 335 name = "{name}", 336 exec_compatible_with = {exec_constraint_sets_serialized}, 337 target_compatible_with = {target_constraint_sets_serialized}, 338 toolchain = "{toolchain}", 339 toolchain_type = "{toolchain_type}", 340 {target_settings} 341) 342""" 343 344def BUILD_for_toolchain( 345 name, 346 toolchain, 347 toolchain_type, 348 target_settings, 349 target_compatible_with, 350 exec_compatible_with): 351 target_settings_value = "target_settings = {},".format(json.encode(target_settings)) if target_settings else "# target_settings = []" 352 353 return _build_file_for_toolchain_template.format( 354 name = name, 355 exec_constraint_sets_serialized = json.encode(exec_compatible_with), 356 target_constraint_sets_serialized = json.encode(target_compatible_with), 357 toolchain = toolchain, 358 toolchain_type = toolchain_type, 359 target_settings = target_settings_value, 360 ) 361 362def load_rustfmt(ctx, target_triple, version, iso_date): 363 """Loads a rustfmt binary and yields corresponding BUILD for it 364 365 Args: 366 ctx (repository_ctx): The repository rule's context object. 367 target_triple (struct): The platform triple to download rustfmt for. 368 version (str): The version or channel of rustfmt. 369 iso_date (str): The date of the tool (or None, if the version is a specific version). 370 371 Returns: 372 str: The BUILD file contents for this rustfmt binary 373 """ 374 375 load_arbitrary_tool( 376 ctx, 377 iso_date = iso_date, 378 target_triple = target_triple, 379 tool_name = "rustfmt", 380 tool_subdirectories = ["rustfmt-preview"], 381 version = version, 382 ) 383 384 return BUILD_for_rustfmt(target_triple) 385 386def load_rust_compiler(ctx, iso_date, target_triple, version): 387 """Loads a rust compiler and yields corresponding BUILD for it 388 389 Args: 390 ctx (repository_ctx): A repository_ctx. 391 iso_date (str): The date of the tool (or None, if the version is a specific version). 392 target_triple (struct): The Rust-style target that this compiler runs on. 393 version (str): The version of the tool among \"nightly\", \"beta\", or an exact version. 394 395 Returns: 396 str: The BUILD file contents for this compiler and compiler library 397 """ 398 399 load_arbitrary_tool( 400 ctx, 401 iso_date = iso_date, 402 target_triple = target_triple, 403 tool_name = "rustc", 404 tool_subdirectories = ["rustc"], 405 version = version, 406 ) 407 408 return BUILD_for_compiler(target_triple) 409 410def load_clippy(ctx, iso_date, target_triple, version): 411 """Loads Clippy and yields corresponding BUILD for it 412 413 Args: 414 ctx (repository_ctx): A repository_ctx. 415 iso_date (str): The date of the tool (or None, if the version is a specific version). 416 target_triple (struct): The Rust-style target that this compiler runs on. 417 version (str): The version of the tool among \"nightly\", \"beta\", or an exact version. 418 419 Returns: 420 str: The BUILD file contents for Clippy 421 """ 422 load_arbitrary_tool( 423 ctx, 424 iso_date = iso_date, 425 target_triple = target_triple, 426 tool_name = "clippy", 427 tool_subdirectories = ["clippy-preview"], 428 version = version, 429 ) 430 431 return BUILD_for_clippy(target_triple) 432 433def load_cargo(ctx, iso_date, target_triple, version): 434 """Loads Cargo and yields corresponding BUILD for it 435 436 Args: 437 ctx (repository_ctx): A repository_ctx. 438 iso_date (str): The date of the tool (or None, if the version is a specific version). 439 target_triple (struct): The Rust-style target that this compiler runs on. 440 version (str): The version of the tool among \"nightly\", \"beta\", or an exact version. 441 442 Returns: 443 str: The BUILD file contents for Cargo 444 """ 445 446 load_arbitrary_tool( 447 ctx, 448 iso_date = iso_date, 449 target_triple = target_triple, 450 tool_name = "cargo", 451 tool_subdirectories = ["cargo"], 452 version = version, 453 ) 454 455 return BUILD_for_cargo(target_triple) 456 457def includes_rust_analyzer_proc_macro_srv(version, iso_date): 458 """Determine whether or not the rust_analyzer_proc_macro_srv binary in available in the given version of Rust. 459 460 Args: 461 version (str): The version of the tool among \"nightly\", \"beta\", or an exact version. 462 iso_date (str): The date of the tool (or None, if the version is a specific version). 463 464 Returns: 465 bool: Whether or not the binary is expected to be included 466 """ 467 468 if version == "nightly": 469 return iso_date >= "2022-09-21" 470 elif version == "beta": 471 return False 472 elif version >= "1.64.0": 473 return True 474 475 return False 476 477def load_rust_src(ctx, iso_date, version, sha256 = ""): 478 """Loads the rust source code. Used by the rust-analyzer rust-project.json generator. 479 480 Args: 481 ctx (ctx): A repository_ctx. 482 version (str): The version of the tool among "nightly", "beta', or an exact version. 483 iso_date (str): The date of the tool (or None, if the version is a specific version). 484 sha256 (str): The sha256 value for the `rust-src` artifact 485 """ 486 tool_suburl = produce_tool_suburl("rust-src", None, version, iso_date) 487 url = ctx.attr.urls[0].format(tool_suburl) 488 489 tool_path = produce_tool_path("rust-src", version, None) 490 archive_path = tool_path + _get_tool_extension(getattr(ctx.attr, "urls", None)) 491 sha256 = sha256 or getattr(ctx.attr, "sha256s", {}).get(archive_path) or FILE_KEY_TO_SHA.get(archive_path) or "" 492 ctx.download_and_extract( 493 url, 494 output = "lib/rustlib/src", 495 sha256 = sha256, 496 auth = _make_auth_dict(ctx, [url]), 497 stripPrefix = "{}/rust-src/lib/rustlib/src/rust".format(tool_path), 498 ) 499 ctx.file( 500 "lib/rustlib/src/BUILD.bazel", 501 """\ 502filegroup( 503 name = "rustc_srcs", 504 srcs = glob(["**/*"]), 505 visibility = ["//visibility:public"], 506)""", 507 ) 508 509_build_file_for_rust_analyzer_toolchain_template = """\ 510load("@rules_rust//rust:toolchain.bzl", "rust_analyzer_toolchain") 511 512rust_analyzer_toolchain( 513 name = "{name}", 514 proc_macro_srv = {proc_macro_srv}, 515 rustc = "{rustc}", 516 rustc_srcs = "//lib/rustlib/src:rustc_srcs", 517 visibility = ["//visibility:public"], 518) 519""" 520 521def BUILD_for_rust_analyzer_toolchain(name, rustc, proc_macro_srv): 522 return _build_file_for_rust_analyzer_toolchain_template.format( 523 name = name, 524 rustc = rustc, 525 proc_macro_srv = repr(proc_macro_srv), 526 ) 527 528_build_file_for_rustfmt_toolchain_template = """\ 529load("@rules_rust//rust:toolchain.bzl", "rustfmt_toolchain") 530 531rustfmt_toolchain( 532 name = "{name}", 533 rustfmt = "{rustfmt}", 534 rustc = "{rustc}", 535 rustc_lib = "{rustc_lib}", 536 visibility = ["//visibility:public"], 537) 538""" 539 540def BUILD_for_rustfmt_toolchain(name, rustfmt, rustc, rustc_lib): 541 return _build_file_for_rustfmt_toolchain_template.format( 542 name = name, 543 rustfmt = rustfmt, 544 rustc = rustc, 545 rustc_lib = rustc_lib, 546 ) 547 548def load_rust_stdlib(ctx, target_triple): 549 """Loads a rust standard library and yields corresponding BUILD for it 550 551 Args: 552 ctx (repository_ctx): A repository_ctx. 553 target_triple (struct): The rust-style target triple of the tool 554 555 Returns: 556 str: The BUILD file contents for this stdlib 557 """ 558 559 load_arbitrary_tool( 560 ctx, 561 iso_date = ctx.attr.iso_date, 562 target_triple = target_triple, 563 tool_name = "rust-std", 564 tool_subdirectories = ["rust-std-{}".format(target_triple.str)], 565 version = ctx.attr.version, 566 ) 567 568 return BUILD_for_stdlib(target_triple) 569 570def load_rustc_dev_nightly(ctx, target_triple): 571 """Loads the nightly rustc dev component 572 573 Args: 574 ctx: A repository_ctx. 575 target_triple: The rust-style target triple of the tool 576 """ 577 578 subdir_name = "rustc-dev" 579 if ctx.attr.iso_date < "2020-12-24": 580 subdir_name = "rustc-dev-{}".format(target_triple) 581 582 load_arbitrary_tool( 583 ctx, 584 iso_date = ctx.attr.iso_date, 585 target_triple = target_triple, 586 tool_name = "rustc-dev", 587 tool_subdirectories = [subdir_name], 588 version = ctx.attr.version, 589 ) 590 591def load_llvm_tools(ctx, target_triple): 592 """Loads the llvm tools 593 594 Args: 595 ctx: A repository_ctx. 596 target_triple: The rust-style target triple of the tool 597 """ 598 load_arbitrary_tool( 599 ctx, 600 iso_date = ctx.attr.iso_date, 601 target_triple = target_triple, 602 tool_name = "llvm-tools", 603 tool_subdirectories = ["llvm-tools-preview"], 604 version = ctx.attr.version, 605 ) 606 607 return BUILD_for_llvm_tools(target_triple) 608 609def check_version_valid(version, iso_date, param_prefix = ""): 610 """Verifies that the provided rust version and iso_date make sense. 611 612 Args: 613 version (str): The rustc version 614 iso_date (str): The rustc nightly version's iso date 615 param_prefix (str, optional): The name of the tool who's version is being checked. 616 """ 617 618 if not version and iso_date: 619 fail("{param_prefix}iso_date must be paired with a {param_prefix}version".format(param_prefix = param_prefix)) 620 621 if version in ("beta", "nightly") and not iso_date: 622 fail("{param_prefix}iso_date must be specified if version is 'beta' or 'nightly'".format(param_prefix = param_prefix)) 623 624def produce_tool_suburl(tool_name, target_triple, version, iso_date = None): 625 """Produces a fully qualified Rust tool name for URL 626 627 Args: 628 tool_name (str): The name of the tool per `static.rust-lang.org`. 629 target_triple (struct): The rust-style target triple of the tool. 630 version (str): The version of the tool among "nightly", "beta', or an exact version. 631 iso_date (str): The date of the tool (or None, if the version is a specific version). 632 633 Returns: 634 str: The fully qualified url path for the specified tool. 635 """ 636 path = produce_tool_path(tool_name, version, target_triple) 637 return iso_date + "/" + path if (iso_date and version in ("beta", "nightly")) else path 638 639def produce_tool_path(tool_name, version, target_triple = None): 640 """Produces a qualified Rust tool name 641 642 Args: 643 tool_name (str): The name of the tool per static.rust-lang.org 644 version (str): The version of the tool among "nightly", "beta', or an exact version. 645 target_triple (struct, optional): The rust-style target triple of the tool 646 647 Returns: 648 str: The qualified path for the specified tool. 649 """ 650 if not tool_name: 651 fail("No tool name was provided") 652 if not version: 653 fail("No tool version was provided") 654 655 # Not all tools require a triple. E.g. `rustc_src` (Rust source files for rust-analyzer). 656 platform_triple = None 657 if target_triple: 658 platform_triple = target_triple.str 659 660 return "-".join([e for e in [tool_name, version, platform_triple] if e]) 661 662def lookup_tool_sha256(ctx, tool_name, target_triple, version, iso_date, sha256): 663 """Looks up the sha256 hash of a specific tool archive. 664 665 The lookup order is: 666 667 1. The sha256s dict in the context attributes; 668 2. The list of sha256 hashes populated in //rust:known_shas.bzl; 669 3. The sha256 argument to the function 670 671 Args: 672 ctx (repository_ctx): A repository_ctx (no attrs required). 673 tool_name (str): The name of the given tool per the archive naming. 674 target_triple (struct): The rust-style target triple of the tool. 675 version (str): The version of the tool among "nightly", "beta', or an exact version. 676 iso_date (str): The date of the tool (ignored if the version is a specific version). 677 sha256 (str): The expected hash of hash of the Rust tool. 678 679 Returns: 680 str: The sha256 of the tool archive, or an empty string if the hash could not be found. 681 """ 682 tool_suburl = produce_tool_suburl(tool_name, target_triple, version, iso_date) 683 archive_path = tool_suburl + _get_tool_extension(getattr(ctx.attr, "urls", None)) 684 return getattr(ctx.attr, "sha256s", dict()).get(archive_path) or FILE_KEY_TO_SHA.get(archive_path) or sha256 685 686def load_arbitrary_tool(ctx, tool_name, tool_subdirectories, version, iso_date, target_triple, sha256 = ""): 687 """Loads a Rust tool, downloads, and extracts into the common workspace. 688 689 This function sources the tool from the Rust-lang static file server. The index is available at: 690 - https://static.rust-lang.org/dist/channel-rust-stable.toml 691 - https://static.rust-lang.org/dist/channel-rust-beta.toml 692 - https://static.rust-lang.org/dist/channel-rust-nightly.toml 693 694 Args: 695 ctx (repository_ctx): A repository_ctx (no attrs required). 696 tool_name (str): The name of the given tool per the archive naming. 697 tool_subdirectories (str): The subdirectories of the tool files (at a level below the root directory of 698 the archive). The root directory of the archive is expected to match 699 $TOOL_NAME-$VERSION-$TARGET_TRIPLE. 700 Example: 701 tool_name 702 | version 703 | | target_triple 704 v v v 705 rust-1.39.0-x86_64-unknown-linux-gnu/clippy-preview 706 .../rustc 707 .../etc 708 tool_subdirectories = ["clippy-preview", "rustc"] 709 version (str): The version of the tool among "nightly", "beta', or an exact version. 710 iso_date (str): The date of the tool (ignored if the version is a specific version). 711 target_triple (struct): The rust-style target triple of the tool. 712 sha256 (str, optional): The expected hash of hash of the Rust tool. Defaults to "". 713 """ 714 check_version_valid(version, iso_date, param_prefix = tool_name + "_") 715 716 # View the indices mentioned in the docstring to find the tool_suburl for a given 717 # tool. 718 tool_suburl = produce_tool_suburl(tool_name, target_triple, version, iso_date) 719 urls = [] 720 721 for url in getattr(ctx.attr, "urls", DEFAULT_STATIC_RUST_URL_TEMPLATES): 722 new_url = url.format(tool_suburl) 723 if new_url not in urls: 724 urls.append(new_url) 725 726 tool_path = produce_tool_path(tool_name, version, target_triple) 727 728 sha256 = lookup_tool_sha256(ctx, tool_name, target_triple, version, iso_date, sha256) 729 730 for subdirectory in tool_subdirectories: 731 # As long as the sha256 value is consistent accross calls here the 732 # cost of downloading an artifact is negated as by Bazel's caching. 733 result = ctx.download_and_extract( 734 urls, 735 sha256 = sha256, 736 auth = _make_auth_dict(ctx, urls), 737 stripPrefix = "{}/{}".format(tool_path, subdirectory), 738 ) 739 740 # In the event no sha256 was provided, set it to the value of the first 741 # downloaded item so subsequent downloads use a cached artifact. 742 if not sha256: 743 sha256 = result.sha256 744 745def _make_auth_dict(ctx, urls): 746 auth = getattr(ctx.attr, "auth", {}) 747 if not auth: 748 return {} 749 ret = {} 750 for url in urls: 751 ret[url] = auth 752 return ret 753 754def _get_tool_extension(urls = None): 755 if urls == None: 756 urls = DEFAULT_STATIC_RUST_URL_TEMPLATES 757 if urls[0][-7:] == ".tar.gz": 758 return ".tar.gz" 759 elif urls[0][-7:] == ".tar.xz": 760 return ".tar.xz" 761 else: 762 return "" 763 764def select_rust_version(versions): 765 """Select the highest priorty version for a list of Rust versions 766 767 Priority order: `stable > nightly > beta` 768 769 Note that duplicate channels are unexpected in `versions`. 770 771 Args: 772 versions (list): A list of Rust versions. E.g. [`1.66.0`, `nightly/2022-12-15`] 773 774 Returns: 775 str: The highest ranking value from `versions` 776 """ 777 if not versions: 778 fail("No versions were provided") 779 780 current = versions[0] 781 782 for ver in versions: 783 if ver.startswith("beta"): 784 if current[0].isdigit() or current.startswith("nightly"): 785 continue 786 if current.startswith("beta") and ver > current: 787 current = ver 788 continue 789 790 current = ver 791 elif ver.startswith("nightly"): 792 if current[0].isdigit(): 793 continue 794 if current.startswith("nightly") and ver > current: 795 current = ver 796 continue 797 798 current = ver 799 800 else: 801 current = ver 802 803 return current 804 805_build_file_for_toolchain_hub_template = """ 806toolchain( 807 name = "{name}", 808 exec_compatible_with = {exec_constraint_sets_serialized}, 809 target_compatible_with = {target_constraint_sets_serialized}, 810 toolchain = "{toolchain}", 811 toolchain_type = "{toolchain_type}", 812 visibility = ["//visibility:public"], 813) 814""" 815 816def BUILD_for_toolchain_hub( 817 toolchain_names, 818 toolchain_labels, 819 toolchain_types, 820 target_compatible_with, 821 exec_compatible_with): 822 return "\n".join([_build_file_for_toolchain_hub_template.format( 823 name = toolchain_name, 824 exec_constraint_sets_serialized = json.encode(exec_compatible_with[toolchain_name]), 825 target_constraint_sets_serialized = json.encode(target_compatible_with[toolchain_name]), 826 toolchain = toolchain_labels[toolchain_name], 827 toolchain_type = toolchain_types[toolchain_name], 828 ) for toolchain_name in toolchain_names]) 829 830def _toolchain_repository_hub_impl(repository_ctx): 831 repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format( 832 repository_ctx.name, 833 )) 834 835 repository_ctx.file("BUILD.bazel", BUILD_for_toolchain_hub( 836 toolchain_names = repository_ctx.attr.toolchain_names, 837 toolchain_labels = repository_ctx.attr.toolchain_labels, 838 toolchain_types = repository_ctx.attr.toolchain_types, 839 target_compatible_with = repository_ctx.attr.target_compatible_with, 840 exec_compatible_with = repository_ctx.attr.exec_compatible_with, 841 )) 842 843toolchain_repository_hub = repository_rule( 844 doc = ( 845 "Generates a toolchain-bearing repository that declares a set of other toolchains from other " + 846 "repositories. This exists to allow registering a set of toolchains in one go with the `:all` target." 847 ), 848 attrs = { 849 "exec_compatible_with": attr.string_list_dict( 850 doc = "A list of constraints for the execution platform for this toolchain, keyed by toolchain name.", 851 mandatory = True, 852 ), 853 "target_compatible_with": attr.string_list_dict( 854 doc = "A list of constraints for the target platform for this toolchain, keyed by toolchain name.", 855 mandatory = True, 856 ), 857 "toolchain_labels": attr.string_dict( 858 doc = "The name of the toolchain implementation target, keyed by toolchain name.", 859 mandatory = True, 860 ), 861 "toolchain_names": attr.string_list(mandatory = True), 862 "toolchain_types": attr.string_dict( 863 doc = "The toolchain type of the toolchain to declare, keyed by toolchain name.", 864 mandatory = True, 865 ), 866 }, 867 implementation = _toolchain_repository_hub_impl, 868) 869