• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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# Reexport `load_arbitrary_tool` as it's currently in use in https://github.com/google/cargo-raze
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 = DEFAULT_NIGHTLY_VERSION,
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 `sha256` 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.
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 dev_components:
180        has_nightly = False
181        for ver in versions:
182            if ver.startswith("nightly"):
183                has_nightly = True
184                break
185        if not has_nightly:
186            fail("rustc-dev components were requested but no \"nightly\" is being registered. Please update `versions` to include a nightly version.")
187
188    if not rust_analyzer_version:
189        rust_analyzer_version = select_rust_version(versions)
190
191    rust_analyzer_repo_name = "rust_analyzer_{}".format(rust_analyzer_version.replace("/", "-"))
192    rust_analyzer_iso_date = None
193    if rust_analyzer_version.startswith(("beta", "nightly")):
194        rust_analyzer_version, _, rust_analyzer_iso_date = rustfmt_version.partition("/")
195
196    toolchain_names = []
197    toolchain_labels = {}
198    toolchain_types = {}
199    exec_compatible_with_by_toolchain = {}
200    target_compatible_with_by_toolchain = {}
201
202    maybe(
203        rust_analyzer_toolchain_repository,
204        name = rust_analyzer_repo_name,
205        version = rust_analyzer_version,
206        urls = urls,
207        sha256s = sha256s,
208        iso_date = rust_analyzer_iso_date,
209    )
210
211    toolchain_names.append(rust_analyzer_repo_name)
212    toolchain_labels[rust_analyzer_repo_name] = "@{}_tools//:rust_analyzer_toolchain".format(
213        rust_analyzer_repo_name,
214    )
215    exec_compatible_with_by_toolchain[rust_analyzer_repo_name] = []
216    target_compatible_with_by_toolchain[rust_analyzer_repo_name] = []
217    toolchain_types[rust_analyzer_repo_name] = "@rules_rust//rust/rust_analyzer:toolchain_type"
218
219    if register_toolchains:
220        native.register_toolchains("@{}//:toolchain".format(
221            rust_analyzer_repo_name,
222        ))
223
224    rustfmt_iso_date = None
225    rustfmt_version_or_channel = rustfmt_version
226    if rustfmt_version.startswith(("beta", "nightly")):
227        rustfmt_version_or_channel, _, rustfmt_iso_date = rustfmt_version.partition("/")
228
229    for exec_triple, name in DEFAULT_TOOLCHAIN_TRIPLES.items():
230        maybe(
231            rust_repository_set,
232            name = name,
233            dev_components = dev_components,
234            edition = edition,
235            exec_triple = exec_triple,
236            extra_target_triples = extra_target_triples,
237            allocator_library = allocator_library,
238            global_allocator_library = global_allocator_library,
239            iso_date = iso_date,
240            register_toolchain = register_toolchains,
241            rustfmt_version = rustfmt_version,
242            extra_rustc_flags = extra_rustc_flags,
243            extra_exec_rustc_flags = extra_exec_rustc_flags,
244            sha256s = sha256s,
245            urls = urls,
246            version = version,
247            versions = versions,
248        )
249
250        rustfmt_repo_name = "rustfmt_{}__{}".format(rustfmt_version.replace("/", "-"), exec_triple)
251
252        maybe(
253            rustfmt_toolchain_repository,
254            name = rustfmt_repo_name,
255            version = rustfmt_version_or_channel,
256            urls = urls,
257            sha256s = sha256s,
258            iso_date = rustfmt_iso_date,
259            exec_triple = exec_triple,
260        )
261
262        if register_toolchains:
263            native.register_toolchains("@{}//:toolchain".format(
264                rustfmt_repo_name,
265            ))
266
267        for toolchain in _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions, iso_date):
268            toolchain_names.append(toolchain.name)
269            toolchain_labels[toolchain.name] = "@{}//:{}".format(toolchain.name + "_tools", "rust_toolchain")
270            exec_compatible_with_by_toolchain[toolchain.name] = triple_to_constraint_set(exec_triple)
271            target_compatible_with_by_toolchain[toolchain.name] = triple_to_constraint_set(toolchain.target_triple)
272            toolchain_types[toolchain.name] = "@rules_rust//rust:toolchain"
273
274        toolchain_names.append(rustfmt_repo_name)
275        toolchain_labels[rustfmt_repo_name] = "@{}_tools//:rustfmt_toolchain".format(rustfmt_repo_name)
276        exec_compatible_with_by_toolchain[rustfmt_repo_name] = triple_to_constraint_set(exec_triple)
277        target_compatible_with_by_toolchain[rustfmt_repo_name] = []
278        toolchain_types[rustfmt_repo_name] = "@rules_rust//rust/rustfmt:toolchain_type"
279
280    toolchain_repository_hub(
281        name = "rust_toolchains",
282        toolchain_names = toolchain_names,
283        toolchain_labels = toolchain_labels,
284        toolchain_types = toolchain_types,
285        exec_compatible_with = exec_compatible_with_by_toolchain,
286        target_compatible_with = target_compatible_with_by_toolchain,
287    )
288
289# buildifier: disable=unnamed-macro
290def rust_repositories(**kwargs):
291    """**Deprecated**: Use [rules_rust_dependencies](#rules_rust_dependencies) \
292    and [rust_register_toolchains](#rust_register_toolchains) directly.
293
294    Args:
295        **kwargs (dict): Keyword arguments for the `rust_register_toolchains` macro.
296    """
297    rules_rust_dependencies()
298
299    rust_register_toolchains(**kwargs)
300
301def _rust_toolchain_tools_repository_impl(ctx):
302    """The implementation of the rust toolchain tools repository rule."""
303
304    check_version_valid(ctx.attr.version, ctx.attr.iso_date)
305
306    exec_triple = triple(ctx.attr.exec_triple)
307
308    build_components = [
309        load_rust_compiler(
310            ctx = ctx,
311            iso_date = ctx.attr.iso_date,
312            target_triple = exec_triple,
313            version = ctx.attr.version,
314        ),
315        load_clippy(
316            ctx = ctx,
317            iso_date = ctx.attr.iso_date,
318            target_triple = exec_triple,
319            version = ctx.attr.version,
320        ),
321        load_cargo(
322            ctx = ctx,
323            iso_date = ctx.attr.iso_date,
324            target_triple = exec_triple,
325            version = ctx.attr.version,
326        ),
327    ]
328
329    if ctx.attr.rustfmt_version:
330        rustfmt_version = ctx.attr.rustfmt_version
331        rustfmt_iso_date = None
332        if rustfmt_version in ("nightly", "beta"):
333            if ctx.attr.iso_date:
334                rustfmt_iso_date = ctx.attr.iso_date
335            else:
336                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(
337                    ctx.name,
338                ))
339        elif rustfmt_version.startswith(("nightly", "beta")):
340            rustfmt_version, _, rustfmt_iso_date = rustfmt_version.partition("/")
341        build_components.append(load_rustfmt(
342            ctx = ctx,
343            target_triple = triple(ctx.attr.exec_triple),
344            version = rustfmt_version,
345            iso_date = rustfmt_iso_date,
346        ))
347
348    # Rust 1.45.0 and nightly builds after 2020-05-22 need the llvm-tools gzip to get the libLLVM dylib
349    include_llvm_tools = ctx.attr.version >= "1.45.0" or (ctx.attr.version == "nightly" and ctx.attr.iso_date > "2020-05-22")
350    if include_llvm_tools:
351        build_components.append(load_llvm_tools(
352            ctx = ctx,
353            target_triple = exec_triple,
354        ))
355
356    target_triple = triple(ctx.attr.target_triple)
357    build_components.append(load_rust_stdlib(
358        ctx = ctx,
359        target_triple = target_triple,
360    ))
361
362    stdlib_linkflags = None
363    if "BAZEL_RUST_STDLIB_LINKFLAGS" in ctx.os.environ:
364        stdlib_linkflags = ctx.os.environ["BAZEL_RUST_STDLIB_LINKFLAGS"].split(":")
365
366    build_components.append(BUILD_for_rust_toolchain(
367        name = "rust_toolchain",
368        exec_triple = exec_triple,
369        allocator_library = ctx.attr.allocator_library,
370        global_allocator_library = ctx.attr.global_allocator_library,
371        target_triple = target_triple,
372        stdlib_linkflags = stdlib_linkflags,
373        default_edition = ctx.attr.edition,
374        include_rustfmt = not (not ctx.attr.rustfmt_version),
375        include_llvm_tools = include_llvm_tools,
376        extra_rustc_flags = ctx.attr.extra_rustc_flags,
377        extra_exec_rustc_flags = ctx.attr.extra_exec_rustc_flags,
378        opt_level = ctx.attr.opt_level if ctx.attr.opt_level else None,
379    ))
380
381    # Not all target triples are expected to have dev components
382    if ctx.attr.dev_components:
383        load_rustc_dev_nightly(ctx, target_triple)
384
385    ctx.file("WORKSPACE.bazel", "")
386    ctx.file("BUILD.bazel", "\n".join(build_components))
387
388rust_toolchain_tools_repository = repository_rule(
389    doc = (
390        "Composes a single workspace containing the toolchain components for compiling on a given " +
391        "platform to a series of target platforms.\n" +
392        "\n" +
393        "A given instance of this rule should be accompanied by a toolchain_repository_proxy " +
394        "invocation to declare its toolchains to Bazel; the indirection allows separating toolchain " +
395        "selection from toolchain fetching."
396    ),
397    attrs = {
398        "allocator_library": attr.string(
399            doc = "Target that provides allocator functions when rust_library targets are embedded in a cc_binary.",
400            default = "@rules_rust//ffi/cc/allocator_library",
401        ),
402        "auth": attr.string_dict(
403            doc = (
404                "Auth object compatible with repository_ctx.download to use when downloading files. " +
405                "See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details."
406            ),
407        ),
408        "dev_components": attr.bool(
409            doc = "Whether to download the rustc-dev components (defaults to False). Requires version to be \"nightly\".",
410            default = False,
411        ),
412        "edition": attr.string(
413            doc = (
414                "The rust edition to be used by default (2015, 2018, or 2021). " +
415                "If absent, every rule is required to specify its `edition` attribute."
416            ),
417        ),
418        "exec_triple": attr.string(
419            doc = "The Rust-style target that this compiler runs on",
420            mandatory = True,
421        ),
422        "extra_exec_rustc_flags": attr.string_list(
423            doc = "Extra flags to pass to rustc in exec configuration",
424        ),
425        "extra_rustc_flags": attr.string_list(
426            doc = "Extra flags to pass to rustc in non-exec configuration",
427        ),
428        "global_allocator_library": attr.string(
429            doc = "Target that provides allocator functions when a global allocator is used with cc_common.link.",
430            default = "@rules_rust//ffi/cc/global_allocator_library",
431        ),
432        "iso_date": attr.string(
433            doc = "The date of the tool (or None, if the version is a specific version).",
434        ),
435        "opt_level": attr.string_dict(
436            doc = "Rustc optimization levels. For more details see the documentation for `rust_toolchain.opt_level`.",
437        ),
438        "rustfmt_version": attr.string(
439            doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
440        ),
441        "sha256s": attr.string_dict(
442            doc = "A dict associating tool subdirectories to sha256 hashes. See [rust_repositories](#rust_repositories) for more details.",
443        ),
444        "target_triple": attr.string(
445            doc = "The Rust-style target that this compiler builds for.",
446            mandatory = True,
447        ),
448        "urls": attr.string_list(
449            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).",
450            default = DEFAULT_STATIC_RUST_URL_TEMPLATES,
451        ),
452        "version": attr.string(
453            doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
454            mandatory = True,
455        ),
456    },
457    implementation = _rust_toolchain_tools_repository_impl,
458)
459
460def _toolchain_repository_proxy_impl(repository_ctx):
461    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
462        repository_ctx.name,
463    ))
464
465    repository_ctx.file("BUILD.bazel", BUILD_for_toolchain(
466        name = "toolchain",
467        toolchain = repository_ctx.attr.toolchain,
468        target_settings = repository_ctx.attr.target_settings,
469        toolchain_type = repository_ctx.attr.toolchain_type,
470        target_compatible_with = repository_ctx.attr.target_compatible_with,
471        exec_compatible_with = repository_ctx.attr.exec_compatible_with,
472    ))
473
474toolchain_repository_proxy = repository_rule(
475    doc = (
476        "Generates a toolchain-bearing repository that declares the toolchains from some other " +
477        "rust_toolchain_repository."
478    ),
479    attrs = {
480        "exec_compatible_with": attr.string_list(
481            doc = "A list of constraints for the execution platform for this toolchain.",
482        ),
483        "target_compatible_with": attr.string_list(
484            doc = "A list of constraints for the target platform for this toolchain.",
485        ),
486        "target_settings": attr.string_list(
487            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.",
488        ),
489        "toolchain": attr.string(
490            doc = "The name of the toolchain implementation target.",
491            mandatory = True,
492        ),
493        "toolchain_type": attr.string(
494            doc = "The toolchain type of the toolchain to declare",
495            mandatory = True,
496        ),
497    },
498    implementation = _toolchain_repository_proxy_impl,
499)
500
501# For legacy support
502rust_toolchain_repository_proxy = toolchain_repository_proxy
503
504# N.B. A "proxy repository" is needed to allow for registering the toolchain (with constraints)
505# without actually downloading the toolchain.
506def rust_toolchain_repository(
507        name,
508        version,
509        exec_triple,
510        target_triple,
511        exec_compatible_with = None,
512        target_compatible_with = None,
513        target_settings = [],
514        channel = None,
515        allocator_library = None,
516        global_allocator_library = None,
517        iso_date = None,
518        rustfmt_version = None,
519        edition = None,
520        dev_components = False,
521        extra_rustc_flags = None,
522        extra_exec_rustc_flags = None,
523        opt_level = None,
524        sha256s = None,
525        urls = DEFAULT_STATIC_RUST_URL_TEMPLATES,
526        auth = None):
527    """Assembles a remote repository for the given toolchain params, produces a proxy repository \
528    to contain the toolchain declaration, and registers the toolchains.
529
530    Args:
531        name (str): The name of the generated repository
532        version (str): The version of the tool among "nightly", "beta", or an exact version.
533        exec_triple (str): The Rust-style target that this compiler runs on.
534        target_triple (str): The Rust-style target to build for.
535        channel (str, optional): The channel of the Rust toolchain.
536        exec_compatible_with (list, optional): A list of constraints for the execution platform for this toolchain.
537        target_compatible_with (list, optional): A list of constraints for the target platform for this toolchain.
538        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.
539        allocator_library (str, optional): Target that provides allocator functions when rust_library targets are embedded in a cc_binary.
540        global_allocator_library (str, optional): Target that provides allocator functions when a global allocator is used with cc_common.link.
541        iso_date (str, optional): The date of the tool.
542        rustfmt_version (str, optional):  The version of rustfmt to be associated with the
543            toolchain.
544        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.
545        dev_components (bool, optional): Whether to download the rustc-dev components.
546            Requires version to be "nightly". Defaults to False.
547        extra_rustc_flags (list, optional): Extra flags to pass to rustc in non-exec configuration.
548        extra_exec_rustc_flags (list, optional): Extra flags to pass to rustc in exec configuration.
549        opt_level (dict, optional): Optimization level config for this toolchain.
550        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes. See
551            [rust_repositories](#rust_repositories) for more details.
552        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']
553        auth (dict): Auth object compatible with repository_ctx.download to use when downloading files.
554            See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details.
555
556    Returns:
557        str: The name of the registerable toolchain created by this rule.
558    """
559
560    if rustfmt_version in ("nightly", "beta"):
561        # buildifier: disable=print
562        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")
563        rustfmt_version = "{}/{}".format(rustfmt_version, DEFAULT_NIGHTLY_ISO_DATE)
564
565    if exec_compatible_with == None:
566        exec_compatible_with = triple_to_constraint_set(exec_triple)
567
568    if target_compatible_with == None:
569        target_compatible_with = triple_to_constraint_set(target_triple)
570
571    tools_repo_name = "{}_tools".format(name)
572
573    rust_toolchain_tools_repository(
574        name = tools_repo_name,
575        exec_triple = exec_triple,
576        allocator_library = allocator_library,
577        global_allocator_library = global_allocator_library,
578        target_triple = target_triple,
579        iso_date = iso_date,
580        version = version,
581        rustfmt_version = rustfmt_version,
582        edition = edition,
583        dev_components = dev_components,
584        extra_rustc_flags = extra_rustc_flags,
585        extra_exec_rustc_flags = extra_exec_rustc_flags,
586        opt_level = opt_level,
587        sha256s = sha256s,
588        urls = urls,
589        auth = auth,
590    )
591
592    channel_target_settings = ["@rules_rust//rust/toolchain/channel:{}".format(channel)] if channel else []
593
594    toolchain_repository_proxy(
595        name = name,
596        toolchain = "@{}//:rust_toolchain".format(tools_repo_name),
597        target_settings = channel_target_settings + target_settings,
598        toolchain_type = "@rules_rust//rust:toolchain",
599        exec_compatible_with = exec_compatible_with,
600        target_compatible_with = target_compatible_with,
601    )
602
603    return "@{name}//:toolchain".format(
604        name = name,
605    )
606
607def _rust_analyzer_toolchain_tools_repository_impl(repository_ctx):
608    load_rust_src(
609        ctx = repository_ctx,
610        iso_date = repository_ctx.attr.iso_date,
611        version = repository_ctx.attr.version,
612    )
613
614    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
615        repository_ctx.name,
616    ))
617
618    host_triple = get_host_triple(repository_ctx)
619    build_contents = [
620        load_rust_compiler(
621            ctx = repository_ctx,
622            iso_date = repository_ctx.attr.iso_date,
623            target_triple = host_triple,
624            version = repository_ctx.attr.version,
625        ),
626    ]
627    rustc = "//:rustc"
628
629    proc_macro_srv = None
630    if includes_rust_analyzer_proc_macro_srv(repository_ctx.attr.version, repository_ctx.attr.iso_date):
631        build_contents.append(BUILD_for_rust_analyzer_proc_macro_srv(host_triple))
632        proc_macro_srv = "//:rust_analyzer_proc_macro_srv"
633
634    build_contents.append(BUILD_for_rust_analyzer_toolchain(
635        name = "rust_analyzer_toolchain",
636        rustc = rustc,
637        proc_macro_srv = proc_macro_srv,
638    ))
639
640    repository_ctx.file("BUILD.bazel", "\n".join(build_contents))
641    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
642        repository_ctx.name,
643    ))
644
645rust_analyzer_toolchain_tools_repository = repository_rule(
646    doc = "A repository rule for defining a rust_analyzer_toolchain with a `rust-src` artifact.",
647    attrs = {
648        "auth": attr.string_dict(
649            doc = (
650                "Auth object compatible with repository_ctx.download to use when downloading files. " +
651                "See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details."
652            ),
653        ),
654        "iso_date": attr.string(
655            doc = "The date of the tool (or None, if the version is a specific version).",
656        ),
657        "sha256s": attr.string_dict(
658            doc = "A dict associating tool subdirectories to sha256 hashes. See [rust_repositories](#rust_repositories) for more details.",
659        ),
660        "urls": attr.string_list(
661            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).",
662            default = DEFAULT_STATIC_RUST_URL_TEMPLATES,
663        ),
664        "version": attr.string(
665            doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
666            mandatory = True,
667        ),
668    },
669    implementation = _rust_analyzer_toolchain_tools_repository_impl,
670)
671
672def rust_analyzer_toolchain_repository(
673        name,
674        version,
675        exec_compatible_with = [],
676        target_compatible_with = [],
677        iso_date = None,
678        sha256s = None,
679        urls = None,
680        auth = None):
681    """Assemble a remote rust_analyzer_toolchain target based on the given params.
682
683    Args:
684        name (str): The name of the toolchain proxy repository contianing the registerable toolchain.
685        version (str): The version of the tool among "nightly", "beta', or an exact version.
686        exec_compatible_with (list, optional): A list of constraints for the execution platform for this toolchain.
687        target_compatible_with (list, optional): A list of constraints for the target platform for this toolchain.
688        iso_date (str, optional): The date of the tool.
689        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes. See
690            [rust_repositories](#rust_repositories) for more details.
691        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']
692        auth (dict): Auth object compatible with repository_ctx.download to use when downloading files.
693            See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details.
694
695    Returns:
696        str: The name of a registerable rust_analyzer_toolchain.
697    """
698    rust_analyzer_toolchain_tools_repository(
699        name = name + "_tools",
700        version = version,
701        iso_date = iso_date,
702        sha256s = sha256s,
703        urls = urls,
704        auth = auth,
705    )
706
707    toolchain_repository_proxy(
708        name = name,
709        toolchain = "@{}//:{}".format(name + "_tools", "rust_analyzer_toolchain"),
710        toolchain_type = "@rules_rust//rust/rust_analyzer:toolchain_type",
711        exec_compatible_with = exec_compatible_with,
712        target_compatible_with = target_compatible_with,
713    )
714
715    return "@{}//:toolchain".format(
716        name,
717    )
718
719def _rustfmt_toolchain_tools_repository_impl(repository_ctx):
720    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
721        repository_ctx.name,
722    ))
723
724    rustfmt = "//:rustfmt_bin"
725    rustc = "//:rustc"
726    rustc_lib = "//:rustc_lib"
727
728    exec_triple = triple(repository_ctx.attr.exec_triple)
729
730    build_contents = [
731        load_rust_compiler(
732            ctx = repository_ctx,
733            iso_date = repository_ctx.attr.iso_date,
734            target_triple = exec_triple,
735            version = repository_ctx.attr.version,
736        ),
737        load_rustfmt(
738            ctx = repository_ctx,
739            iso_date = repository_ctx.attr.iso_date,
740            target_triple = exec_triple,
741            version = repository_ctx.attr.version,
742        ),
743        BUILD_for_rustfmt_toolchain(
744            name = "rustfmt_toolchain",
745            rustfmt = rustfmt,
746            rustc = rustc,
747            rustc_lib = rustc_lib,
748        ),
749    ]
750
751    repository_ctx.file("BUILD.bazel", "\n".join(build_contents))
752    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
753        repository_ctx.name,
754    ))
755
756rustfmt_toolchain_tools_repository = repository_rule(
757    doc = "A repository rule for defining a rustfmt_toolchain.",
758    attrs = {
759        "auth": attr.string_dict(
760            doc = (
761                "Auth object compatible with repository_ctx.download to use when downloading files. " +
762                "See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details."
763            ),
764        ),
765        "exec_triple": attr.string(
766            doc = "The Rust-style triple Rustfmt is expected to run on.",
767            mandatory = True,
768        ),
769        "iso_date": attr.string(
770            doc = "The date of the tool (or None, if the version is a specific version).",
771        ),
772        "sha256s": attr.string_dict(
773            doc = "A dict associating tool subdirectories to sha256 hashes. See [rust_repositories](#rust_repositories) for more details.",
774        ),
775        "urls": attr.string_list(
776            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).",
777            default = DEFAULT_STATIC_RUST_URL_TEMPLATES,
778        ),
779        "version": attr.string(
780            doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
781            mandatory = True,
782        ),
783    },
784    implementation = _rustfmt_toolchain_tools_repository_impl,
785)
786
787def rustfmt_toolchain_repository(
788        name,
789        version,
790        exec_triple,
791        exec_compatible_with = None,
792        target_compatible_with = None,
793        iso_date = None,
794        channel = None,
795        sha256s = None,
796        urls = None,
797        auth = None):
798    """Assemble a remote rustfmt_toolchain target based on the given params.
799
800    Args:
801        name (str): The name of the toolchain proxy repository contianing the registerable toolchain.
802        version (str): The version of the tool among "nightly", "beta', or an exact version.
803        exec_triple (str): The platform triple Rustfmt is expected to run on.
804        exec_compatible_with (list, optional): A list of constraints for the execution platform for this toolchain.
805        target_compatible_with (list, optional): A list of constraints for the target platform for this toolchain.
806        iso_date (str, optional): The date of the tool.
807        channel (str, optional): The channel value to with which to constrain the toolchain.
808        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes. See
809            [rust_repositories](#rust_repositories) for more details.
810        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']
811        auth (dict): Auth object compatible with repository_ctx.download to use when downloading files.
812            See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details.
813
814    Returns:
815        str: The name of a registerable rustfmt_toolchain.
816    """
817    if exec_compatible_with == None:
818        exec_compatible_with = triple_to_constraint_set(exec_triple)
819
820    rustfmt_toolchain_tools_repository(
821        name = name + "_tools",
822        version = version,
823        iso_date = iso_date,
824        sha256s = sha256s,
825        urls = urls,
826        auth = auth,
827        exec_triple = exec_triple,
828    )
829
830    toolchain_repository_proxy(
831        name = name,
832        toolchain = "@{}//:{}".format(name + "_tools", "rustfmt_toolchain"),
833        toolchain_type = "@rules_rust//rust/rustfmt:toolchain_type",
834        target_settings = ["@rules_rust//rust/toolchain/channel:{}".format(channel)] if channel else None,
835        exec_compatible_with = exec_compatible_with,
836        target_compatible_with = target_compatible_with,
837    )
838
839    return "@{}//:toolchain".format(
840        name,
841    )
842
843def _rust_toolchain_set_repository_impl(repository_ctx):
844    repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
845        repository_ctx.name,
846    ))
847
848    repository_ctx.file("BUILD.bazel", """exports_files(["defs.bzl"])""")
849    repository_ctx.file("defs.bzl", "ALL_TOOLCHAINS = {}\n".format(
850        json.encode_indent(repository_ctx.attr.toolchains, indent = " " * 4),
851    ))
852
853rust_toolchain_set_repository = repository_rule(
854    doc = (
855        "Generates a toolchain-bearing repository that declares the toolchains from some other " +
856        "rust_toolchain_repository."
857    ),
858    attrs = {
859        "toolchains": attr.string_list(
860            doc = "The list of all toolchains created by the current `rust_toolchain_set`",
861            mandatory = True,
862        ),
863    },
864    implementation = _rust_toolchain_set_repository_impl,
865)
866
867def _get_toolchain_repositories(name, exec_triple, extra_target_triples, versions, iso_date):
868    toolchain_repos = []
869
870    for target_triple in depset([exec_triple] + extra_target_triples).to_list():
871        # Parse all provided versions while checking for duplicates
872        channels = {}
873        for version in versions:
874            if version.startswith(("beta", "nightly")):
875                channel, _, date = version.partition("/")
876                ver = channel
877            else:
878                channel = "stable"
879                date = iso_date
880                ver = version
881
882            if channel in channels:
883                fail("Duplicate {} channels provided for {}: {}".format(channel, name, versions))
884
885            channels.update({channel: struct(
886                name = channel,
887                iso_date = date,
888                version = ver,
889            )})
890
891        # Define toolchains for each requested version
892        for channel in channels.values():
893            toolchain_repos.append(struct(
894                name = "{}__{}__{}".format(name, target_triple, channel.name),
895                target_triple = target_triple,
896                channel = channel,
897            ))
898
899    return toolchain_repos
900
901def rust_repository_set(
902        name,
903        exec_triple,
904        target_settings = [],
905        version = None,
906        versions = [],
907        allocator_library = None,
908        global_allocator_library = None,
909        extra_target_triples = {},
910        iso_date = None,
911        rustfmt_version = None,
912        edition = None,
913        dev_components = False,
914        extra_rustc_flags = None,
915        extra_exec_rustc_flags = None,
916        opt_level = None,
917        sha256s = None,
918        urls = DEFAULT_STATIC_RUST_URL_TEMPLATES,
919        auth = None,
920        register_toolchain = True,
921        exec_compatible_with = None,
922        default_target_compatible_with = None):
923    """Assembles a remote repository for the given toolchain params, produces a proxy repository \
924    to contain the toolchain declaration, and registers the toolchains.
925
926    Args:
927        name (str): The name of the generated repository
928        exec_triple (str): The Rust-style target that this compiler runs on
929        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.
930        version (str): The version of the tool among "nightly", "beta', or an exact version.
931        versions (list, optional): A list of toolchain versions to download. This paramter only accepts one versions
932            per channel. E.g. `["1.65.0", "nightly/2022-11-02", "beta/2020-12-30"]`.
933        allocator_library (str, optional): Target that provides allocator functions when rust_library targets are
934            embedded in a cc_binary.
935        global_allocator_library (str, optional): Target that provides allocator functions a global allocator is used with cc_common.link.
936        extra_target_triples (list or map, optional): Additional rust-style targets that this set of
937            toolchains should support. If a map, values should be (optional) target_compatible_with lists for that particular target triple.
938        iso_date (str, optional): The date of the tool.
939        rustfmt_version (str, optional):  The version of rustfmt to be associated with the
940            toolchain.
941        edition (str, optional): The rust edition to be used by default (2015, 2018, or 2021). If absent, every rule is
942            required to specify its `edition` attribute.
943        dev_components (bool, optional): Whether to download the rustc-dev components.
944            Requires version to be "nightly".
945        extra_rustc_flags (dict, list, optional): Dictionary of target triples to list of extra flags to pass to rustc in non-exec configuration.
946        extra_exec_rustc_flags (list, optional): Extra flags to pass to rustc in exec configuration.
947        opt_level (dict, dict, optional): Dictionary of target triples to optimiztion config.
948        sha256s (str, optional): A dict associating tool subdirectories to sha256 hashes. See
949            [rust_repositories](#rust_repositories) for more details.
950        urls (list, optional): A list of mirror urls containing the tools from the Rust-lang static file server. These
951            must contain the '{}' used to substitute the tool being fetched (using .format).
952        auth (dict): Auth object compatible with repository_ctx.download to use when downloading files.
953            See [repository_ctx.download](https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download) for more details.
954        register_toolchain (bool): If True, the generated `rust_toolchain` target will become a registered toolchain.
955        exec_compatible_with (list, optional): A list of constraints for the execution platform for this toolchain.
956        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.
957    """
958
959    if version and versions:
960        fail("`version` and `versions` attributes are mutually exclusive. Update {} to use one".format(
961            name,
962        ))
963
964    if not version and not versions:
965        fail("`version` or `versions` attributes are required. Update {} to use one".format(
966            name,
967        ))
968
969    if version:
970        # buildifier: disable=print
971        print("`rust_repository_set.version` is deprecated. Instead use `rust_repository_set.versions`")
972
973    if version and not versions:
974        versions = [version]
975
976    # extra_target_triples may be a dict or list - make a list we can pass to _get_toolchain_repositories
977    extra_target_triples_list = []
978    for extra_target_triple in extra_target_triples:
979        extra_target_triples_list.append(extra_target_triple)
980
981    all_toolchain_names = []
982    for toolchain in _get_toolchain_repositories(name, exec_triple, extra_target_triples_list, versions, iso_date):
983        target_compatible_with = None
984        if toolchain.target_triple == exec_triple:
985            # The exec triple implicitly gets a toolchain with itself as a target - use default_target_compatible_with for it
986            target_compatible_with = default_target_compatible_with
987        elif type(extra_target_triples) == "dict":
988            target_compatible_with = extra_target_triples.get(toolchain.target_triple)
989
990        all_toolchain_names.append(rust_toolchain_repository(
991            name = toolchain.name,
992            allocator_library = allocator_library,
993            global_allocator_library = global_allocator_library,
994            auth = auth,
995            channel = toolchain.channel.name,
996            dev_components = dev_components,
997            edition = edition,
998            exec_triple = exec_triple,
999            extra_exec_rustc_flags = extra_exec_rustc_flags,
1000            extra_rustc_flags = extra_rustc_flags.get(toolchain.target_triple) if extra_rustc_flags != None else None,
1001            opt_level = opt_level.get(toolchain.target_triple) if opt_level != None else None,
1002            target_settings = target_settings,
1003            iso_date = toolchain.channel.iso_date,
1004            rustfmt_version = rustfmt_version,
1005            sha256s = sha256s,
1006            target_triple = toolchain.target_triple,
1007            urls = urls,
1008            version = toolchain.channel.version,
1009            exec_compatible_with = exec_compatible_with,
1010            target_compatible_with = target_compatible_with,
1011        ))
1012
1013    # This repository exists to allow `rust_repository_set` to work with the `maybe` wrapper.
1014    rust_toolchain_set_repository(
1015        name = name,
1016        toolchains = all_toolchain_names,
1017    )
1018
1019    # Register toolchains
1020    if register_toolchain:
1021        native.register_toolchains(*all_toolchain_names)
1022        native.register_toolchains(str(Label("//rust/private/dummy_cc_toolchain:dummy_cc_wasm32_toolchain")))
1023