1"Module extensions for using rules_rust with bzlmod" 2 3load("@bazel_features//:features.bzl", "bazel_features") 4load("//rust:defs.bzl", "rust_common") 5load("//rust:repositories.bzl", "rust_register_toolchains", "rust_toolchain_tools_repository") 6load("//rust/platform:triple.bzl", "get_host_triple") 7load( 8 "//rust/private:repository_utils.bzl", 9 "DEFAULT_EXTRA_TARGET_TRIPLES", 10 "DEFAULT_NIGHTLY_VERSION", 11 "DEFAULT_STATIC_RUST_URL_TEMPLATES", 12) 13 14def _find_modules(module_ctx): 15 root = None 16 our_module = None 17 for mod in module_ctx.modules: 18 if mod.is_root: 19 root = mod 20 if mod.name == "rules_rust": 21 our_module = mod 22 if root == None: 23 root = our_module 24 if our_module == None: 25 fail("Unable to find rules_rust module") 26 27 return root, our_module 28 29def _rust_impl(module_ctx): 30 # Toolchain configuration is only allowed in the root module, or in 31 # rules_rust. 32 # See https://github.com/bazelbuild/bazel/discussions/22024 for discussion. 33 root, rules_rust = _find_modules(module_ctx) 34 35 toolchains = root.tags.toolchain or rules_rust.tags.toolchain 36 37 for toolchain in toolchains: 38 rust_register_toolchains( 39 dev_components = toolchain.dev_components, 40 edition = toolchain.edition, 41 allocator_library = toolchain.allocator_library, 42 rustfmt_version = toolchain.rustfmt_version, 43 rust_analyzer_version = toolchain.rust_analyzer_version, 44 sha256s = toolchain.sha256s, 45 extra_target_triples = toolchain.extra_target_triples, 46 urls = toolchain.urls, 47 versions = toolchain.versions, 48 register_toolchains = False, 49 ) 50 51_COMMON_TAG_KWARGS = dict( 52 allocator_library = attr.string( 53 doc = "Target that provides allocator functions when rust_library targets are embedded in a cc_binary.", 54 default = "@rules_rust//ffi/cc/allocator_library", 55 ), 56 dev_components = attr.bool( 57 doc = "Whether to download the rustc-dev components (defaults to False). Requires version to be \"nightly\".", 58 default = False, 59 ), 60 edition = attr.string( 61 doc = ( 62 "The rust edition to be used by default (2015, 2018, or 2021). " + 63 "If absent, every rule is required to specify its `edition` attribute." 64 ), 65 ), 66 rustfmt_version = attr.string( 67 doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.", 68 default = DEFAULT_NIGHTLY_VERSION, 69 ), 70 sha256s = attr.string_dict( 71 doc = "A dict associating tool subdirectories to sha256 hashes. See [rust_repositories](#rust_repositories) for more details.", 72 ), 73 urls = attr.string_list( 74 doc = "A list of mirror urls containing the tools from the Rust-lang static file server. These must contain the '{}' used to substitute the tool being fetched (using .format).", 75 default = DEFAULT_STATIC_RUST_URL_TEMPLATES, 76 ), 77) 78 79_RUST_TOOLCHAIN_TAG = tag_class( 80 attrs = dict( 81 extra_target_triples = attr.string_list( 82 default = DEFAULT_EXTRA_TARGET_TRIPLES, 83 ), 84 rust_analyzer_version = attr.string( 85 doc = "The version of Rustc to pair with rust-analyzer.", 86 ), 87 versions = attr.string_list( 88 doc = ( 89 "A list of toolchain versions to download. This paramter only accepts one versions " + 90 "per channel. E.g. `[\"1.65.0\", \"nightly/2022-11-02\", \"beta/2020-12-30\"]`." 91 ), 92 default = [], 93 ), 94 **_COMMON_TAG_KWARGS 95 ), 96) 97 98_RUST_HOST_TOOLS_TAG = tag_class( 99 attrs = dict( 100 version = attr.string( 101 default = rust_common.default_version, 102 doc = "The version of Rust to use for tools executed on the Bazel host.", 103 ), 104 **_COMMON_TAG_KWARGS 105 ), 106) 107 108rust = module_extension( 109 implementation = _rust_impl, 110 tag_classes = { 111 "toolchain": _RUST_TOOLCHAIN_TAG, 112 }, 113) 114 115# This is a separate module extension so that only the host tools are 116# marked as reproducible and os and arch dependent 117def _rust_host_tools_impl(module_ctx): 118 root, _ = _find_modules(module_ctx) 119 120 if len(root.tags.host_tools) == 1: 121 attrs = root.tags.host_tools[0] 122 123 iso_date = None 124 version = attrs.version 125 126 # Any version containing a slash is expected to be a nightly/beta release with iso date. E.g. `nightly/2024-03-21` 127 if "/" in version: 128 version, _, iso_date = version.partition("/") 129 130 host_tools = { 131 "allocator_library": attrs.allocator_library, 132 "dev_components": attrs.dev_components, 133 "edition": attrs.edition, 134 "iso_date": iso_date, 135 "rustfmt_version": attrs.rustfmt_version, 136 "sha256s": attrs.sha256s, 137 "urls": attrs.urls, 138 "version": version, 139 } 140 elif not root.tags.host_tools: 141 host_tools = { 142 "version": rust_common.default_version, 143 } 144 else: 145 fail("Multiple host_tools were defined in your root MODULE.bazel") 146 147 host_triple = get_host_triple(module_ctx) 148 rust_toolchain_tools_repository( 149 name = "rust_host_tools", 150 exec_triple = host_triple.str, 151 target_triple = host_triple.str, 152 **host_tools 153 ) 154 155 metadata_kwargs = {} 156 if bazel_features.external_deps.extension_metadata_has_reproducible: 157 metadata_kwargs["reproducible"] = True 158 return module_ctx.extension_metadata(**metadata_kwargs) 159 160_conditional_rust_host_tools_args = { 161 "arch_dependent": True, 162 "os_dependent": True, 163} if bazel_features.external_deps.module_extension_has_os_arch_dependent else {} 164 165rust_host_tools = module_extension( 166 implementation = _rust_host_tools_impl, 167 tag_classes = { 168 "host_tools": _RUST_HOST_TOOLS_TAG, 169 }, 170 **_conditional_rust_host_tools_args 171) 172