xref: /aosp_15_r20/external/bazelbuild-rules_rust/rust/repositories.bzl (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1"""Repository rules for defining Rust dependencies and toolchains"""
2
3load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
4load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
5load("//rust/platform:triple.bzl", "get_host_triple", "triple")
6load("//rust/platform:triple_mappings.bzl", "triple_to_constraint_set")
7load("//rust/private:common.bzl", "DEFAULT_NIGHTLY_ISO_DATE", "rust_common")
8load(
9    "//rust/private:repository_utils.bzl",
10    "BUILD_for_rust_analyzer_proc_macro_srv",
11    "BUILD_for_rust_analyzer_toolchain",
12    "BUILD_for_rust_toolchain",
13    "BUILD_for_rustfmt_toolchain",
14    "BUILD_for_toolchain",
15    "DEFAULT_EXTRA_TARGET_TRIPLES",
16    "DEFAULT_NIGHTLY_VERSION",
17    "DEFAULT_STATIC_RUST_URL_TEMPLATES",
18    "TINYJSON_KWARGS",
19    "check_version_valid",
20    "includes_rust_analyzer_proc_macro_srv",
21    "load_cargo",
22    "load_clippy",
23    "load_llvm_tools",
24    "load_rust_compiler",
25    "load_rust_src",
26    "load_rust_stdlib",
27    "load_rustc_dev_nightly",
28    "load_rustfmt",
29    "select_rust_version",
30    "toolchain_repository_hub",
31    _load_arbitrary_tool = "load_arbitrary_tool",
32)
33
34# Re-export `load_arbitrary_tool` as it's historically been used in external repositories.
35load_arbitrary_tool = _load_arbitrary_tool
36
37# Note: Code in `.github/workflows/crate_universe.yaml` looks for this line, if you remove it or change its format, you will also need to update that code.
38DEFAULT_TOOLCHAIN_TRIPLES = {
39    "aarch64-apple-darwin": "rust_darwin_aarch64",
40    "aarch64-pc-windows-msvc": "rust_windows_aarch64",
41    "aarch64-unknown-linux-gnu": "rust_linux_aarch64",
42    "x86_64-apple-darwin": "rust_darwin_x86_64",
43    "x86_64-pc-windows-msvc": "rust_windows_x86_64",
44    "x86_64-unknown-freebsd": "rust_freebsd_x86_64",
45    "x86_64-unknown-linux-gnu": "rust_linux_x86_64",
46}
47
48def rules_rust_dependencies():
49    """Dependencies used in the implementation of `rules_rust`."""
50
51    maybe(
52        http_archive,
53        name = "platforms",
54        urls = [
55            "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
56            "https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
57        ],
58        sha256 = "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74",
59    )
60    maybe(
61        http_archive,
62        name = "rules_cc",
63        urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz"],
64        sha256 = "2037875b9a4456dce4a79d112a8ae885bbc4aad968e6587dca6e64f3a0900cdf",
65        strip_prefix = "rules_cc-0.0.9",
66    )
67    maybe(
68        http_archive,
69        name = "rules_license",
70        urls = [
71            "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.8/rules_license-0.0.8.tar.gz",
72            "https://github.com/bazelbuild/rules_license/releases/download/0.0.8/rules_license-0.0.8.tar.gz",
73        ],
74        sha256 = "241b06f3097fd186ff468832150d6cc142247dc42a32aaefb56d0099895fd229",
75    )
76
77    maybe(
78        http_archive,
79        name = "bazel_skylib",
80        sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94",
81        urls = [
82            "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
83            "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
84        ],
85    )
86
87    # Make the iOS simulator constraint available, which is referenced in abi_to_constraints()
88    # rules_rust does not require this dependency; it is just imported as a convenience for users.
89    maybe(
90        http_archive,
91        name = "build_bazel_apple_support",
92        sha256 = "1c4031e72b456a048d8177f59a5581808c07585fa9e255c6f5fefb8752af7e40",
93        url = "https://github.com/bazelbuild/apple_support/releases/download/1.13.0/apple_support.1.13.0.tar.gz",
94    )
95
96    # process_wrapper needs a low-dependency way to process json.
97    maybe(
98        http_archive,
99        **TINYJSON_KWARGS
100    )
101
102_RUST_TOOLCHAIN_VERSIONS = [
103    rust_common.default_version,
104    DEFAULT_NIGHTLY_VERSION,
105]
106
107# buildifier: disable=unnamed-macro
108def rust_register_toolchains(
109        dev_components = False,
110        edition = None,
111        allocator_library = None,
112        global_allocator_library = None,
113        iso_date = None,
114        register_toolchains = True,
115        rustfmt_version = None,
116        rust_analyzer_version = None,
117        sha256s = None,
118        extra_target_triples = DEFAULT_EXTRA_TARGET_TRIPLES,
119        extra_rustc_flags = None,
120        extra_exec_rustc_flags = None,
121        urls = DEFAULT_STATIC_RUST_URL_TEMPLATES,
122        version = None,
123        versions = []):
124    """Emits a default set of toolchains for Linux, MacOS, and Freebsd
125
126    Skip this macro and call the `rust_repository_set` macros directly if you need a compiler for \
127    other hosts or for additional target triples.
128
129    The `sha256s` attribute represents a dict associating tool subdirectories to sha256 hashes. As an example:
130    ```python
131    {
132        "rust-1.46.0-x86_64-unknown-linux-gnu": "e3b98bc3440fe92817881933f9564389eccb396f5f431f33d48b979fa2fbdcf5",
133        "rustfmt-1.4.12-x86_64-unknown-linux-gnu": "1894e76913303d66bf40885a601462844eec15fca9e76a6d13c390d7000d64b0",
134        "rust-std-1.46.0-x86_64-unknown-linux-gnu": "ac04aef80423f612c0079829b504902de27a6997214eb58ab0765d02f7ec1dbc",
135    }
136    ```
137    This would match for `exec_triple = "x86_64-unknown-linux-gnu"`.  If not specified, rules_rust pulls from a non-exhaustive \
138    list of known checksums..
139
140    See `load_arbitrary_tool` in `@rules_rust//rust:repositories.bzl` for more details.
141
142    Args:
143        dev_components (bool, optional): Whether to download the rustc-dev components (defaults to False). Requires version to be "nightly".
144        edition (str, optional): The rust edition to be used by default (2015, 2018, or 2021). If absent, every target is required to specify its `edition` attribute.
145        allocator_library (str, optional): Target that provides allocator functions when rust_library targets are embedded in a cc_binary.
146        global_allocator_library (str, optional): Target that provides allocator functions when global allocator is used with cc_common.link.
147        iso_date (str, optional):  **Deprecated**: Use `versions` instead.
148        register_toolchains (bool): If true, repositories will be generated to produce and register `rust_toolchain` targets.
149        rustfmt_version (str, optional): The version of rustfmt. If none is supplied and only a single version in `versions` is given, then this defaults to that version, otherwise will default to the default nightly version.
150        rust_analyzer_version (str, optional): The version of Rustc to pair with rust-analyzer.
151        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes.
152        extra_target_triples (list, optional): Additional rust-style targets that rust toolchains should support.
153        extra_rustc_flags (dict, list, optional): Dictionary of target triples to list of extra flags to pass to rustc in non-exec configuration.
154        extra_exec_rustc_flags (list, optional): Extra flags to pass to rustc in exec configuration.
155        urls (list, optional): 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).
156        version (str, optional): **Deprecated**: Use `versions` instead.
157        versions (list, optional): A list of toolchain versions to download. This paramter only accepts one versions
158            per channel. E.g. `["1.65.0", "nightly/2022-11-02", "beta/2020-12-30"]`.
159    """
160    if version:
161        # buildifier: disable=print
162        print("`rust_register.toolchains.version` is deprecated. Please use `versions` instead: https://bazelbuild.github.io/rules_rust/flatten.html#rust_register_toolchains-versions")
163
164    if iso_date:
165        # buildifier: disable=print
166        print("`rust_register.toolchains.iso_date` is deprecated. Please use `versions` instead: https://bazelbuild.github.io/rules_rust/flatten.html#rust_register_toolchains-versions")
167
168    if rustfmt_version in ("nightly", "beta"):
169        # buildifier: disable=print
170        print("`rust_register.toolchains.rustfmt_version` now requires iso date to be included in the string. E.g. `nightly/2022-12-15`. This version will be assumed until this value is updated")
171        rustfmt_version = "{}/{}".format(rustfmt_version, DEFAULT_NIGHTLY_ISO_DATE)
172
173    if not versions:
174        if version:
175            versions = [version]
176        else:
177            versions = _RUST_TOOLCHAIN_VERSIONS
178
179    if not rustfmt_version:
180        if len(versions) == 1:
181            rustfmt_version = versions[0]
182        else:
183            rustfmt_version = DEFAULT_NIGHTLY_VERSION
184
185    if dev_components:
186        has_nightly = False
187        for ver in versions:
188            if ver.startswith("nightly"):
189                has_nightly = True
190                break
191        if not has_nightly:
192            fail("rustc-dev components were requested but no \"nightly\" is being registered. Please update `versions` to include a nightly version.")
193
194    if not rust_analyzer_version:
195        rust_analyzer_version = select_rust_version(versions)
196
197    rust_analyzer_repo_name = "rust_analyzer_{}".format(rust_analyzer_version.replace("/", "-"))
198    rust_analyzer_iso_date = None
199    if rust_analyzer_version.startswith(("beta", "nightly")):
200        rust_analyzer_version, _, rust_analyzer_iso_date = rust_analyzer_version.partition("/")
201
202    toolchain_names = []
203    toolchain_labels = {}
204    toolchain_types = {}
205    exec_compatible_with_by_toolchain = {}
206    target_compatible_with_by_toolchain = {}
207
208    maybe(
209        rust_analyzer_toolchain_repository,
210        name = rust_analyzer_repo_name,
211        version = rust_analyzer_version,
212        urls = urls,
213        sha256s = sha256s,
214        iso_date = rust_analyzer_iso_date,
215    )
216
217    toolchain_names.append(rust_analyzer_repo_name)
218    toolchain_labels[rust_analyzer_repo_name] = "@{}_tools//:rust_analyzer_toolchain".format(
219        rust_analyzer_repo_name,
220    )
221    exec_compatible_with_by_toolchain[rust_analyzer_repo_name] = []
222    target_compatible_with_by_toolchain[rust_analyzer_repo_name] = []
223    toolchain_types[rust_analyzer_repo_name] = "@rules_rust//rust/rust_analyzer:toolchain_type"
224
225    if register_toolchains:
226        native.register_toolchains("@{}//:toolchain".format(
227            rust_analyzer_repo_name,
228        ))
229
230    rustfmt_iso_date = None
231    rustfmt_version_or_channel = rustfmt_version
232    if rustfmt_version.startswith(("beta", "nightly")):
233        rustfmt_version_or_channel, _, rustfmt_iso_date = rustfmt_version.partition("/")
234
235    for exec_triple, name in DEFAULT_TOOLCHAIN_TRIPLES.items():
236        maybe(
237            rust_repository_set,
238            name = name,
239            dev_components = dev_components,
240            edition = edition,
241            exec_triple = exec_triple,
242            extra_target_triples = extra_target_triples,
243            allocator_library = allocator_library,
244            global_allocator_library = global_allocator_library,
245            iso_date = iso_date,
246            register_toolchain = register_toolchains,
247            rustfmt_version = rustfmt_version,
248            extra_rustc_flags = extra_rustc_flags,
249            extra_exec_rustc_flags = extra_exec_rustc_flags,
250            sha256s = sha256s,
251            urls = urls,
252            version = version,
253            versions = versions,
254        )
255
256        rustfmt_repo_name = "rustfmt_{}__{}".format(rustfmt_version.replace("/", "-"), exec_triple)
257
258        maybe(
259            rustfmt_toolchain_repository,
260            name = rustfmt_repo_name,
261            version = rustfmt_version_or_channel,
262            urls = urls,
263            sha256s = sha256s,
264            iso_date = rustfmt_iso_date,
265            exec_triple = exec_triple,
266        )
267
268        if register_toolchains:
269            native.register_toolchains("@{}//:toolchain".format(
270                rustfmt_repo_name,
271            ))
272
273        for toolchain in _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions, iso_date):
274            toolchain_names.append(toolchain.name)
275            toolchain_labels[toolchain.name] = "@{}//:{}".format(toolchain.name + "_tools", "rust_toolchain")
276            exec_compatible_with_by_toolchain[toolchain.name] = triple_to_constraint_set(exec_triple)
277            target_compatible_with_by_toolchain[toolchain.name] = triple_to_constraint_set(toolchain.target_triple)
278            toolchain_types[toolchain.name] = "@rules_rust//rust:toolchain"
279
280        toolchain_names.append(rustfmt_repo_name)
281        toolchain_labels[rustfmt_repo_name] = "@{}_tools//:rustfmt_toolchain".format(rustfmt_repo_name)
282        exec_compatible_with_by_toolchain[rustfmt_repo_name] = triple_to_constraint_set(exec_triple)
283        target_compatible_with_by_toolchain[rustfmt_repo_name] = []
284        toolchain_types[rustfmt_repo_name] = "@rules_rust//rust/rustfmt:toolchain_type"
285
286    toolchain_repository_hub(
287        name = "rust_toolchains",
288        toolchain_names = toolchain_names,
289        toolchain_labels = toolchain_labels,
290        toolchain_types = toolchain_types,
291        exec_compatible_with = exec_compatible_with_by_toolchain,
292        target_compatible_with = target_compatible_with_by_toolchain,
293    )
294
295# buildifier: disable=unnamed-macro
296def rust_repositories(**kwargs):
297    """**Deprecated**: Use [rules_rust_dependencies](#rules_rust_dependencies) \
298    and [rust_register_toolchains](#rust_register_toolchains) directly.
299
300    Args:
301        **kwargs (dict): Keyword arguments for the `rust_register_toolchains` macro.
302    """
303    rules_rust_dependencies()
304
305    rust_register_toolchains(**kwargs)
306
307_RUST_TOOLCHAIN_REPOSITORY_ATTRS = {
308    "allocator_library": attr.string(
309        doc = "Target that provides allocator functions when rust_library targets are embedded in a cc_binary.",
310        default = "@rules_rust//ffi/cc/allocator_library",
311    ),
312    "auth": attr.string_dict(
313        doc = (
314            "Auth object compatible with repository_ctx.download to use when downloading files. " +
315            "See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details."
316        ),
317    ),
318    "auth_patterns": attr.string_list(
319        doc = "A list of patterns to match against urls for which the auth object should be used.",
320    ),
321    "dev_components": attr.bool(
322        doc = "Whether to download the rustc-dev components (defaults to False). Requires version to be \"nightly\".",
323        default = False,
324    ),
325    "edition": attr.string(
326        doc = (
327            "The rust edition to be used by default (2015, 2018, or 2021). " +
328            "If absent, every rule is required to specify its `edition` attribute."
329        ),
330    ),
331    "exec_triple": attr.string(
332        doc = "The Rust-style target that this compiler runs on",
333        mandatory = True,
334    ),
335    "extra_exec_rustc_flags": attr.string_list(
336        doc = "Extra flags to pass to rustc in exec configuration",
337    ),
338    "extra_rustc_flags": attr.string_list(
339        doc = "Extra flags to pass to rustc in non-exec configuration",
340    ),
341    "global_allocator_library": attr.string(
342        doc = "Target that provides allocator functions when a global allocator is used with cc_common.link.",
343        default = "@rules_rust//ffi/cc/global_allocator_library",
344    ),
345    "iso_date": attr.string(
346        doc = "The date of the tool (or None, if the version is a specific version).",
347    ),
348    "netrc": attr.string(
349        doc = ".netrc file to use for authentication; mirrors the eponymous attribute from http_archive",
350    ),
351    "opt_level": attr.string_dict(
352        doc = "Rustc optimization levels. For more details see the documentation for `rust_toolchain.opt_level`.",
353    ),
354    "rustfmt_version": attr.string(
355        doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
356    ),
357    "sha256s": attr.string_dict(
358        doc = "A dict associating tool subdirectories to sha256 hashes. See [rust_register_toolchains](#rust_register_toolchains) for more details.",
359    ),
360    "target_triple": attr.string(
361        doc = "The Rust-style target that this compiler builds for.",
362        mandatory = True,
363    ),
364    "urls": attr.string_list(
365        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).",
366        default = DEFAULT_STATIC_RUST_URL_TEMPLATES,
367    ),
368    "version": attr.string(
369        doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
370        mandatory = True,
371    ),
372}
373
374def _rust_toolchain_tools_repository_impl(ctx):
375    """The implementation of the rust toolchain tools repository rule."""
376    sha256s = dict(ctx.attr.sha256s)
377    iso_date = ctx.attr.iso_date
378    version = ctx.attr.version
379    version_array = version.split("/")
380    if len(version_array) > 1:
381        version = version_array[0]
382        iso_date = version_array[1]
383
384    check_version_valid(ctx.attr.version, iso_date)
385
386    exec_triple = triple(ctx.attr.exec_triple)
387
388    rustc_content, rustc_sha256 = load_rust_compiler(
389        ctx = ctx,
390        iso_date = iso_date,
391        target_triple = exec_triple,
392        version = version,
393    )
394    clippy_content, clippy_sha256 = load_clippy(
395        ctx = ctx,
396        iso_date = iso_date,
397        target_triple = exec_triple,
398        version = version,
399    )
400    cargo_content, cargo_sha256 = load_cargo(
401        ctx = ctx,
402        iso_date = iso_date,
403        target_triple = exec_triple,
404        version = version,
405    )
406
407    build_components = [
408        rustc_content,
409        clippy_content,
410        cargo_content,
411    ]
412    sha256s.update(rustc_sha256 | clippy_sha256 | cargo_sha256)
413
414    if ctx.attr.rustfmt_version:
415        rustfmt_version = ctx.attr.rustfmt_version
416        rustfmt_iso_date = None
417        if rustfmt_version in ("nightly", "beta"):
418            if iso_date:
419                rustfmt_iso_date = iso_date
420            else:
421                fail("`rustfmt_version` does not include an iso_date. The following reposiotry should either set `iso_date` or update `rustfmt_version` to include an iso_date suffix: {}".format(
422                    ctx.name,
423                ))
424        elif rustfmt_version.startswith(("nightly", "beta")):
425            rustfmt_version, _, rustfmt_iso_date = rustfmt_version.partition("/")
426        rustfmt_content, rustfmt_sha256 = load_rustfmt(
427            ctx = ctx,
428            target_triple = triple(ctx.attr.exec_triple),
429            version = rustfmt_version,
430            iso_date = rustfmt_iso_date,
431        )
432        build_components.append(rustfmt_content)
433        sha256s.update(rustfmt_sha256)
434
435    # Rust 1.45.0 and nightly builds after 2020-05-22 need the llvm-tools gzip to get the libLLVM dylib
436    include_llvm_tools = version >= "1.45.0" or (version == "nightly" and iso_date > "2020-05-22")
437    if include_llvm_tools:
438        llvm_tools_content, llvm_tools_sha256 = load_llvm_tools(
439            ctx = ctx,
440            target_triple = exec_triple,
441        )
442        build_components.append(llvm_tools_content)
443        sha256s.update(llvm_tools_sha256)
444
445    target_triple = triple(ctx.attr.target_triple)
446    rust_stdlib_content, rust_stdlib_sha256 = load_rust_stdlib(
447        ctx = ctx,
448        target_triple = target_triple,
449    )
450    build_components.append(rust_stdlib_content)
451    sha256s.update(rust_stdlib_sha256)
452
453    stdlib_linkflags = None
454    if "BAZEL_RUST_STDLIB_LINKFLAGS" in ctx.os.environ:
455        stdlib_linkflags = ctx.os.environ["BAZEL_RUST_STDLIB_LINKFLAGS"].split(":")
456
457    build_components.append(BUILD_for_rust_toolchain(
458        name = "rust_toolchain",
459        exec_triple = exec_triple,
460        allocator_library = ctx.attr.allocator_library,
461        global_allocator_library = ctx.attr.global_allocator_library,
462        target_triple = target_triple,
463        stdlib_linkflags = stdlib_linkflags,
464        default_edition = ctx.attr.edition,
465        include_rustfmt = not (not ctx.attr.rustfmt_version),
466        include_llvm_tools = include_llvm_tools,
467        extra_rustc_flags = ctx.attr.extra_rustc_flags,
468        extra_exec_rustc_flags = ctx.attr.extra_exec_rustc_flags,
469        opt_level = ctx.attr.opt_level if ctx.attr.opt_level else None,
470    ))
471
472    # Not all target triples are expected to have dev components
473    if ctx.attr.dev_components:
474        rustc_dev_sha256 = load_rustc_dev_nightly(ctx, target_triple)
475        sha256s.update(rustc_dev_sha256)
476
477    ctx.file("WORKSPACE.bazel", "")
478    ctx.file("BUILD.bazel", "\n".join(build_components))
479
480    repro = {"name": ctx.name}
481    for key in _RUST_TOOLCHAIN_REPOSITORY_ATTRS:
482        repro[key] = getattr(ctx.attr, key)
483    repro["sha256s"] = sha256s
484
485    return repro
486
487rust_toolchain_tools_repository = repository_rule(
488    doc = (
489        "Composes a single workspace containing the toolchain components for compiling on a given " +
490        "platform to a series of target platforms.\n" +
491        "\n" +
492        "A given instance of this rule should be accompanied by a toolchain_repository_proxy " +
493        "invocation to declare its toolchains to Bazel; the indirection allows separating toolchain " +
494        "selection from toolchain fetching."
495    ),
496    attrs = _RUST_TOOLCHAIN_REPOSITORY_ATTRS,
497    implementation = _rust_toolchain_tools_repository_impl,
498)
499
500def _toolchain_repository_proxy_impl(repository_ctx):
501    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
502        repository_ctx.name,
503    ))
504
505    repository_ctx.file("BUILD.bazel", BUILD_for_toolchain(
506        name = "toolchain",
507        toolchain = repository_ctx.attr.toolchain,
508        target_settings = repository_ctx.attr.target_settings,
509        toolchain_type = repository_ctx.attr.toolchain_type,
510        target_compatible_with = repository_ctx.attr.target_compatible_with,
511        exec_compatible_with = repository_ctx.attr.exec_compatible_with,
512    ))
513
514toolchain_repository_proxy = repository_rule(
515    doc = (
516        "Generates a toolchain-bearing repository that declares the toolchains from some other " +
517        "rust_toolchain_repository."
518    ),
519    attrs = {
520        "exec_compatible_with": attr.string_list(
521            doc = "A list of constraints for the execution platform for this toolchain.",
522        ),
523        "target_compatible_with": attr.string_list(
524            doc = "A list of constraints for the target platform for this toolchain.",
525        ),
526        "target_settings": attr.string_list(
527            doc = "A list of config_settings that must be satisfied by the target configuration in order for this toolchain to be selected during toolchain resolution.",
528        ),
529        "toolchain": attr.string(
530            doc = "The name of the toolchain implementation target.",
531            mandatory = True,
532        ),
533        "toolchain_type": attr.string(
534            doc = "The toolchain type of the toolchain to declare",
535            mandatory = True,
536        ),
537    },
538    implementation = _toolchain_repository_proxy_impl,
539)
540
541# For legacy support
542rust_toolchain_repository_proxy = toolchain_repository_proxy
543
544# N.B. A "proxy repository" is needed to allow for registering the toolchain (with constraints)
545# without actually downloading the toolchain.
546def rust_toolchain_repository(
547        name,
548        version,
549        exec_triple,
550        target_triple,
551        exec_compatible_with = None,
552        target_compatible_with = None,
553        target_settings = [],
554        channel = None,
555        allocator_library = None,
556        global_allocator_library = None,
557        iso_date = None,
558        rustfmt_version = None,
559        edition = None,
560        dev_components = False,
561        extra_rustc_flags = None,
562        extra_exec_rustc_flags = None,
563        opt_level = None,
564        sha256s = None,
565        urls = DEFAULT_STATIC_RUST_URL_TEMPLATES,
566        auth = None,
567        netrc = None,
568        auth_patterns = None):
569    """Assembles a remote repository for the given toolchain params, produces a proxy repository \
570    to contain the toolchain declaration, and registers the toolchains.
571
572    Args:
573        name (str): The name of the generated repository
574        version (str): The version of the tool among "nightly", "beta", or an exact version.
575        exec_triple (str): The Rust-style target that this compiler runs on.
576        target_triple (str): The Rust-style target to build for.
577        channel (str, optional): The channel of the Rust toolchain.
578        exec_compatible_with (list, optional): A list of constraints for the execution platform for this toolchain.
579        target_compatible_with (list, optional): A list of constraints for the target platform for this toolchain.
580        target_settings (list, optional): A list of config_settings that must be satisfied by the target configuration in order for this toolchain to be selected during toolchain resolution.
581        allocator_library (str, optional): Target that provides allocator functions when rust_library targets are embedded in a cc_binary.
582        global_allocator_library (str, optional): Target that provides allocator functions when a global allocator is used with cc_common.link.
583        iso_date (str, optional): The date of the tool.
584        rustfmt_version (str, optional):  The version of rustfmt to be associated with the
585            toolchain.
586        edition (str, optional): The rust edition to be used by default (2015, 2018, or 2021). If absent, every rule is required to specify its `edition` attribute.
587        dev_components (bool, optional): Whether to download the rustc-dev components.
588            Requires version to be "nightly". Defaults to False.
589        extra_rustc_flags (list, optional): Extra flags to pass to rustc in non-exec configuration.
590        extra_exec_rustc_flags (list, optional): Extra flags to pass to rustc in exec configuration.
591        opt_level (dict, optional): Optimization level config for this toolchain.
592        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes. See
593            [rust_register_toolchains](#rust_register_toolchains) for more details.
594        urls (list, optional): 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). Defaults to ['https://static.rust-lang.org/dist/{}.tar.xz']
595        auth (dict): Auth object compatible with repository_ctx.download to use when downloading files.
596            See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details.
597        netrc (str, optional): .netrc file to use for authentication; mirrors the eponymous attribute from http_archive
598        auth_patterns (list, optional): A list of patterns to match against urls for which the auth object should be used.
599
600    Returns:
601        str: The name of the registerable toolchain created by this rule.
602    """
603
604    if rustfmt_version in ("nightly", "beta"):
605        # buildifier: disable=print
606        print("`rust_toolchain_repository.rustfmt_version` now requires iso date to be included in the string. E.g. `nightly/2022-12-15`. This version will be assumed until this value is updated")
607        rustfmt_version = "{}/{}".format(rustfmt_version, DEFAULT_NIGHTLY_ISO_DATE)
608
609    if exec_compatible_with == None:
610        exec_compatible_with = triple_to_constraint_set(exec_triple)
611
612    if target_compatible_with == None:
613        target_compatible_with = triple_to_constraint_set(target_triple)
614
615    tools_repo_name = "{}_tools".format(name)
616
617    rust_toolchain_tools_repository(
618        name = tools_repo_name,
619        exec_triple = exec_triple,
620        allocator_library = allocator_library,
621        global_allocator_library = global_allocator_library,
622        target_triple = target_triple,
623        iso_date = iso_date,
624        version = version,
625        rustfmt_version = rustfmt_version,
626        edition = edition,
627        dev_components = dev_components,
628        extra_rustc_flags = extra_rustc_flags,
629        extra_exec_rustc_flags = extra_exec_rustc_flags,
630        opt_level = opt_level,
631        sha256s = sha256s,
632        urls = urls,
633        auth = auth,
634        netrc = netrc,
635        auth_patterns = auth_patterns,
636    )
637
638    channel_target_settings = ["@rules_rust//rust/toolchain/channel:{}".format(channel)] if channel else []
639
640    toolchain_repository_proxy(
641        name = name,
642        toolchain = "@{}//:rust_toolchain".format(tools_repo_name),
643        target_settings = channel_target_settings + target_settings,
644        toolchain_type = "@rules_rust//rust:toolchain",
645        exec_compatible_with = exec_compatible_with,
646        target_compatible_with = target_compatible_with,
647    )
648
649    return "@{name}//:toolchain".format(
650        name = name,
651    )
652
653_RUST_ANALYZER_TOOLCHAIN_TOOLS_REPOSITORY_ATTRS = {
654    "auth": attr.string_dict(
655        doc = (
656            "Auth object compatible with repository_ctx.download to use when downloading files. " +
657            "See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details."
658        ),
659    ),
660    "auth_patterns": attr.string_list(
661        doc = "A list of patterns to match against urls for which the auth object should be used.",
662    ),
663    "iso_date": attr.string(
664        doc = "The date of the tool (or None, if the version is a specific version).",
665    ),
666    "netrc": attr.string(
667        doc = ".netrc file to use for authentication; mirrors the eponymous attribute from http_archive",
668    ),
669    "sha256s": attr.string_dict(
670        doc = "A dict associating tool subdirectories to sha256 hashes. See [rust_register_toolchains](#rust_register_toolchains) for more details.",
671    ),
672    "urls": attr.string_list(
673        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).",
674        default = DEFAULT_STATIC_RUST_URL_TEMPLATES,
675    ),
676    "version": attr.string(
677        doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
678        mandatory = True,
679    ),
680}
681
682def _rust_analyzer_toolchain_tools_repository_impl(repository_ctx):
683    sha256s = dict(repository_ctx.attr.sha256s)
684
685    sha256s.update(load_rust_src(
686        ctx = repository_ctx,
687        iso_date = repository_ctx.attr.iso_date,
688        version = repository_ctx.attr.version,
689    ))
690
691    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
692        repository_ctx.name,
693    ))
694
695    host_triple = get_host_triple(repository_ctx)
696    rustc_content, rustc_sha256 = load_rust_compiler(
697        ctx = repository_ctx,
698        iso_date = repository_ctx.attr.iso_date,
699        target_triple = host_triple,
700        version = repository_ctx.attr.version,
701    )
702    build_contents = [rustc_content]
703    sha256s.update(rustc_sha256)
704    rustc = "//:rustc"
705
706    proc_macro_srv = None
707    if includes_rust_analyzer_proc_macro_srv(repository_ctx.attr.version, repository_ctx.attr.iso_date):
708        build_contents.append(BUILD_for_rust_analyzer_proc_macro_srv(host_triple))
709        proc_macro_srv = "//:rust_analyzer_proc_macro_srv"
710
711    build_contents.append(BUILD_for_rust_analyzer_toolchain(
712        name = "rust_analyzer_toolchain",
713        rustc = rustc,
714        proc_macro_srv = proc_macro_srv,
715    ))
716
717    repository_ctx.file("BUILD.bazel", "\n".join(build_contents))
718    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
719        repository_ctx.name,
720    ))
721
722    repro = {"name": repository_ctx.name}
723    for key in _RUST_ANALYZER_TOOLCHAIN_TOOLS_REPOSITORY_ATTRS:
724        repro[key] = getattr(repository_ctx.attr, key)
725    repro["sha256s"] = sha256s
726
727    return repro
728
729rust_analyzer_toolchain_tools_repository = repository_rule(
730    doc = "A repository rule for defining a rust_analyzer_toolchain with a `rust-src` artifact.",
731    implementation = _rust_analyzer_toolchain_tools_repository_impl,
732    attrs = _RUST_ANALYZER_TOOLCHAIN_TOOLS_REPOSITORY_ATTRS,
733)
734
735def rust_analyzer_toolchain_repository(
736        name,
737        version,
738        exec_compatible_with = [],
739        target_compatible_with = [],
740        iso_date = None,
741        sha256s = None,
742        urls = None,
743        auth = None,
744        netrc = None,
745        auth_patterns = None):
746    """Assemble a remote rust_analyzer_toolchain target based on the given params.
747
748    Args:
749        name (str): The name of the toolchain proxy repository contianing the registerable toolchain.
750        version (str): The version of the tool among "nightly", "beta', or an exact version.
751        exec_compatible_with (list, optional): A list of constraints for the execution platform for this toolchain.
752        target_compatible_with (list, optional): A list of constraints for the target platform for this toolchain.
753        iso_date (str, optional): The date of the tool.
754        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes. See
755            [rust_register_toolchains](#rust_register_toolchains) for more details.
756        urls (list, optional): 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). Defaults to ['https://static.rust-lang.org/dist/{}.tar.xz']
757        auth (dict): Auth object compatible with repository_ctx.download to use when downloading files.
758            See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details.
759        netrc (str, optional): .netrc file to use for authentication; mirrors the eponymous attribute from http_archive
760        auth_patterns (dict, optional): Override mapping of hostnames to authorization patterns; mirrors the eponymous attribute from http_archive
761
762    Returns:
763        str: The name of a registerable rust_analyzer_toolchain.
764    """
765    rust_analyzer_toolchain_tools_repository(
766        name = name + "_tools",
767        version = version,
768        iso_date = iso_date,
769        sha256s = sha256s,
770        urls = urls,
771        auth = auth,
772        netrc = netrc,
773        auth_patterns = auth_patterns,
774    )
775
776    toolchain_repository_proxy(
777        name = name,
778        toolchain = "@{}//:{}".format(name + "_tools", "rust_analyzer_toolchain"),
779        toolchain_type = "@rules_rust//rust/rust_analyzer:toolchain_type",
780        exec_compatible_with = exec_compatible_with,
781        target_compatible_with = target_compatible_with,
782    )
783
784    return "@{}//:toolchain".format(
785        name,
786    )
787
788_RUSTFMT_TOOLCHAIN_TOOLS_ATTRS = {
789    "auth": attr.string_dict(
790        doc = (
791            "Auth object compatible with repository_ctx.download to use when downloading files. " +
792            "See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details."
793        ),
794    ),
795    "auth_patterns": attr.string_dict(
796        doc = "Override mapping of hostnames to authorization patterns; mirrors the eponymous attribute from http_archive",
797    ),
798    "exec_triple": attr.string(
799        doc = "The Rust-style triple Rustfmt is expected to run on.",
800        mandatory = True,
801    ),
802    "iso_date": attr.string(
803        doc = "The date of the tool (or None, if the version is a specific version).",
804    ),
805    "netrc": attr.string(
806        doc = ".netrc file to use for authentication; mirrors the eponymous attribute from http_archive",
807    ),
808    "sha256s": attr.string_dict(
809        doc = "A dict associating tool subdirectories to sha256 hashes. See [rust_register_toolchains](#rust_register_toolchains) for more details.",
810    ),
811    "urls": attr.string_list(
812        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).",
813        default = DEFAULT_STATIC_RUST_URL_TEMPLATES,
814    ),
815    "version": attr.string(
816        doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
817        mandatory = True,
818    ),
819}
820
821def _rustfmt_toolchain_tools_repository_impl(repository_ctx):
822    sha256s = dict(repository_ctx.attr.sha256s)
823    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
824        repository_ctx.name,
825    ))
826
827    rustfmt = "//:rustfmt_bin"
828    rustc = "//:rustc"
829    rustc_lib = "//:rustc_lib"
830
831    exec_triple = triple(repository_ctx.attr.exec_triple)
832
833    rustc_content, rustc_sha256 = load_rust_compiler(
834        ctx = repository_ctx,
835        iso_date = repository_ctx.attr.iso_date,
836        target_triple = exec_triple,
837        version = repository_ctx.attr.version,
838    )
839    rustfmt_content, rustfmt_sha256 = load_rustfmt(
840        ctx = repository_ctx,
841        iso_date = repository_ctx.attr.iso_date,
842        target_triple = exec_triple,
843        version = repository_ctx.attr.version,
844    )
845
846    build_contents = [
847        rustc_content,
848        rustfmt_content,
849        BUILD_for_rustfmt_toolchain(
850            name = "rustfmt_toolchain",
851            rustfmt = rustfmt,
852            rustc = rustc,
853            rustc_lib = rustc_lib,
854        ),
855    ]
856    sha256s.update(rustc_sha256 | rustfmt_sha256)
857
858    repository_ctx.file("BUILD.bazel", "\n".join(build_contents))
859    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
860        repository_ctx.name,
861    ))
862
863    repro = {"name": repository_ctx.name}
864    for key in _RUSTFMT_TOOLCHAIN_TOOLS_ATTRS:
865        repro[key] = getattr(repository_ctx.attr, key)
866    repro["sha256s"] = sha256s
867
868    return repro
869
870rustfmt_toolchain_tools_repository = repository_rule(
871    doc = "A repository rule for defining a rustfmt_toolchain.",
872    attrs = _RUSTFMT_TOOLCHAIN_TOOLS_ATTRS,
873    implementation = _rustfmt_toolchain_tools_repository_impl,
874)
875
876def rustfmt_toolchain_repository(
877        name,
878        version,
879        exec_triple,
880        exec_compatible_with = None,
881        target_compatible_with = None,
882        iso_date = None,
883        channel = None,
884        sha256s = None,
885        urls = None,
886        auth = None,
887        netrc = None,
888        auth_patterns = None):
889    """Assemble a remote rustfmt_toolchain target based on the given params.
890
891    Args:
892        name (str): The name of the toolchain proxy repository contianing the registerable toolchain.
893        version (str): The version of the tool among "nightly", "beta', or an exact version.
894        exec_triple (str): The platform triple Rustfmt is expected to run on.
895        exec_compatible_with (list, optional): A list of constraints for the execution platform for this toolchain.
896        target_compatible_with (list, optional): A list of constraints for the target platform for this toolchain.
897        iso_date (str, optional): The date of the tool.
898        channel (str, optional): The channel value to with which to constrain the toolchain.
899        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes. See
900            [rust_register_toolchains](#rust_register_toolchains) for more details.
901        urls (list, optional): 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). Defaults to ['https://static.rust-lang.org/dist/{}.tar.xz']
902        auth (dict): Auth object compatible with repository_ctx.download to use when downloading files.
903            See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details.
904        netrc (str, optional): .netrc file to use for authentication; mirrors the eponymous attribute from http_archive
905        auth_patterns (dict, optional): Override mapping of hostnames to authorization patterns; mirrors the eponymous attribute from http_archive
906
907    Returns:
908        str: The name of a registerable rustfmt_toolchain.
909    """
910    if exec_compatible_with == None:
911        exec_compatible_with = triple_to_constraint_set(exec_triple)
912
913    rustfmt_toolchain_tools_repository(
914        name = name + "_tools",
915        version = version,
916        iso_date = iso_date,
917        sha256s = sha256s,
918        urls = urls,
919        auth = auth,
920        netrc = netrc,
921        auth_patterns = auth_patterns,
922        exec_triple = exec_triple,
923    )
924
925    toolchain_repository_proxy(
926        name = name,
927        toolchain = "@{}//:{}".format(name + "_tools", "rustfmt_toolchain"),
928        toolchain_type = "@rules_rust//rust/rustfmt:toolchain_type",
929        target_settings = ["@rules_rust//rust/toolchain/channel:{}".format(channel)] if channel else None,
930        exec_compatible_with = exec_compatible_with,
931        target_compatible_with = target_compatible_with,
932    )
933
934    return "@{}//:toolchain".format(
935        name,
936    )
937
938def _rust_toolchain_set_repository_impl(repository_ctx):
939    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
940        repository_ctx.name,
941    ))
942
943    repository_ctx.file("BUILD.bazel", """exports_files(["defs.bzl"])""")
944    repository_ctx.file("defs.bzl", "ALL_TOOLCHAINS = {}\n".format(
945        json.encode_indent(repository_ctx.attr.toolchains, indent = " " * 4),
946    ))
947
948rust_toolchain_set_repository = repository_rule(
949    doc = (
950        "Generates a toolchain-bearing repository that declares the toolchains from some other " +
951        "rust_toolchain_repository."
952    ),
953    attrs = {
954        "toolchains": attr.string_list(
955            doc = "The list of all toolchains created by the current `rust_toolchain_set`",
956            mandatory = True,
957        ),
958    },
959    implementation = _rust_toolchain_set_repository_impl,
960)
961
962def _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions, iso_date):
963    toolchain_repos = []
964
965    for target_triple in depset([exec_triple] + extra_target_triples).to_list():
966        # Parse all provided versions while checking for duplicates
967        channels = {}
968        for version in versions:
969            if version.startswith(("beta", "nightly")):
970                channel, _, date = version.partition("/")
971                ver = channel
972            else:
973                channel = "stable"
974                date = iso_date
975                ver = version
976
977            if channel in channels:
978                fail("Duplicate {} channels provided for {}: {}".format(channel, name, versions))
979
980            channels.update({channel: struct(
981                name = channel,
982                iso_date = date,
983                version = ver,
984            )})
985
986        # Define toolchains for each requested version
987        for channel in channels.values():
988            toolchain_repos.append(struct(
989                name = "{}__{}__{}".format(name, target_triple, channel.name),
990                target_triple = target_triple,
991                channel = channel,
992            ))
993
994    return toolchain_repos
995
996def rust_repository_set(
997        name,
998        exec_triple,
999        target_settings = [],
1000        version = None,
1001        versions = [],
1002        allocator_library = None,
1003        global_allocator_library = None,
1004        extra_target_triples = {},
1005        iso_date = None,
1006        rustfmt_version = None,
1007        edition = None,
1008        dev_components = False,
1009        extra_rustc_flags = None,
1010        extra_exec_rustc_flags = None,
1011        opt_level = None,
1012        sha256s = None,
1013        urls = DEFAULT_STATIC_RUST_URL_TEMPLATES,
1014        auth = None,
1015        netrc = None,
1016        auth_patterns = None,
1017        register_toolchain = True,
1018        exec_compatible_with = None,
1019        default_target_compatible_with = None):
1020    """Assembles a remote repository for the given toolchain params, produces a proxy repository \
1021    to contain the toolchain declaration, and registers the toolchains.
1022
1023    Args:
1024        name (str): The name of the generated repository
1025        exec_triple (str): The Rust-style target that this compiler runs on
1026        target_settings (list, optional): A list of config_settings that must be satisfied by the target configuration in order for this set of toolchains to be selected during toolchain resolution.
1027        version (str): The version of the tool among "nightly", "beta', or an exact version.
1028        versions (list, optional): A list of toolchain versions to download. This paramter only accepts one versions
1029            per channel. E.g. `["1.65.0", "nightly/2022-11-02", "beta/2020-12-30"]`.
1030        allocator_library (str, optional): Target that provides allocator functions when rust_library targets are
1031            embedded in a cc_binary.
1032        global_allocator_library (str, optional): Target that provides allocator functions a global allocator is used with cc_common.link.
1033        extra_target_triples (list or map, optional): Additional rust-style targets that this set of
1034            toolchains should support. If a map, values should be (optional) target_compatible_with lists for that particular target triple.
1035        iso_date (str, optional): The date of the tool.
1036        rustfmt_version (str, optional):  The version of rustfmt to be associated with the
1037            toolchain.
1038        edition (str, optional): The rust edition to be used by default (2015, 2018, or 2021). If absent, every rule is
1039            required to specify its `edition` attribute.
1040        dev_components (bool, optional): Whether to download the rustc-dev components.
1041            Requires version to be "nightly".
1042        extra_rustc_flags (dict, list, optional): Dictionary of target triples to list of extra flags to pass to rustc in non-exec configuration.
1043        extra_exec_rustc_flags (list, optional): Extra flags to pass to rustc in exec configuration.
1044        opt_level (dict, dict, optional): Dictionary of target triples to optimiztion config.
1045        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes. See
1046            [rust_register_toolchains](#rust_register_toolchains) for more details.
1047        urls (list, optional): A list of mirror urls containing the tools from the Rust-lang static file server. These
1048            must contain the '{}' used to substitute the tool being fetched (using .format).
1049        auth (dict): Auth object compatible with repository_ctx.download to use when downloading files.
1050            See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details.
1051        netrc (str, optional): .netrc file to use for authentication; mirrors the eponymous attribute from http_archive
1052        auth_patterns (dict, optional): Override mapping of hostnames to authorization patterns; mirrors the eponymous attribute from http_archive
1053
1054        register_toolchain (bool): If True, the generated `rust_toolchain` target will become a registered toolchain.
1055        exec_compatible_with (list, optional): A list of constraints for the execution platform for this toolchain.
1056        default_target_compatible_with (list, optional): A list of constraints for the target platform for this toolchain when the exec platform is the same as the target platform.
1057    """
1058
1059    if version and versions:
1060        fail("`version` and `versions` attributes are mutually exclusive. Update {} to use one".format(
1061            name,
1062        ))
1063
1064    if not version and not versions:
1065        fail("`version` or `versions` attributes are required. Update {} to use one".format(
1066            name,
1067        ))
1068
1069    if version:
1070        # buildifier: disable=print
1071        print("`rust_repository_set.version` is deprecated. Instead use `rust_repository_set.versions`")
1072
1073    if version and not versions:
1074        versions = [version]
1075
1076    # extra_target_triples may be a dict or list - make a list we can pass to _get_toolchain_repositories
1077    extra_target_triples_list = []
1078    for extra_target_triple in extra_target_triples:
1079        extra_target_triples_list.append(extra_target_triple)
1080
1081    all_toolchain_names = []
1082    for toolchain in _get_toolchain_repositories(name, exec_triple, extra_target_triples_list, versions, iso_date):
1083        target_compatible_with = None
1084        if toolchain.target_triple == exec_triple:
1085            # The exec triple implicitly gets a toolchain with itself as a target - use default_target_compatible_with for it
1086            target_compatible_with = default_target_compatible_with
1087        elif type(extra_target_triples) == "dict":
1088            target_compatible_with = extra_target_triples.get(toolchain.target_triple)
1089
1090        # Infer toolchain-specific rustc flags depending on the type (list, dict, optional) of extra_rustc_flags
1091        if extra_rustc_flags == None:
1092            toolchain_extra_rustc_flags = []
1093        elif type(extra_rustc_flags) == "list":
1094            toolchain_extra_rustc_flags = extra_rustc_flags
1095        elif type(extra_rustc_flags) == "dict":
1096            toolchain_extra_rustc_flags = extra_rustc_flags.get(toolchain.target_triple)
1097        else:
1098            fail("extra_rustc_flags should be a list or a dict")
1099
1100        all_toolchain_names.append(rust_toolchain_repository(
1101            name = toolchain.name,
1102            allocator_library = allocator_library,
1103            global_allocator_library = global_allocator_library,
1104            auth = auth,
1105            netrc = netrc,
1106            auth_patterns = auth_patterns,
1107            channel = toolchain.channel.name,
1108            dev_components = dev_components,
1109            edition = edition,
1110            exec_triple = exec_triple,
1111            extra_exec_rustc_flags = extra_exec_rustc_flags,
1112            extra_rustc_flags = toolchain_extra_rustc_flags,
1113            opt_level = opt_level.get(toolchain.target_triple) if opt_level != None else None,
1114            target_settings = target_settings,
1115            iso_date = toolchain.channel.iso_date,
1116            rustfmt_version = rustfmt_version,
1117            sha256s = sha256s,
1118            target_triple = toolchain.target_triple,
1119            urls = urls,
1120            version = toolchain.channel.version,
1121            exec_compatible_with = exec_compatible_with,
1122            target_compatible_with = target_compatible_with,
1123        ))
1124
1125    # This repository exists to allow `rust_repository_set` to work with the `maybe` wrapper.
1126    rust_toolchain_set_repository(
1127        name = name,
1128        toolchains = all_toolchain_names,
1129    )
1130
1131    # Register toolchains
1132    if register_toolchain:
1133        native.register_toolchains(*all_toolchain_names)
1134        native.register_toolchains(str(Label("//rust/private/dummy_cc_toolchain:dummy_cc_wasm32_toolchain")))
1135