Skip to content

Commit

Permalink
Implement thorough check and test in xtask
Browse files Browse the repository at this point in the history
`cargo xtask check` depends on having installed `<arch>-unknown-linux-gnu` for each supported arch via `rustup`, otherwise the relevant check is not run.
Also changes the riscv target from riscvimac to riscvgc so that we have better toolchain support.

Signed-off-by: Graham MacDonald <[email protected]>
  • Loading branch information
gmacd committed Nov 22, 2023
1 parent 64c6ae6 commit 5accf07
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 74 deletions.
70 changes: 70 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion riscv64/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cargo-features = ["per-package-target"]
name = "riscv64"
version = "0.1.0"
edition = "2021"
default-target = "riscv64imac-unknown-none-elf"
default-target = "riscv64gc-unknown-none-elf"

[dependencies]
port = { path = "../port" }
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ channel = "nightly-2023-06-05"
components = [ "rustfmt", "rust-src", "clippy", "llvm-tools" ]
targets = [
"aarch64-unknown-none",
"riscv64imac-unknown-none-elf",
"riscv64gc-unknown-none-elf",
"x86_64-unknown-none"
]
1 change: 1 addition & 0 deletions xtask/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ edition = "2021"

[dependencies]
clap = { version = "4.2.4", features = ["derive"] }
rustup-configurator = "0.1.1"
serde = { version = "1.0.160", features = ["derive"] }
toml = "0.8.0"
207 changes: 135 additions & 72 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::config::{generate_args, read_config, Configuration};
use rustup_configurator::Triple;
use std::{
env, fmt,
path::{Path, PathBuf},
process::{self, Command},
};

mod config;
use crate::config::{generate_args, read_config, Configuration};

type DynError = Box<dyn std::error::Error>;
type Result<T> = std::result::Result<T, DynError>;
Expand Down Expand Up @@ -73,7 +74,9 @@ impl BuildParams {
config_file
));

let json_output = matches.try_contains_id("json").unwrap_or(false);
// This is a very awkward way to check a boolean which may not exist...
let json_output = matches.try_contains_id("json").unwrap_or(false)
&& matches.value_source("json") != Some(clap::parser::ValueSource::DefaultValue);

Self { arch: *arch, profile, verbose, wait_for_gdb, dump_dtb, config, json_output }
}
Expand Down Expand Up @@ -108,6 +111,42 @@ impl BuildParams {
}
}

struct RustupState {
installed_targets: Vec<Triple>,
curr_toolchain: String,
}

impl RustupState {
/// Runs rustup command to get a list of all installed toolchains.
/// Also caches the current toolchain.
fn new() -> Self {
Self {
installed_targets: rustup_configurator::installed().unwrap(),
curr_toolchain: env::var("RUSTUP_TOOLCHAIN").unwrap(),
}
}

/// For the given arch, return a compatible toolchain triple that is
/// installed and can be used by cargo check. It will prefer the default
/// toolchain if it's a match, otherwise it will look for the
/// <arch-unknown-linux-gnu> toolchain.
fn std_supported_target(&self, arch: &str) -> Option<&Triple> {
let arch = Self::target_arch(arch);
self.installed_targets.iter().filter(|&t| t.architecture.to_string() == arch).find(|&t| {
self.curr_toolchain.ends_with(&t.to_string())
|| t.to_string() == arch.to_owned() + "-unknown-linux-gnu"
})
}

/// Return the arch in a form compatible with the supported targets and toolchains
fn target_arch(arch: &str) -> &str {
match arch {
"riscv64" => "riscv64gc",
_ => arch,
}
}
}

fn main() {
let matches = clap::Command::new("xtask")
.version("0.1.0")
Expand Down Expand Up @@ -172,12 +211,10 @@ fn main() {
clap::arg!(--verbose "Print commands"),
]),
)
.subcommand(
clap::Command::new("check")
.about("Runs check")
.args(&[clap::arg!(--json "Output messages as json")])
.args(&[clap::arg!(--verbose "Print commands")]),
)
.subcommand(clap::Command::new("check").about("Runs check").args(&[
clap::arg!(--json "Output messages as json"),
clap::arg!(--verbose "Print commands"),
]))
.subcommand(
clap::Command::new("qemu").about("Run r9 under QEMU").args(&[
clap::arg!(--release "Build a release version").conflicts_with("debug"),
Expand Down Expand Up @@ -407,19 +444,47 @@ fn dist(build_params: &BuildParams) -> Result<()> {
Ok(())
}

/// Run tests for the current host toolchain.
fn test(build_params: &BuildParams) -> Result<()> {
let mut cmd = Command::new(cargo());
cmd.current_dir(workspace());
cmd.arg("test");
cmd.arg("--workspace");
cmd.arg("--target").arg("x86_64-unknown-linux-gnu");
build_params.add_build_arg(&mut cmd);
if build_params.verbose {
println!("Executing {cmd:?}");
let mut all_cmd_args = Vec::new();

all_cmd_args.push(vec![
"test".to_string(),
"--package".to_string(),
"port".to_string(),
"--lib".to_string(),
]);

let rustup_state = RustupState::new();

let arch = std::env::consts::ARCH;
if let Some(target) = rustup_state.std_supported_target(arch) {
all_cmd_args.push(vec![
"test".to_string(),
"--package".to_string(),
arch.to_string(),
"--bins".to_string(),
"--target".to_string(),
target.to_string(),
]);
}
let status = annotated_status(&mut cmd)?;
if !status.success() {
return Err("test failed".into());

for cmd_args in all_cmd_args {
let mut cmd = Command::new(cargo());
cmd.current_dir(workspace());

cmd.args(cmd_args);
if build_params.json_output {
cmd.arg("--message-format=json").arg("--quiet");
}

if build_params.verbose {
println!("Executing {cmd:?}");
}
let status = annotated_status(&mut cmd)?;
if !status.success() {
return Err("check failed".into());
}
}
Ok(())
}
Expand All @@ -446,71 +511,69 @@ fn clippy(build_params: &BuildParams) -> Result<()> {
Ok(())
}

/// Run check for all packages for all relevant toolchains.
/// This assumes that the <arch>-unknown-linux-gnu toolchain has been installed
/// for any arch we care about.
fn check(build_params: &BuildParams) -> Result<()> {
let all_check_args = vec![
vec!["check", "--package", "aarch64", "--bins"],
vec!["check", "--package", "x86_64", "--bins"],
vec!["check", "--package", "riscv64", "--bins"],
vec!["check", "--package", "port", "--lib"],
vec![
"check",
"--package",
"aarch64",
"--tests",
"--benches",
"--target",
"aarch64-unknown-linux-gnu",
],
vec![
"check",
"--package",
"x86_64",
"--tests",
"--benches",
"--target",
"x86_64-unknown-linux-gnu",
],
// To run check for bins and lib we use the default toolchain, which has
// been set to the OS-independent arch toolchain in each Cargo.toml file.
// The same applies to tests and benches for non-arch-specific lib packages.
let bins_lib_package_cmd_args = vec![
vec![
"check",
"--package",
"riscv64",
"--tests",
"--benches",
"--target",
"riscv64gc-unknown-linux-gnu",
"check".to_string(),
"--package".to_string(),
"aarch64".to_string(),
"--bins".to_string(),
],
vec![
"check",
"--package",
"port",
"--tests",
"--benches",
"--target",
"aarch64-unknown-linux-gnu",
"check".to_string(),
"--package".to_string(),
"riscv64".to_string(),
"--bins".to_string(),
],
vec![
"check",
"--package",
"port",
"--tests",
"--benches",
"--target",
"x86_64-unknown-linux-gnu",
"check".to_string(),
"--package".to_string(),
"x86_64".to_string(),
"--bins".to_string(),
],
vec![
"check",
"--package",
"port",
"--tests",
"--benches",
"--target",
"riscv64gc-unknown-linux-gnu",
"check".to_string(),
"--package".to_string(),
"port".to_string(),
"--lib".to_string(),
"--tests".to_string(),
"--benches".to_string(),
],
];

for check_args in all_check_args {
let rustup_state = RustupState::new();

// However, running check for tests and benches in arch packages requires
// that we use a toolchain with `std`, so we need an OS-specific toolchain.
// If the arch matches that of the current toolchain, then that will be used
// for check. Otherwise we'll always default to <arch>-unknown-linux-gnu.
let mut benches_tests_package_cmd_args = Vec::new();

for arch in ["aarch64", "riscv64", "x86_64"] {
let Some(target) = rustup_state.std_supported_target(arch) else {
continue;
};

benches_tests_package_cmd_args.push(vec![
"check".to_string(),
"--package".to_string(),
arch.to_string(),
"--tests".to_string(),
"--benches".to_string(),
"--target".to_string(),
target.to_string(),
]);
}

for cmd_args in [bins_lib_package_cmd_args, benches_tests_package_cmd_args].concat() {
let mut cmd = Command::new(cargo());
cmd.args(check_args);
cmd.args(cmd_args);
if build_params.json_output {
cmd.arg("--message-format=json").arg("--quiet");
}
Expand Down

0 comments on commit 5accf07

Please sign in to comment.