# 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-/. 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, )