blob: 083991a51221cd8bca089dae71ed5483d7a67e1f [file] [log] [blame]
Brian Silvermancc09f182022-03-09 15:40:20 -08001"""The rust_toolchain rule definition and implementation."""
2
3load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
4load("//rust/private:common.bzl", "rust_common")
5load("//rust/private:utils.bzl", "dedent", "find_cc_toolchain", "make_static_lib_symlink")
6
7def _rust_stdlib_filegroup_impl(ctx):
8 rust_std = ctx.files.srcs
9 dot_a_files = []
10 between_alloc_and_core_files = []
11 core_files = []
12 between_core_and_std_files = []
13 std_files = []
Brian Silverman8751d482022-05-18 23:28:44 -070014 memchr_files = []
Brian Silvermancc09f182022-03-09 15:40:20 -080015 alloc_files = []
16 self_contained_files = [
17 file
18 for file in rust_std
19 if file.basename.endswith(".o") and "self-contained" in file.path
20 ]
21
22 std_rlibs = [f for f in rust_std if f.basename.endswith(".rlib")]
23 if std_rlibs:
24 # std depends on everything
25 #
26 # core only depends on alloc, but we poke adler in there
27 # because that needs to be before miniz_oxide
28 #
29 # alloc depends on the allocator_library if it's configured, but we
30 # do that later.
31 dot_a_files = [make_static_lib_symlink(ctx.actions, f) for f in std_rlibs]
32
33 alloc_files = [f for f in dot_a_files if "alloc" in f.basename and "std" not in f.basename]
34 between_alloc_and_core_files = [f for f in dot_a_files if "compiler_builtins" in f.basename]
35 core_files = [f for f in dot_a_files if ("core" in f.basename or "adler" in f.basename) and "std" not in f.basename]
36 between_core_and_std_files = [
37 f
38 for f in dot_a_files
Brian Silverman8751d482022-05-18 23:28:44 -070039 if "alloc" not in f.basename and "compiler_builtins" not in f.basename and "core" not in f.basename and "adler" not in f.basename and "std" not in f.basename and "memchr" not in f.basename
Brian Silvermancc09f182022-03-09 15:40:20 -080040 ]
Brian Silverman8751d482022-05-18 23:28:44 -070041 memchr_files = [f for f in dot_a_files if "memchr" in f.basename]
Brian Silvermancc09f182022-03-09 15:40:20 -080042 std_files = [f for f in dot_a_files if "std" in f.basename]
43
Brian Silverman8751d482022-05-18 23:28:44 -070044 partitioned_files_len = len(alloc_files) + len(between_alloc_and_core_files) + len(core_files) + len(between_core_and_std_files) + len(memchr_files) + len(std_files)
Brian Silvermancc09f182022-03-09 15:40:20 -080045 if partitioned_files_len != len(dot_a_files):
Brian Silverman8751d482022-05-18 23:28:44 -070046 partitioned = alloc_files + between_alloc_and_core_files + core_files + between_core_and_std_files + memchr_files + std_files
Brian Silvermancc09f182022-03-09 15:40:20 -080047 for f in sorted(partitioned):
48 # buildifier: disable=print
49 print("File partitioned: {}".format(f.basename))
50 fail("rust_toolchain couldn't properly partition rlibs in rust_std. Partitioned {} out of {} files. This is probably a bug in the rule implementation.".format(partitioned_files_len, len(dot_a_files)))
51
52 return [
53 DefaultInfo(
54 files = depset(ctx.files.srcs),
55 ),
56 rust_common.stdlib_info(
57 std_rlibs = std_rlibs,
58 dot_a_files = dot_a_files,
59 between_alloc_and_core_files = between_alloc_and_core_files,
60 core_files = core_files,
61 between_core_and_std_files = between_core_and_std_files,
62 std_files = std_files,
Brian Silverman8751d482022-05-18 23:28:44 -070063 memchr_files = memchr_files,
Brian Silvermancc09f182022-03-09 15:40:20 -080064 alloc_files = alloc_files,
65 self_contained_files = self_contained_files,
66 srcs = ctx.attr.srcs,
67 ),
68 ]
69
70rust_stdlib_filegroup = rule(
71 doc = "A dedicated filegroup-like rule for Rust stdlib artifacts.",
72 implementation = _rust_stdlib_filegroup_impl,
73 attrs = {
74 "srcs": attr.label_list(
75 allow_files = True,
76 doc = "The list of targets/files that are components of the rust-stdlib file group",
77 mandatory = True,
78 ),
79 },
80)
81
82def _ltl(library, ctx, cc_toolchain, feature_configuration):
83 """A helper to generate `LibraryToLink` objects
84
85 Args:
86 library (File): A rust library file to link.
87 ctx (ctx): The rule's context object.
88 cc_toolchain (CcToolchainInfo): A cc toolchain provider to be used.
89 feature_configuration (feature_configuration): feature_configuration to be queried.
90
91 Returns:
92 LibraryToLink: A provider containing information about libraries to link.
93 """
94 return cc_common.create_library_to_link(
95 actions = ctx.actions,
96 feature_configuration = feature_configuration,
97 cc_toolchain = cc_toolchain,
98 static_library = library,
99 pic_static_library = library,
100 )
101
102def _make_libstd_and_allocator_ccinfo(ctx, rust_std, allocator_library):
103 """Make the CcInfo (if possible) for libstd and allocator libraries.
104
105 Args:
106 ctx (ctx): The rule's context object.
107 rust_std: The Rust standard library.
108 allocator_library: The target to use for providing allocator functions.
109
110
111 Returns:
112 A CcInfo object for the required libraries, or None if no such libraries are available.
113 """
114 cc_toolchain, feature_configuration = find_cc_toolchain(ctx)
115 cc_infos = []
116
117 if not rust_common.stdlib_info in rust_std:
118 fail(dedent("""\
119 {} --
120 The `rust_lib` ({}) must be a target providing `rust_common.stdlib_info`
121 (typically `rust_stdlib_filegroup` rule from @rules_rust//rust:defs.bzl).
122 See https://github.com/bazelbuild/rules_rust/pull/802 for more information.
123 """).format(ctx.label, rust_std))
124 rust_stdlib_info = rust_std[rust_common.stdlib_info]
125
126 if rust_stdlib_info.self_contained_files:
127 compilation_outputs = cc_common.create_compilation_outputs(
128 objects = depset(rust_stdlib_info.self_contained_files),
129 )
130
131 linking_context, _linking_outputs = cc_common.create_linking_context_from_compilation_outputs(
132 name = ctx.label.name,
133 actions = ctx.actions,
134 feature_configuration = feature_configuration,
135 cc_toolchain = cc_toolchain,
136 compilation_outputs = compilation_outputs,
137 )
138
139 cc_infos.append(CcInfo(
140 linking_context = linking_context,
141 ))
142
143 if rust_stdlib_info.std_rlibs:
144 alloc_inputs = depset(
145 [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.alloc_files],
146 )
147 between_alloc_and_core_inputs = depset(
148 [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.between_alloc_and_core_files],
149 transitive = [alloc_inputs],
150 order = "topological",
151 )
152 core_inputs = depset(
153 [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.core_files],
154 transitive = [between_alloc_and_core_inputs],
155 order = "topological",
156 )
157
158 # The libraries panic_abort and panic_unwind are alternatives.
159 # The std by default requires panic_unwind.
160 # Exclude panic_abort if panic_unwind is present.
161 # TODO: Provide a setting to choose between panic_abort and panic_unwind.
162 filtered_between_core_and_std_files = rust_stdlib_info.between_core_and_std_files
163 has_panic_unwind = [
164 f
165 for f in filtered_between_core_and_std_files
166 if "panic_unwind" in f.basename
167 ]
168 if has_panic_unwind:
169 filtered_between_core_and_std_files = [
170 f
171 for f in filtered_between_core_and_std_files
172 if "panic_abort" not in f.basename
173 ]
Brian Silverman8751d482022-05-18 23:28:44 -0700174 memchr_inputs = depset(
175 [
176 _ltl(f, ctx, cc_toolchain, feature_configuration)
177 for f in rust_stdlib_info.memchr_files
178 ],
179 transitive = [core_inputs],
180 order = "topological",
181 )
Brian Silvermancc09f182022-03-09 15:40:20 -0800182 between_core_and_std_inputs = depset(
183 [
184 _ltl(f, ctx, cc_toolchain, feature_configuration)
185 for f in filtered_between_core_and_std_files
186 ],
Brian Silverman8751d482022-05-18 23:28:44 -0700187 transitive = [memchr_inputs],
Brian Silvermancc09f182022-03-09 15:40:20 -0800188 order = "topological",
189 )
190 std_inputs = depset(
191 [
192 _ltl(f, ctx, cc_toolchain, feature_configuration)
193 for f in rust_stdlib_info.std_files
194 ],
195 transitive = [between_core_and_std_inputs],
196 order = "topological",
197 )
198
Brian Silverman8751d482022-05-18 23:28:44 -0700199 link_inputs = [depset([cc_common.create_linker_input(
Brian Silvermancc09f182022-03-09 15:40:20 -0800200 owner = rust_std.label,
201 libraries = std_inputs,
Brian Silverman8751d482022-05-18 23:28:44 -0700202 )])]
Brian Silvermancc09f182022-03-09 15:40:20 -0800203
Brian Silverman8751d482022-05-18 23:28:44 -0700204 allocator_inputs = []
Brian Silvermancc09f182022-03-09 15:40:20 -0800205 if allocator_library:
Brian Silverman8751d482022-05-18 23:28:44 -0700206 allocator_inputs = allocator_library[CcInfo].linking_context.linker_inputs.to_list()
Brian Silvermancc09f182022-03-09 15:40:20 -0800207
208 cc_infos.append(CcInfo(
209 linking_context = cc_common.create_linking_context(
210 linker_inputs = depset(
Brian Silverman8751d482022-05-18 23:28:44 -0700211 allocator_inputs,
212 transitive = link_inputs,
Brian Silvermancc09f182022-03-09 15:40:20 -0800213 order = "topological",
214 ),
215 ),
216 ))
217
218 if cc_infos:
219 return cc_common.merge_cc_infos(
220 direct_cc_infos = cc_infos,
221 )
222 return None
223
224def _symlink_sysroot_tree(ctx, name, target):
225 """Generate a set of symlinks to files from another target
226
227 Args:
228 ctx (ctx): The toolchain's context object
229 name (str): The name of the sysroot directory (typically `ctx.label.name`)
230 target (Target): A target owning files to symlink
231
232 Returns:
233 depset[File]: A depset of the generated symlink files
234 """
235 tree_files = []
236 for file in target.files.to_list():
237 # Parse the path to the file relative to the workspace root so a
238 # symlink matching this path can be created within the sysroot.
239
240 # The code blow attempts to parse any workspace names out of the
241 # path. For local targets, this code is a noop.
242 if target.label.workspace_root:
243 file_path = file.path.split(target.label.workspace_root, 1)[-1]
244 else:
245 file_path = file.path
246
247 symlink = ctx.actions.declare_file("{}/{}".format(name, file_path.lstrip("/")))
248
249 ctx.actions.symlink(
250 output = symlink,
251 target_file = file,
252 )
253
254 tree_files.append(symlink)
255
256 return depset(tree_files)
257
258def _symlink_sysroot_bin(ctx, name, directory, target):
259 """Crete a symlink to a target file.
260
261 Args:
262 ctx (ctx): The rule's context object
263 name (str): A common name for the output directory
264 directory (str): The directory under `name` to put the file in
265 target (File): A File object to symlink to
266
267 Returns:
268 File: A newly generated symlink file
269 """
270 symlink = ctx.actions.declare_file("{}/{}/{}".format(
271 name,
272 directory,
273 target.basename,
274 ))
275
276 ctx.actions.symlink(
277 output = symlink,
278 target_file = target,
279 is_executable = True,
280 )
281
282 return symlink
283
284def _generate_sysroot(
285 ctx,
286 rustc,
287 rustdoc,
288 rustc_lib,
289 cargo = None,
290 clippy = None,
291 llvm_tools = None,
292 rust_std = None,
293 rustfmt = None):
294 """Generate a rust sysroot from collection of toolchain components
295
296 Args:
297 ctx (ctx): A context object from a `rust_toolchain` rule.
298 rustc (File): The path to a `rustc` executable.
299 rustdoc (File): The path to a `rustdoc` executable.
300 rustc_lib (Target): A collection of Files containing dependencies of `rustc`.
301 cargo (File, optional): The path to a `cargo` executable.
302 clippy (File, optional): The path to a `clippy-driver` executable.
303 llvm_tools (Target, optional): A collection of llvm tools used by `rustc`.
304 rust_std (Target, optional): A collection of Files containing Rust standard library components.
305 rustfmt (File, optional): The path to a `rustfmt` executable.
306
307 Returns:
308 struct: A struct of generated files representing the new sysroot
309 """
310 name = ctx.label.name
311
312 # Define runfiles
313 direct_files = []
314 transitive_file_sets = []
315
316 # Rustc
317 sysroot_rustc = _symlink_sysroot_bin(ctx, name, "bin", rustc)
318 direct_files.extend([sysroot_rustc])
319
320 # Rustc dependencies
321 sysroot_rustc_lib = None
322 if rustc_lib:
323 sysroot_rustc_lib = _symlink_sysroot_tree(ctx, name, rustc_lib)
324 transitive_file_sets.extend([sysroot_rustc_lib])
325
326 # Rustdoc
327 sysroot_rustdoc = _symlink_sysroot_bin(ctx, name, "bin", rustdoc)
328 direct_files.extend([sysroot_rustdoc])
329
330 # Clippy
331 sysroot_clippy = None
332 if clippy:
333 sysroot_clippy = _symlink_sysroot_bin(ctx, name, "bin", clippy)
334 direct_files.extend([sysroot_clippy])
335
336 # Cargo
337 sysroot_cargo = None
338 if cargo:
339 sysroot_cargo = _symlink_sysroot_bin(ctx, name, "bin", cargo)
340 direct_files.extend([sysroot_cargo])
341
342 # Rustfmt
343 sysroot_rustfmt = None
344 if rustfmt:
345 sysroot_rustfmt = _symlink_sysroot_bin(ctx, name, "bin", rustfmt)
346 direct_files.extend([sysroot_rustfmt])
347
348 # Llvm tools
349 sysroot_llvm_tools = None
350 if llvm_tools:
351 sysroot_llvm_tools = _symlink_sysroot_tree(ctx, name, llvm_tools)
352 transitive_file_sets.extend([sysroot_llvm_tools])
353
354 # Rust standard library
355 sysroot_rust_std = None
356 if rust_std:
357 sysroot_rust_std = _symlink_sysroot_tree(ctx, name, rust_std)
358 transitive_file_sets.extend([sysroot_rust_std])
359
360 # Declare a file in the root of the sysroot to make locating the sysroot easy
361 sysroot_anchor = ctx.actions.declare_file("{}/rust.sysroot".format(name))
362 ctx.actions.write(
363 output = sysroot_anchor,
364 content = "\n".join([
365 "cargo: {}".format(cargo),
366 "clippy: {}".format(clippy),
367 "llvm_tools: {}".format(llvm_tools),
368 "rust_std: {}".format(rust_std),
369 "rustc_lib: {}".format(rustc_lib),
370 "rustc: {}".format(rustc),
371 "rustdoc: {}".format(rustdoc),
372 "rustfmt: {}".format(rustfmt),
373 ]),
374 )
375
376 # Create a depset of all sysroot files (symlinks and their real paths)
377 all_files = depset(direct_files, transitive = transitive_file_sets)
378
379 return struct(
380 all_files = all_files,
381 cargo = sysroot_cargo,
382 clippy = sysroot_clippy,
383 rust_std = sysroot_rust_std,
384 rustc = sysroot_rustc,
385 rustc_lib = sysroot_rustc_lib,
386 rustdoc = sysroot_rustdoc,
387 rustfmt = sysroot_rustfmt,
388 sysroot_anchor = sysroot_anchor,
389 )
390
391def _rust_toolchain_impl(ctx):
392 """The rust_toolchain implementation
393
394 Args:
395 ctx (ctx): The rule's context object
396
397 Returns:
398 list: A list containing the target's toolchain Provider info
399 """
400 compilation_mode_opts = {}
401 for k, v in ctx.attr.opt_level.items():
402 if not k in ctx.attr.debug_info:
403 fail("Compilation mode {} is not defined in debug_info but is defined opt_level".format(k))
404 compilation_mode_opts[k] = struct(debug_info = ctx.attr.debug_info[k], opt_level = v)
405 for k, v in ctx.attr.debug_info.items():
406 if not k in ctx.attr.opt_level:
407 fail("Compilation mode {} is not defined in opt_level but is defined debug_info".format(k))
408
409 if ctx.attr.target_triple and ctx.file.target_json:
410 fail("Do not specify both target_triple and target_json, either use a builtin triple or provide a custom specification file.")
411
412 rename_first_party_crates = ctx.attr._rename_first_party_crates[BuildSettingInfo].value
413 third_party_dir = ctx.attr._third_party_dir[BuildSettingInfo].value
414
415 if ctx.attr.rust_lib:
416 # buildifier: disable=print
417 print("`rust_toolchain.rust_lib` is deprecated. Please update {} to use `rust_toolchain.rust_std`".format(
418 ctx.label,
419 ))
420 rust_std = ctx.attr.rust_lib
421 else:
422 rust_std = ctx.attr.rust_std
423
424 sysroot = _generate_sysroot(
425 ctx = ctx,
426 rustc = ctx.file.rustc,
427 rustdoc = ctx.file.rust_doc,
428 rustc_lib = ctx.attr.rustc_lib,
429 rust_std = rust_std,
430 rustfmt = ctx.file.rustfmt,
431 clippy = ctx.file.clippy_driver,
432 cargo = ctx.file.cargo,
433 llvm_tools = ctx.attr.llvm_tools,
434 )
435
436 expanded_stdlib_linkflags = []
437 for flag in ctx.attr.stdlib_linkflags:
438 expanded_stdlib_linkflags.append(
439 ctx.expand_location(
440 flag,
441 targets = rust_std[rust_common.stdlib_info].srcs,
442 ),
443 )
444
445 linking_context = cc_common.create_linking_context(
446 linker_inputs = depset([
447 cc_common.create_linker_input(
448 owner = ctx.label,
449 user_link_flags = depset(expanded_stdlib_linkflags),
450 ),
451 ]),
452 )
453
454 # Contains linker flags needed to link Rust standard library.
455 # These need to be added to linker command lines when the linker is not rustc
456 # (rustc does this automatically). Linker flags wrapped in an otherwise empty
457 # `CcInfo` to provide the flags in a way that doesn't duplicate them per target
458 # providing a `CcInfo`.
459 stdlib_linkflags_cc_info = CcInfo(
460 compilation_context = cc_common.create_compilation_context(),
461 linking_context = linking_context,
462 )
463
464 # Determine the path and short_path of the sysroot
465 sysroot_path = sysroot.sysroot_anchor.dirname
466 sysroot_short_path, _, _ = sysroot.sysroot_anchor.short_path.rpartition("/")
467
468 toolchain = platform_common.ToolchainInfo(
469 all_files = sysroot.all_files,
470 binary_ext = ctx.attr.binary_ext,
471 cargo = sysroot.cargo,
472 clippy_driver = sysroot.clippy,
473 compilation_mode_opts = compilation_mode_opts,
474 crosstool_files = ctx.files._cc_toolchain,
475 default_edition = ctx.attr.default_edition,
476 dylib_ext = ctx.attr.dylib_ext,
477 exec_triple = ctx.attr.exec_triple,
478 libstd_and_allocator_ccinfo = _make_libstd_and_allocator_ccinfo(ctx, rust_std, ctx.attr.allocator_library),
479 os = ctx.attr.os,
480 rust_doc = sysroot.rustdoc,
481 rust_lib = sysroot.rust_std, # `rust_lib` is deprecated and only exists for legacy support.
482 rust_std = sysroot.rust_std,
483 rust_std_paths = depset([file.dirname for file in sysroot.rust_std.to_list()]),
484 rustc = sysroot.rustc,
485 rustc_lib = sysroot.rustc_lib,
486 rustc_srcs = ctx.attr.rustc_srcs,
487 rustfmt = sysroot.rustfmt,
488 staticlib_ext = ctx.attr.staticlib_ext,
489 stdlib_linkflags = stdlib_linkflags_cc_info,
490 sysroot = sysroot_path,
491 sysroot_short_path = sysroot_short_path,
492 target_arch = ctx.attr.target_triple.split("-")[0],
493 target_flag_value = ctx.file.target_json.path if ctx.file.target_json else ctx.attr.target_triple,
494 target_json = ctx.file.target_json,
495 target_triple = ctx.attr.target_triple,
496
497 # Experimental and incompatible flags
498 _rename_first_party_crates = rename_first_party_crates,
499 _third_party_dir = third_party_dir,
500 )
501 return [toolchain]
502
503rust_toolchain = rule(
504 implementation = _rust_toolchain_impl,
505 fragments = ["cpp"],
506 attrs = {
507 "allocator_library": attr.label(
508 doc = "Target that provides allocator functions when rust_library targets are embedded in a cc_binary.",
509 ),
510 "binary_ext": attr.string(
511 doc = "The extension for binaries created from rustc.",
512 mandatory = True,
513 ),
514 "cargo": attr.label(
515 doc = "The location of the `cargo` binary. Can be a direct source or a filegroup containing one item.",
516 allow_single_file = True,
517 cfg = "exec",
518 ),
519 "clippy_driver": attr.label(
520 doc = "The location of the `clippy-driver` binary. Can be a direct source or a filegroup containing one item.",
521 allow_single_file = True,
522 cfg = "exec",
523 ),
524 "debug_info": attr.string_dict(
525 doc = "Rustc debug info levels per opt level",
526 default = {
527 "dbg": "2",
528 "fastbuild": "0",
529 "opt": "0",
530 },
531 ),
532 "default_edition": attr.string(
533 doc = "The edition to use for rust_* rules that don't specify an edition.",
534 default = rust_common.default_edition,
535 ),
536 "dylib_ext": attr.string(
537 doc = "The extension for dynamic libraries created from rustc.",
538 mandatory = True,
539 ),
540 "exec_triple": attr.string(
541 doc = (
542 "The platform triple for the toolchains execution environment. " +
543 "For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations"
544 ),
545 mandatory = True,
546 ),
547 "llvm_tools": attr.label(
548 doc = "LLVM tools that are shipped with the Rust toolchain.",
549 allow_files = True,
550 ),
551 "opt_level": attr.string_dict(
552 doc = "Rustc optimization levels.",
553 default = {
554 "dbg": "0",
555 "fastbuild": "0",
556 "opt": "3",
557 },
558 ),
559 "os": attr.string(
560 doc = "The operating system for the current toolchain",
561 mandatory = True,
562 ),
563 "rust_doc": attr.label(
564 doc = "The location of the `rustdoc` binary. Can be a direct source or a filegroup containing one item.",
565 allow_single_file = True,
566 cfg = "exec",
567 mandatory = True,
568 ),
569 "rust_lib": attr.label(
570 doc = "**Deprecated**: Use `rust_std`",
571 ),
572 "rust_std": attr.label(
573 doc = "The Rust standard library.",
574 ),
575 "rustc": attr.label(
576 doc = "The location of the `rustc` binary. Can be a direct source or a filegroup containing one item.",
577 allow_single_file = True,
578 cfg = "exec",
579 mandatory = True,
580 ),
581 "rustc_lib": attr.label(
582 doc = "The libraries used by rustc during compilation.",
583 cfg = "exec",
584 ),
585 "rustc_srcs": attr.label(
586 doc = "The source code of rustc.",
587 ),
588 "rustfmt": attr.label(
589 doc = "The location of the `rustfmt` binary. Can be a direct source or a filegroup containing one item.",
590 allow_single_file = True,
591 cfg = "exec",
592 ),
593 "staticlib_ext": attr.string(
594 doc = "The extension for static libraries created from rustc.",
595 mandatory = True,
596 ),
597 "stdlib_linkflags": attr.string_list(
598 doc = (
599 "Additional linker flags to use when Rust standard library is linked by a C++ linker " +
600 "(rustc will deal with these automatically). Subject to location expansion with respect " +
601 "to the srcs of the `rust_std` attribute."
602 ),
603 mandatory = True,
604 ),
605 "target_json": attr.label(
606 doc = ("Override the target_triple with a custom target specification. " +
607 "For more details see: https://doc.rust-lang.org/rustc/targets/custom.html"),
608 allow_single_file = True,
609 ),
610 "target_triple": attr.string(
611 doc = (
612 "The platform triple for the toolchains target environment. " +
613 "For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations"
614 ),
615 ),
616 "_cc_toolchain": attr.label(
617 default = "@bazel_tools//tools/cpp:current_cc_toolchain",
618 ),
619 "_rename_first_party_crates": attr.label(
620 default = "@rules_rust//rust/settings:rename_first_party_crates",
621 ),
622 "_third_party_dir": attr.label(
623 default = "@rules_rust//rust/settings:third_party_dir",
624 ),
625 },
626 toolchains = [
627 "@bazel_tools//tools/cpp:toolchain_type",
628 ],
629 incompatible_use_toolchain_transition = True,
630 doc = """Declares a Rust toolchain for use.
631
632This is for declaring a custom toolchain, eg. for configuring a particular version of rust or supporting a new platform.
633
634Example:
635
636Suppose the core rust team has ported the compiler to a new target CPU, called `cpuX`. This \
637support can be used in Bazel by defining a new toolchain definition and declaration:
638
639```python
640load('@rules_rust//rust:toolchain.bzl', 'rust_toolchain')
641
642rust_toolchain(
643 name = "rust_cpuX_impl",
644 rustc = "@rust_cpuX//:rustc",
645 rustc_lib = "@rust_cpuX//:rustc_lib",
646 rust_std = "@rust_cpuX//:rust_std",
647 rust_doc = "@rust_cpuX//:rustdoc",
648 binary_ext = "",
649 staticlib_ext = ".a",
650 dylib_ext = ".so",
651 stdlib_linkflags = ["-lpthread", "-ldl"],
652 os = "linux",
653)
654
655toolchain(
656 name = "rust_cpuX",
657 exec_compatible_with = [
658 "@platforms//cpu:cpuX",
659 ],
660 target_compatible_with = [
661 "@platforms//cpu:cpuX",
662 ],
663 toolchain = ":rust_cpuX_impl",
664)
665```
666
667Then, either add the label of the toolchain rule to `register_toolchains` in the WORKSPACE, or pass \
668it to the `"--extra_toolchains"` flag for Bazel, and it will be used.
669
670See @rules_rust//rust:repositories.bzl for examples of defining the @rust_cpuX repository \
671with the actual binaries and libraries.
672""",
673)