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