xref: /aosp_15_r20/external/bazelbuild-rules_rust/rust/extensions.bzl (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
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