xtask: add cargo xtask command

This command can be used to build a full image.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2020-08-17 19:42:39 +08:00
parent 82c9915ad6
commit acbcb0cb12
3 changed files with 148 additions and 0 deletions

2
.cargo/config Normal file
View file

@ -0,0 +1,2 @@
[alias]
xtask = "run --package xtask --"

9
xtask/Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "xtask"
version = "0.1.0"
authors = ["Sean Cross <sean@xobs.io>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

137
xtask/src/main.rs Normal file
View file

@ -0,0 +1,137 @@
use std::{
env, fs,
path::{Path, PathBuf},
process::Command,
};
type DynError = Box<dyn std::error::Error>;
const TARGET: &str = "riscv32imac-unknown-none-elf";
#[derive(Debug)]
enum BuildError {
PathConversionError,
}
impl std::fmt::Display for BuildError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
BuildError::PathConversionError => write!(f, "could not convert path to UTF-8"),
}
}
}
impl std::error::Error for BuildError {}
fn main() {
if let Err(e) = try_main() {
eprintln!("{}", e);
std::process::exit(-1);
}
}
fn try_main() -> Result<(), DynError> {
let task = env::args().nth(1);
match task.as_deref() {
Some("image") => image()?,
_ => print_help(),
}
Ok(())
}
fn print_help() {
eprintln!(
"Tasks:
renode-image builds a test image for renode
"
)
}
fn image() -> Result<(), DynError> {
let debug = false;
let _ = fs::remove_dir_all(&dist_dir());
fs::create_dir_all(&dist_dir())?;
let kernel = build_kernel(debug)?;
let mut init = vec![];
for pkg in &["shell", "log-server", "graphics-server"] {
init.push(build(pkg, debug, None)?);
}
create_image(&kernel, &init, debug)?;
Ok(())
}
fn build_kernel(debug: bool) -> Result<PathBuf, DynError> {
build("kernel", debug, Some("kernel".into()))
}
fn build(project: &str, debug: bool, directory: Option<PathBuf>) -> Result<PathBuf, DynError> {
let stream = if debug { "debug" } else { "release" };
let mut args = vec!["build", "--target", TARGET, "--package", project];
if !debug {
args.push("--release");
}
let mut dir = project_root();
if let Some(subdir) = directory {
dir.push(subdir);
}
let status = Command::new(cargo())
.current_dir(dir)
.args(&args)
.status()?;
if !status.success() {
return Err("cargo build failed".into());
}
Ok(project_root().join(&format!("target/{}/{}/{}", TARGET, stream, project)))
}
fn create_image(kernel: &Path, init: &[PathBuf], debug: bool) -> Result<PathBuf, DynError> {
let stream = if debug { "debug" } else { "release" };
let mut args = vec!["run", "--package", "tools", "--bin", "create-image", "--"];
let output_file = format!("target/{}/{}/args.bin", TARGET, stream);
args.push(&output_file);
args.push("--kernel");
args.push(kernel.to_str().ok_or(BuildError::PathConversionError)?);
for i in init {
args.push("--init");
args.push(i.to_str().ok_or(BuildError::PathConversionError)?);
}
args.push("--csv");
args.push("emulation/csr.csv");
let status = Command::new(cargo())
.current_dir(project_root())
.args(&args)
.status()?;
if !status.success() {
return Err("cargo build failed".into());
}
Ok(project_root().join(&format!("target/{}/{}/args.bin", TARGET, stream)))
}
fn cargo() -> String {
env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())
}
fn project_root() -> PathBuf {
Path::new(&env!("CARGO_MANIFEST_DIR"))
.ancestors()
.nth(1)
.unwrap()
.to_path_buf()
}
fn dist_dir() -> PathBuf {
project_root().join("target/dist")
}