Skip to content

Commit

Permalink
Better error diagnostics on targets without std.
Browse files Browse the repository at this point in the history
Provides a warning if a docker command fails and `rust-std` is not available for the target. For example, for `x86_64-unknown-dragonfly`, the added output would be:

```bash
[cross] warning: rust-std is not available for x86_64-unknown-dragonfly
[cross] note: you may need to build components for the target via `-Z build-std=<components>` or in your cross configuration specify `target.x86_64-unknown-dragonfly.build-std`
              the available components are core, std, alloc, and proc_macro
```

This is done solely if the command fails and if the target is a built-in, so we don't get misleading warnings for custom targets, and there is no overhead if the build succeeds.
  • Loading branch information
Alexhuszagh committed Jul 3, 2022
1 parent 74c3ba6 commit 10b0eb1
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 4 deletions.
21 changes: 21 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,24 @@ impl Serialize for Target {
}
}

fn warn_on_failure(target: &Target, toolchain: &str, msg_info: MessageInfo) -> Result<()> {
let rust_std = format!("rust-std-{target}");
if target.is_builtin() {
let component = rustup::check_component(&rust_std, toolchain, msg_info)?;
if component.is_not_available() {
shell::warn(format!("rust-std is not available for {target}"), msg_info)?;
shell::note(
format_args!(
r#"you may need to build components for the target via `-Z build-std=<components>` or in your cross configuration specify `target.{target}.build-std`
the available components are core, std, alloc, and proc_macro"#
),
msg_info,
)?;
}
}
Ok(())
}

pub fn run() -> Result<ExitStatus> {
let target_list = rustc::target_list(Verbosity::Quiet.into())?;
let args = cli::parse(&target_list)?;
Expand Down Expand Up @@ -524,6 +542,9 @@ pub fn run() -> Result<ExitStatus> {
.subcommand
.map(|sc| sc.needs_host(is_remote))
.unwrap_or(false);
if !status.success() {
warn_on_failure(&target, &toolchain, args.msg_info)?;
}
if !(status.success() && needs_host) {
return Ok(status);
}
Expand Down
44 changes: 40 additions & 4 deletions src/rustup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,52 @@ pub fn install_component(component: &str, toolchain: &str, msg_info: MessageInfo
.wrap_err_with(|| format!("couldn't install the `{component}` component"))
}

pub fn component_is_installed(
component: &str,
pub enum Component<'a> {
Installed(&'a str),
Available(&'a str),
NotAvailable(&'a str),
}

impl<'a> Component<'a> {
pub fn is_installed(&'a self) -> bool {
matches!(self, Component::Installed(_))
}

pub fn is_not_available(&'a self) -> bool {
matches!(self, Component::NotAvailable(_))
}
}

pub fn check_component<'a>(
component: &'a str,
toolchain: &str,
msg_info: MessageInfo,
) -> Result<bool> {
) -> Result<Component<'a>> {
Ok(Command::new("rustup")
.args(&["component", "list", "--toolchain", toolchain])
.run_and_get_stdout(msg_info)?
.lines()
.any(|l| l.starts_with(component) && l.contains("installed")))
.find_map(|line| {
let available = line.starts_with(component);
let installed = line.contains("installed");
match available {
true => Some(installed),
false => None,
}
})
.map(|installed| match installed {
true => Component::Installed(component),
false => Component::Available(component),
})
.unwrap_or_else(|| Component::NotAvailable(component)))
}

pub fn component_is_installed(
component: &str,
toolchain: &str,
msg_info: MessageInfo,
) -> Result<bool> {
Ok(check_component(component, toolchain, msg_info)?.is_installed())
}

fn rustc_channel(version: &Version) -> Result<Channel> {
Expand Down

0 comments on commit 10b0eb1

Please sign in to comment.