cargo-dist
cargo-dist copied to clipboard
Enable cross compiling on non Rustup systems
I and a lot of NixOs users, use rust-overlay(or fenix) to manage the installed rust toolchain, selecting and installing targets and Rust versions in our flake.nix or similiar files.
I wanted to test the musl build for our project via cargo-dist, so I did cargo dist build and got this warning:
WARN You're trying to cross-compile for musl from glibc, but I can't find rustup to ensure you have the rust toolchains for it!
and it only built for the current target. Can we widen that check to not use rustup, perhaps by checking for installed targets as cargo does?
Asking some rust toolchain experts what the Correct approach is
Context for what's up here:
cargo dist is functionally serving as a replacement for cargo build that handles far more setup details for you. One of those details is trying to smooth over Simple cross compilations by detecting you have rustup installed and running rustup target add SOME_NON_HOST_TARGET.
If rustup isn't present we currently refuse to proceed with building a non-host target, absent a way to prove that it's setup (me being overly conservative). We can just remove that restriction and let you blow yourself up with an opaque lower-level error in non-rustup setups, but, it would be nice if there was a way to query what targets are properly setup.
Because cargo dist is invoked as a subcommand, the only env-var we have access to is $CARGO (but we're tolerant of even not having that, because people really like invoking cargo subcommands as not subcommands sigh).
So at the end of the day if I'm being 100% "responsible" I only have access to "the ability to opaquely invoke cargo" (not even rustc). This means I need a way to do one of the following, which I can't seem to find:
- have cargo tell me the targets installed
- have cargo report its sysroot (so i could look at the dirs that appear in
$SYSROOT/lib/rustlib/) - have cargo tell me the rustc it's using (so i can ask rustc for the sysroot with
rustc --print sysroot)
I have considered the following options:
cargo rustc -- --print sysroot: will first build all dependencies, making it extremely slow at best and useless for "catch missing target early"cargo rust --print sysroot: unstable, "baking" absent a champion- https://github.com/rust-lang/cargo/issues/9357
- resolve the path to cargo, assume
cargo_path.parent().parent()is a sysroot- not sure how reliable/correct this is, makes me sad
- resolve the path to cargo, assume
rustcis in the same dir?- maybe actually correct? but idk if that Works With rust-overlay or ignores some important configs cargo reads to select rustc or something
- wait, can i even reliably resolve the path to cargo when invoked as a non-subcommand if the command
cargois usually pointing to the rustup toolchain selector shim...? bleugh.
more refined can-do-it-today approach (approved by upstream toolchain criminals):
- find rustc
- if $CARGO is set (because we were invoked as a subcommand, presumably): something to the effect of
PathBuf::from(env("CARGO")).parent().join(format!("rustc{ext}")) - otherwise we need to yolo bare
cargointo PATH, so yolo barerustcinto PATH too. people DO mess this up and have different toolchains on path for those two, but upstream closes all such bugs as WONTFIX because it's too cursed.
- if $CARGO is set (because we were invoked as a subcommand, presumably): something to the effect of
{computed_rustc} --print sysroot- check if
{sysroot}/lib/rustlib/{target}exists
correction, instead of fucking with sysroot:
rustc --print=target-libdir --target={target}- if that errors, we now know that the target triple they specified is Genuine Gibberish to their compiler
- it that succeeds, check if the returned path exists
- if it does, the target is installed
- if it doesn't, the target isn't installed (try to use rustup, but fine if can't)
So all of the above is still correct and worth doing but just to clarify the issue the OP actually ran into:
- they ran
cargo dist buildexpecting it to build all targets, but that defaults to the host build. thus no cross-compiling occured. - HOWEVER: the "validity check" (basically implicitly running
cargo dist plan) we run before every command constructs a build graph for EVERY target to make sure that's ok. this includes computing but not executingcargo buildcommands for every target. the warning in question is in the "compute the build commands" step, so we freak out that you're trying to cross when you absolutely aren't. - this created a situation where cargo-dist suggested crossing was going to happen, but it never was, so the user EXTREMELY REASONABLY thought the warning meant we tried to cross and skipped it (and I initially thought the same because we have similar warnings/behaviours for installers!)
These warnings are overzealous, we should probably do something like supress them if --artifacts=all is set.
Appreciate you taking the time to dive into this, we've been loving cargo-dist