Skip to content
Snippets Groups Projects
Commit eeb224f3 authored by Per Lindgren's avatar Per Lindgren
Browse files

move to clap 4, wip2

parent f11cebd5
No related branches found
No related tags found
No related merge requests found
......@@ -9,27 +9,39 @@ pub struct Cli {
command: String,
/// Binary to build
#[arg(long, group = "binary")]
bin: Option<String>,
pub bin: Option<String>,
/// Example to build
#[arg(long, group = "binary")]
example: Option<String>,
pub example: Option<String>,
/// Arguments to rustc as a string (e.g., "--release, --target", etc)
#[arg(long, allow_hyphen_values = true)]
rustc: Option<String>,
/// Build artifacts in release mode, with optimizations
#[arg(long)]
pub release: bool,
/// Enable features, e.g, --features "foo bar"
#[arg(long)]
pub features: Option<String>,
/// Enable all-features
#[arg(long)]
pub all_features: bool,
/// Verbose output from rustc
/// Verbose output
#[arg(long)]
verbose: bool,
pub verbose: bool,
/// Additional arguments to rustc as a string (e.g., "--target", etc)
#[arg(long, allow_hyphen_values = true)]
pub rustc: Option<String>,
/// Klee invocation
#[arg(long, short)]
klee: bool,
pub klee: bool,
/// GDB Replay
#[arg(long, short)]
replay: bool,
pub replay: bool,
// #[command(subcommand)]
// binary: Option<Commands>,
}
......@@ -42,27 +54,57 @@ fn cli_verify() {
#[test]
fn cli_parse_simple() {
let args = Cli::try_parse_from(&["test"]).unwrap();
let args = Cli::try_parse_from(&["test", "klee"]).unwrap();
assert_eq!(args.bin, None);
assert_eq!(args.all_features, false);
}
#[test]
fn cli_parse_bin() {
let args = Cli::try_parse_from(&["test", "klee", "--bin", "a"]).unwrap();
let args = Cli::try_parse_from(&["test", "klee", "--bin", "foo"]).unwrap();
println!("args {:?}", args);
assert_eq!(args.bin, Some("a".to_owned()));
assert_eq!(&args.bin.unwrap(), "foo");
}
#[test]
fn cli_parse_example() {
let args = Cli::try_parse_from(&["test", "klee", "--example", "b"]).unwrap();
let args = Cli::try_parse_from(&["test", "klee", "--example", "bar"]).unwrap();
println!("args {:?}", args);
assert_eq!(args.example, Some("b".to_owned()));
assert_eq!(&args.example.unwrap(), "bar");
}
#[test]
fn cli_parse_bin_example() {
let args = Cli::try_parse_from(&["test", "klee", "--bin", "a", "--example", "b"]);
let args = Cli::try_parse_from(&["test", "klee", "--bin", "foo", "--example", "bar"]);
println!("args {:?}", args);
assert_eq!(args.is_err(), true);
}
#[test]
fn cli_parse_bin_release() {
let args = Cli::try_parse_from(&["test", "klee", "--release"]).unwrap();
println!("args {:?}", args);
assert_eq!(args.release, true);
}
#[test]
fn cli_parse_bin_features() {
let args = Cli::try_parse_from(&["test", "klee", "--features", "foo bar"]).unwrap();
println!("args {:?}", args);
assert_eq!(args.features, Some("foo bar".to_owned()));
}
#[test]
fn cli_parse_bin_all_features() {
let args = Cli::try_parse_from(&["test", "klee", "--all-features"]).unwrap();
println!("args {:?}", args);
assert_eq!(args.all_features, true);
}
#[test]
fn cli_parse_bin_rustc() {
let args = Cli::try_parse_from(&["test", "klee", "--rustc", "--target=wasm32-unknown-unknown"])
.unwrap();
println!("args {:?}", args);
assert_eq!(&args.rustc.unwrap(), "--target=wasm32-unknown-unknown");
}
......@@ -6,14 +6,14 @@ use clap::Parser;
// extern crate libc;
// use std::{
// env, fs,
// path::PathBuf,
// process::{self, Command},
// time::SystemTime,
// };
use std::{
env, fs,
path::PathBuf,
process::{self, Command},
time::SystemTime,
};
// use cargo_project::{Artifact, Profile, Project};
use cargo_project::{Artifact, Profile, Project};
// #[derive(Debug, Parser)]
// #[command(author, version, about, long_about = None)]
......@@ -40,26 +40,105 @@ use clap::Parser;
// }
fn main() -> Result<(), Error> {
let args = Cli::parse();
let args = Cli::try_parse()?;
let cwd = env::current_dir()?;
let meta = rustc_version::version_meta()?;
let host = meta.host;
let project = Project::query(cwd)?;
println!("{:?}", args);
Ok(())
// we rely on `clap` for either `example` or `bin`
let file = if let Some(ref example) = args.example {
example
} else if let Some(ref bin) = args.bin {
bin
} else {
// if neither --bin nor --example is provided we
// use the Cargo project name
project.name()
};
println!("file {}", file);
// turn `cargo klee --example foo` into `cargo rustc --example foo -- (..)`
let mut cargo = Command::new("cargo");
cargo
// compile using rustc
.arg("rustc");
// verbose output for debugging purposes
if args.verbose {
cargo.arg("-v");
}
// fn main() -> Result<(), Box<dyn std::error::Error>> {
// let args = Cli::parse();
// println!("args {:?}", args);
// Ok(())
// }
// fn main() -> Result<(), failure::Error> {
// match run() {
// Ok(ec) => process::exit(ec),
// Err(e) => {
// eprintln!("error: {}", e);
// process::exit(1)
// }
// }
// }
// set features, always including `klee-analysis`
if args.all_features {
cargo.arg("--all-features");
} else {
if let Some(features) = args.features {
let mut vec: Vec<&str> = features.split(" ").collect();
vec.push("klee-analysis");
cargo.args(&["--features", &vec.join(" ")]);
} else {
cargo.args(&["--features", "klee-analysis"]);
}
}
if args.release {
cargo.arg("--release");
}
// propagate additional arguments to rustc, e.g. --target=wasm32-unknown-unknown
// TODO! this is not tested
if let Some(rustc) = args.rustc {
let vec: Vec<&str> = rustc.split(" ").collect();
for v in vec {
cargo.arg(v);
}
}
// select (single) application to compile
if args.example.is_some() {
cargo.args(&["--example", &file]);
} else {
// file is either the explicitly stated binary or the crate name
cargo.args(&["--bin", &file]);
}
// prepare for klee build
cargo
// enable shell coloring of result
.arg("--color=always")
.arg("--")
// ignore linking
.args(&["-C", "linker=true"])
// force LTO, to get a single oject file
.args(&["-C", "lto"])
// output the LLVM-IR (.ll file) for KLEE analysis
.arg("--emit=llvm-ir")
// force panic=abort in all crates, override .cargo settings
.env("RUSTFLAGS", "-C panic=abort");
// TODO, force `incremental=false`, `codegen-units=1`?
println!("cargo {:?}", cargo);
if args.verbose {
eprintln!("\n{:?}\n", cargo);
}
// execute the command and unwrap the result into status
let status = cargo.status()?;
if !status.success() {
// TODO! correctly handle exit status
panic!("{:?}", status);
// return Err(status.code().unwrap_or(1).into());
}
Ok(())
}
// fn run() -> Result<i32, failure::Error> {
// let matches = App::new("cargo-klee")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment