Skip to content

Commit a3492b4

Browse files
rust_toolchain now generates a Rust sysroot (#1119)
* `rust_toolchain` now recreates a Rust sysroot * Regenerate documentation * Updated docs * Address merge conflicts * Don't use leading `/` * Regenerate documentation * no explicit `--sysroot` flag. * Better fix for `rust_doc_test` * Set `--sysroot` in for `rust_doc_test` * Update rust/private/toolchain_utils.bzl Co-authored-by: Krasimir Georgiev <[email protected]> * Moved `generate_sysroot` Co-authored-by: Krasimir Georgiev <[email protected]>
1 parent c134a45 commit a3492b4

File tree

5 files changed

+218
-29
lines changed

5 files changed

+218
-29
lines changed

docs/flatten.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,9 +1110,9 @@ Run the test with `bazel build //hello_lib:hello_lib_test`.
11101110

11111111
<pre>
11121112
rust_toolchain(<a href="#rust_toolchain-name">name</a>, <a href="#rust_toolchain-allocator_library">allocator_library</a>, <a href="#rust_toolchain-binary_ext">binary_ext</a>, <a href="#rust_toolchain-cargo">cargo</a>, <a href="#rust_toolchain-clippy_driver">clippy_driver</a>, <a href="#rust_toolchain-debug_info">debug_info</a>,
1113-
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-os">os</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>, <a href="#rust_toolchain-rust_lib">rust_lib</a>, <a href="#rust_toolchain-rust_std">rust_std</a>,
1114-
<a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>, <a href="#rust_toolchain-rustc_srcs">rustc_srcs</a>, <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-target_json">target_json</a>,
1115-
<a href="#rust_toolchain-target_triple">target_triple</a>)
1113+
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-llvm_tools">llvm_tools</a>, <a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-os">os</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>, <a href="#rust_toolchain-rust_lib">rust_lib</a>,
1114+
<a href="#rust_toolchain-rust_std">rust_std</a>, <a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>, <a href="#rust_toolchain-rustc_srcs">rustc_srcs</a>, <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>,
1115+
<a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
11161116
</pre>
11171117

11181118
Declares a Rust toolchain for use.
@@ -1170,6 +1170,7 @@ See @rules_rust//rust:repositories.bzl for examples of defining the @rust_cpuX r
11701170
| <a id="rust_toolchain-default_edition"></a>default_edition | The edition to use for rust_* rules that don't specify an edition. | String | optional | "2018" |
11711171
| <a id="rust_toolchain-dylib_ext"></a>dylib_ext | The extension for dynamic libraries created from rustc. | String | required | |
11721172
| <a id="rust_toolchain-exec_triple"></a>exec_triple | The platform triple for the toolchains execution environment. For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations | String | required | |
1173+
| <a id="rust_toolchain-llvm_tools"></a>llvm_tools | LLVM tools that are shipped with the Rust toolchain. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
11731174
| <a id="rust_toolchain-opt_level"></a>opt_level | Rustc optimization levels. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {"dbg": "0", "fastbuild": "0", "opt": "3"} |
11741175
| <a id="rust_toolchain-os"></a>os | The operating system for the current toolchain | String | required | |
11751176
| <a id="rust_toolchain-rust_doc"></a>rust_doc | The location of the <code>rustdoc</code> binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required | |

docs/rust_repositories.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ A dedicated filegroup-like rule for Rust stdlib artifacts.
3535

3636
<pre>
3737
rust_toolchain(<a href="#rust_toolchain-name">name</a>, <a href="#rust_toolchain-allocator_library">allocator_library</a>, <a href="#rust_toolchain-binary_ext">binary_ext</a>, <a href="#rust_toolchain-cargo">cargo</a>, <a href="#rust_toolchain-clippy_driver">clippy_driver</a>, <a href="#rust_toolchain-debug_info">debug_info</a>,
38-
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-os">os</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>, <a href="#rust_toolchain-rust_lib">rust_lib</a>, <a href="#rust_toolchain-rust_std">rust_std</a>,
39-
<a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>, <a href="#rust_toolchain-rustc_srcs">rustc_srcs</a>, <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-target_json">target_json</a>,
40-
<a href="#rust_toolchain-target_triple">target_triple</a>)
38+
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-llvm_tools">llvm_tools</a>, <a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-os">os</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>, <a href="#rust_toolchain-rust_lib">rust_lib</a>,
39+
<a href="#rust_toolchain-rust_std">rust_std</a>, <a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>, <a href="#rust_toolchain-rustc_srcs">rustc_srcs</a>, <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>,
40+
<a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
4141
</pre>
4242

4343
Declares a Rust toolchain for use.
@@ -95,6 +95,7 @@ See @rules_rust//rust:repositories.bzl for examples of defining the @rust_cpuX r
9595
| <a id="rust_toolchain-default_edition"></a>default_edition | The edition to use for rust_* rules that don't specify an edition. | String | optional | "2018" |
9696
| <a id="rust_toolchain-dylib_ext"></a>dylib_ext | The extension for dynamic libraries created from rustc. | String | required | |
9797
| <a id="rust_toolchain-exec_triple"></a>exec_triple | The platform triple for the toolchains execution environment. For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations | String | required | |
98+
| <a id="rust_toolchain-llvm_tools"></a>llvm_tools | LLVM tools that are shipped with the Rust toolchain. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
9899
| <a id="rust_toolchain-opt_level"></a>opt_level | Rustc optimization levels. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {"dbg": "0", "fastbuild": "0", "opt": "3"} |
99100
| <a id="rust_toolchain-os"></a>os | The operating system for the current toolchain | String | required | |
100101
| <a id="rust_toolchain-rust_doc"></a>rust_doc | The location of the <code>rustdoc</code> binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required | |

rust/private/rustc.bzl

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -380,19 +380,16 @@ def collect_inputs(
380380

381381
nolinkstamp_compile_inputs = depset(
382382
getattr(files, "data", []) +
383-
[toolchain.rustc] +
384-
toolchain.crosstool_files +
385383
([build_info.rustc_env, build_info.flags] if build_info else []) +
386384
([toolchain.target_json] if toolchain.target_json else []) +
387385
([] if linker_script == None else [linker_script]),
388386
transitive = [
389-
toolchain.rustc_lib,
390-
toolchain.rust_std,
391387
linker_depset,
392388
crate_info.srcs,
393389
dep_info.transitive_crate_outputs,
394390
depset(additional_transitive_inputs),
395391
crate_info.compile_data,
392+
toolchain.all_files,
396393
],
397394
)
398395

@@ -654,7 +651,7 @@ def construct_arguments(
654651
data_paths,
655652
))
656653

657-
# Set the SYSROOT to the directory of the rust_std files passed to the toolchain
654+
# Ensure the sysroot is set for the target platform
658655
env["SYSROOT"] = toolchain.sysroot
659656

660657
# extra_rustc_flags apply to the target configuration, not the exec configuration.

rust/private/rustdoc.bzl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,17 @@ def rustdoc_compile_action(
119119
force_link = True,
120120
)
121121

122+
# Because rustdoc tests compile tests outside of the sandbox, the sysroot
123+
# must be updated to the `short_path` equivilant as it will now be
124+
# a part of runfiles.
125+
if is_test:
126+
if "SYSROOT" in env:
127+
env.update({"SYSROOT": "${{pwd}}/{}".format(toolchain.sysroot_short_path)})
128+
129+
# `rustdoc` does not support the SYSROOT environment variable. To account
130+
# for this, the flag must be explicitly passed to the `rustdoc` binary.
131+
args.rustc_flags.add("--sysroot=${{pwd}}/{}".format(toolchain.sysroot_short_path))
132+
122133
return struct(
123134
executable = ctx.executable._process_wrapper,
124135
inputs = depset([crate_info.output], transitive = [compile_inputs]),

rust/toolchain.bzl

Lines changed: 197 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,173 @@ def _make_libstd_and_allocator_ccinfo(ctx, rust_std, allocator_library):
210210
)
211211
return None
212212

213+
def _symlink_sysroot_tree(ctx, name, target):
214+
"""Generate a set of symlinks to files from another target
215+
216+
Args:
217+
ctx (ctx): The toolchain's context object
218+
name (str): The name of the sysroot directory (typically `ctx.label.name`)
219+
target (Target): A target owning files to symlink
220+
221+
Returns:
222+
depset[File]: A depset of the generated symlink files
223+
"""
224+
tree_files = []
225+
for file in target.files.to_list():
226+
# Parse the path to the file relative to the workspace root so a
227+
# symlink matching this path can be created within the sysroot.
228+
229+
# The code blow attempts to parse any workspace names out of the
230+
# path. For local targets, this code is a noop.
231+
if target.label.workspace_root:
232+
file_path = file.path.split(target.label.workspace_root, 1)[-1]
233+
else:
234+
file_path = file.path
235+
236+
symlink = ctx.actions.declare_file("{}/{}".format(name, file_path.lstrip("/")))
237+
238+
ctx.actions.symlink(
239+
output = symlink,
240+
target_file = file,
241+
)
242+
243+
tree_files.append(symlink)
244+
245+
return depset(tree_files)
246+
247+
def _symlink_sysroot_bin(ctx, name, directory, target):
248+
"""Crete a symlink to a target file.
249+
250+
Args:
251+
ctx (ctx): The rule's context object
252+
name (str): A common name for the output directory
253+
directory (str): The directory under `name` to put the file in
254+
target (File): A File object to symlink to
255+
256+
Returns:
257+
File: A newly generated symlink file
258+
"""
259+
symlink = ctx.actions.declare_file("{}/{}/{}".format(
260+
name,
261+
directory,
262+
target.basename,
263+
))
264+
265+
ctx.actions.symlink(
266+
output = symlink,
267+
target_file = target,
268+
is_executable = True,
269+
)
270+
271+
return symlink
272+
273+
def _generate_sysroot(
274+
ctx,
275+
rustc,
276+
rustdoc,
277+
rustc_lib,
278+
cargo = None,
279+
clippy = None,
280+
llvm_tools = None,
281+
rust_std = None,
282+
rustfmt = None):
283+
"""Generate a rust sysroot from collection of toolchain components
284+
285+
Args:
286+
ctx (ctx): A context object from a `rust_toolchain` rule.
287+
rustc (File): The path to a `rustc` executable.
288+
rustdoc (File): The path to a `rustdoc` executable.
289+
rustc_lib (Target): A collection of Files containing dependencies of `rustc`.
290+
cargo (File, optional): The path to a `cargo` executable.
291+
clippy (File, optional): The path to a `clippy-driver` executable.
292+
llvm_tools (Target, optional): A collection of llvm tools used by `rustc`.
293+
rust_std (Target, optional): A collection of Files containing Rust standard library components.
294+
rustfmt (File, optional): The path to a `rustfmt` executable.
295+
296+
Returns:
297+
struct: A struct of generated files representing the new sysroot
298+
"""
299+
name = ctx.label.name
300+
301+
# Define runfiles
302+
direct_files = []
303+
transitive_file_sets = []
304+
305+
# Rustc
306+
sysroot_rustc = _symlink_sysroot_bin(ctx, name, "bin", rustc)
307+
direct_files.extend([sysroot_rustc, rustc])
308+
309+
# Rustc dependencies
310+
sysroot_rustc_lib = None
311+
if rustc_lib:
312+
sysroot_rustc_lib = _symlink_sysroot_tree(ctx, name, rustc_lib)
313+
transitive_file_sets.extend([sysroot_rustc_lib, rustc_lib.files])
314+
315+
# Rustdoc
316+
sysroot_rustdoc = _symlink_sysroot_bin(ctx, name, "bin", rustdoc)
317+
direct_files.extend([sysroot_rustdoc, rustdoc])
318+
319+
# Clippy
320+
sysroot_clippy = None
321+
if clippy:
322+
sysroot_clippy = _symlink_sysroot_bin(ctx, name, "bin", clippy)
323+
direct_files.extend([sysroot_clippy, clippy])
324+
325+
# Cargo
326+
sysroot_cargo = None
327+
if cargo:
328+
sysroot_cargo = _symlink_sysroot_bin(ctx, name, "bin", cargo)
329+
direct_files.extend([sysroot_cargo, cargo])
330+
331+
# Rustfmt
332+
sysroot_rustfmt = None
333+
if rustfmt:
334+
sysroot_rustfmt = _symlink_sysroot_bin(ctx, name, "bin", rustfmt)
335+
direct_files.extend([sysroot_rustfmt, rustfmt])
336+
337+
# Llvm tools
338+
sysroot_llvm_tools = None
339+
if llvm_tools:
340+
sysroot_llvm_tools = _symlink_sysroot_tree(ctx, name, llvm_tools)
341+
transitive_file_sets.extend([sysroot_llvm_tools, llvm_tools.files])
342+
343+
# Rust standard library
344+
sysroot_rust_std = None
345+
if rust_std:
346+
sysroot_rust_std = _symlink_sysroot_tree(ctx, name, rust_std)
347+
transitive_file_sets.extend([sysroot_rust_std, rust_std.files])
348+
349+
# Declare a file in the root of the sysroot to make locating the sysroot easy
350+
sysroot_anchor = ctx.actions.declare_file("{}/rust.sysroot".format(name))
351+
ctx.actions.write(
352+
output = sysroot_anchor,
353+
content = "\n".join([
354+
"cargo: {}".format(cargo),
355+
"clippy: {}".format(clippy),
356+
"llvm_tools: {}".format(llvm_tools),
357+
"rust_std: {}".format(rust_std),
358+
"rustc_lib: {}".format(rustc_lib),
359+
"rustc: {}".format(rustc),
360+
"rustdoc: {}".format(rustdoc),
361+
"rustfmt: {}".format(rustfmt),
362+
]),
363+
)
364+
365+
# Create a depset of all sysroot files (symlinks and their real paths)
366+
all_files = depset(direct_files, transitive = transitive_file_sets)
367+
368+
return struct(
369+
all_files = all_files,
370+
cargo = sysroot_cargo,
371+
clippy = sysroot_clippy,
372+
rust_std = sysroot_rust_std,
373+
rustc = sysroot_rustc,
374+
rustc_lib = sysroot_rustc_lib,
375+
rustdoc = sysroot_rustdoc,
376+
rustfmt = sysroot_rustfmt,
377+
sysroot_anchor = sysroot_anchor,
378+
)
379+
213380
def _rust_toolchain_impl(ctx):
214381
"""The rust_toolchain implementation
215382
@@ -243,6 +410,18 @@ def _rust_toolchain_impl(ctx):
243410
else:
244411
rust_std = ctx.attr.rust_std
245412

413+
sysroot = _generate_sysroot(
414+
ctx = ctx,
415+
rustc = ctx.file.rustc,
416+
rustdoc = ctx.file.rust_doc,
417+
rustc_lib = ctx.attr.rustc_lib,
418+
rust_std = rust_std,
419+
rustfmt = ctx.file.rustfmt,
420+
clippy = ctx.file.clippy_driver,
421+
cargo = ctx.file.cargo,
422+
llvm_tools = ctx.attr.llvm_tools,
423+
)
424+
246425
expanded_stdlib_linkflags = []
247426
for flag in ctx.attr.stdlib_linkflags:
248427
expanded_stdlib_linkflags.append(
@@ -265,30 +444,26 @@ def _rust_toolchain_impl(ctx):
265444
linking_context = linking_context,
266445
)
267446

268-
# In cases where the toolchain uses the Rust standard library, calculate sysroot path
269-
sysroot_path = None
270-
rust_std_files_list = []
271-
if rust_std:
272-
# Calculate the rustc sysroot path by using a file from the rust-std bundle
273-
rust_std_files_list = rust_std.files.to_list()
274-
if not rust_std_files_list:
275-
fail("The `rust_std` cannot be represented by an empty list")
276-
sysroot_path = rust_std_files_list[0].dirname
447+
# Determine the path and short_path of the sysroot
448+
sysroot_path = sysroot.sysroot_anchor.dirname
449+
sysroot_short_path, _, _ = sysroot.sysroot_anchor.short_path.rpartition("/")
277450

278451
toolchain = platform_common.ToolchainInfo(
279-
rustc = ctx.file.rustc,
280-
rust_doc = ctx.file.rust_doc,
281-
rustfmt = ctx.file.rustfmt,
282-
cargo = ctx.file.cargo,
283-
clippy_driver = ctx.file.clippy_driver,
452+
all_files = sysroot.all_files,
453+
rustc = sysroot.rustc,
454+
rust_doc = sysroot.rustdoc,
455+
rustfmt = sysroot.rustfmt,
456+
cargo = sysroot.cargo,
457+
clippy_driver = sysroot.clippy,
284458
target_json = ctx.file.target_json,
285459
target_flag_value = ctx.file.target_json.path if ctx.file.target_json else ctx.attr.target_triple,
286-
rustc_lib = depset(ctx.files.rustc_lib),
460+
rustc_lib = sysroot.rustc_lib,
287461
rustc_srcs = ctx.attr.rustc_srcs,
288-
rust_std = rust_std.files,
289-
rust_std_paths = depset([file.dirname for file in rust_std_files_list]),
290-
rust_lib = rust_std.files, # `rust_lib` is deprecated and only exists for legacy support.
462+
rust_std = sysroot.rust_std,
463+
rust_std_paths = depset([file.dirname for file in sysroot.rust_std.to_list()]),
464+
rust_lib = sysroot.rust_std, # `rust_lib` is deprecated and only exists for legacy support.
291465
sysroot = sysroot_path,
466+
sysroot_short_path = sysroot_short_path,
292467
binary_ext = ctx.attr.binary_ext,
293468
staticlib_ext = ctx.attr.staticlib_ext,
294469
dylib_ext = ctx.attr.dylib_ext,
@@ -355,6 +530,10 @@ rust_toolchain = rule(
355530
),
356531
mandatory = True,
357532
),
533+
"llvm_tools": attr.label_list(
534+
doc = "LLVM tools that are shipped with the Rust toolchain.",
535+
allow_files = True,
536+
),
358537
"opt_level": attr.string_dict(
359538
doc = "Rustc optimization levels.",
360539
default = {

0 commit comments

Comments
 (0)