1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
# A Rust toolchain whose compiler is a dependency rather than a name.
#
# The prelude's system_rust_toolchain hands RustToolchainInfo
# `RunInfo(args = ["rustc"])` — a bare string. Nothing about the compiler is an
# input to any action, so nothing about it reaches the action's cache digest,
# and there is nothing for a remote worker to materialise. Both of this repo's
# problems come from that one line: a shared cache cannot tell two compilers
# apart, and remote execution has no compiler to run.
#
# Here the dist tarball is a dep. cmd_args carries the archive's directory into
# every rustc invocation, so buck knows the action depends on it.
load("@prelude//rust:rust_toolchain.bzl", "PanicRuntime", "RustToolchainInfo")
def _hermetic_rust_toolchain_impl(ctx):
dist = ctx.attrs.dist[DefaultInfo].default_outputs[0]
# The dist tarball keeps its components in sibling directories, so the
# compiler's default sysroot (rustc/) holds no libstd — it lives under
# rust-std-<triple>/. The same stitching scripts/rustc does by hand, said
# to buck instead. The compiler's own codegen libraries are found by rpath,
# relative to the binary, so only the sysroot has to be named.
# rustc goes through a wrapper because the sysroot cannot travel any other
# way: rustc_flags takes plain strings, so an artifact path cannot be put
# there, and putting --sysroot on the compiler unconditionally breaks
# buck's own rustc_cfg action, which passes an empty one. Both the wrapper
# and the tarball are inputs, which is the point.
wrapper = ctx.attrs.wrapper[DefaultInfo].default_outputs[0]
compiler = cmd_args(wrapper, dist, ctx.attrs.rustc_target_triple)
rustdoc = cmd_args(dist, format = "{}/rustc/bin/rustdoc")
return [
DefaultInfo(),
RustToolchainInfo(
allow_lints = ctx.attrs.allow_lints,
clippy_driver = RunInfo(args = cmd_args(dist, format = "{}/clippy/bin/clippy-driver")),
clippy_toml = None,
compiler = RunInfo(args = compiler),
default_edition = ctx.attrs.default_edition,
panic_runtime = PanicRuntime("unwind"),
deny_lints = ctx.attrs.deny_lints,
doctests = ctx.attrs.doctests,
nightly_features = ctx.attrs.nightly_features,
report_unused_deps = ctx.attrs.report_unused_deps,
rustc_binary_flags = ctx.attrs.rustc_binary_flags,
rustc_flags = ctx.attrs.rustc_flags,
rustc_target_triple = ctx.attrs.rustc_target_triple,
rustc_test_flags = ctx.attrs.rustc_test_flags,
rustdoc = RunInfo(args = rustdoc),
rustdoc_flags = ctx.attrs.rustdoc_flags,
warn_lints = ctx.attrs.warn_lints,
),
]
hermetic_rust_toolchain = rule(
impl = _hermetic_rust_toolchain_impl,
attrs = {
"allow_lints": attrs.list(attrs.string(), default = []),
"default_edition": attrs.option(attrs.string(), default = None),
"deny_lints": attrs.list(attrs.string(), default = []),
"dist": attrs.dep(providers = [DefaultInfo]),
"wrapper": attrs.dep(providers = [DefaultInfo]),
"doctests": attrs.bool(default = False),
"nightly_features": attrs.bool(default = True),
"report_unused_deps": attrs.bool(default = False),
"rustc_binary_flags": attrs.list(attrs.arg(), default = []),
"rustc_flags": attrs.list(attrs.arg(), default = []),
"rustc_target_triple": attrs.string(),
"rustc_test_flags": attrs.list(attrs.arg(), default = []),
"rustdoc_flags": attrs.list(attrs.arg(), default = []),
"warn_lints": attrs.list(attrs.string(), default = []),
},
is_toolchain_rule = True,
)
|