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