From 750c9ed9c1c022deb4c16630d7bff6ca69ae3587 Mon Sep 17 00:00:00 2001 From: zjp Date: Fri, 25 Oct 2024 22:33:54 +0800 Subject: [PATCH 01/30] feat: no longer `cargo clean` to reduce checking time --- rap/src/bin/cargo-rap.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/rap/src/bin/cargo-rap.rs b/rap/src/bin/cargo-rap.rs index 57f0153..3c06e28 100644 --- a/rap/src/bin/cargo-rap.rs +++ b/rap/src/bin/cargo-rap.rs @@ -149,13 +149,6 @@ fn run_cmd(mut cmd: Command) { } } -fn cleanup() { - let mut cmd = Command::new("cargo"); - cmd.arg("clean"); - run_cmd(cmd); - rap_info!("Execute cargo clean."); -} - fn phase_cargo_rap() { rap_info!("Start cargo-rap"); let mut args = env::args().skip(2); // here we skip two tokens: cargo rap @@ -174,7 +167,6 @@ fn phase_cargo_rap() { } _ => {} } - cleanup(); // clean up the directory before building. let cmd = MetadataCommand::new(); rap_debug!("Please run `cargo metadata` if this step takes too long"); From 764cf9c05cdef3ebc7d7f2c7983828dc7ced8375 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 07:56:43 +0800 Subject: [PATCH 02/30] doc: add an alternative way to interact with toolchain --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 2eb3915..42ba17e 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,13 @@ Navigate to your Rust project folder containing a `Cargo.toml` file. Then run `c cargo +nightly-2024-06-30 rap # ... rest of options of cargo-rap ``` +Alternatively, you can switch to the pinned toolchain ahead of time: + +```rust +rustup default nightly-2024-06-30 +cargo rap # ... rest of options of cargo-rap +``` + Check out supported options with `-help`: ```shell From ae2571fad08b9d84f4700c2db5c4158c81f908fe Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 08:03:02 +0800 Subject: [PATCH 03/30] doc: guide on multiple detections, i.e. `cargo rap -F -M` --- rap/src/bin/cargo-rap.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rap/src/bin/cargo-rap.rs b/rap/src/bin/cargo-rap.rs index 3c06e28..ff63eb8 100644 --- a/rap/src/bin/cargo-rap.rs +++ b/rap/src/bin/cargo-rap.rs @@ -36,6 +36,10 @@ General command: Debugging options: -mir print the MIR of each function + +NOTE: multiple detections can be processed in single run by +appending the options to the arguments. Like `cargo rap -F -M` +will perform two kinds of detection in a row. "#; const RAP_VERSION: &str = r#" From 0cdb489de368a63430affbd341e975a67d4433ec Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 09:03:06 +0800 Subject: [PATCH 04/30] refactor: ArgFlagValueIter => Arguments Defining an iterator is a overkill for get_arg_flag_value. --- rap/src/bin/cargo-rap.rs | 49 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/rap/src/bin/cargo-rap.rs b/rap/src/bin/cargo-rap.rs index ff63eb8..a0dc13a 100644 --- a/rap/src/bin/cargo-rap.rs +++ b/rap/src/bin/cargo-rap.rs @@ -8,9 +8,9 @@ use rap::{rap_debug, rap_error, rap_info}; use rustc_version::VersionMeta; use std::env; use std::fmt::{Display, Formatter}; -use std::iter::TakeWhile; use std::path::{Path, PathBuf}; use std::process::{self, Command}; +use std::sync::LazyLock; use std::time::Duration; use wait_timeout::ChildExt; @@ -48,46 +48,45 @@ released at 2024-07-23 developped by artisan-lab @ Fudan university "#; -/// Yields all values of command line flag `name`. -struct ArgFlagValueIter<'a> { - args: TakeWhile bool>, - name: &'a str, +struct Arguments { + /// a collection of `std::env::args()` + args: Vec, } -impl<'a> ArgFlagValueIter<'a> { - fn new(name: &'a str) -> Self { - Self { - args: env::args().take_while(|val| val != "--"), - name, - } - } -} - -impl Iterator for ArgFlagValueIter<'_> { - type Item = String; +impl Arguments { + // Get value from `name=val` or `name val`. + fn get_arg_flag_value(&self, name: &str) -> Option<&str> { + let mut args = self.args.iter().take_while(|val| *val != "--"); - fn next(&mut self) -> Option { - loop { - let arg = self.args.next()?; - if !arg.starts_with(self.name) { + while let Some(arg) = args.next() { + if !arg.starts_with(name) { continue; } // Strip leading `name`. - let suffix = &arg[self.name.len()..]; + let suffix = &arg[name.len()..]; if suffix.is_empty() { // This argument is exactly `name`; the next one is the value. - return self.args.next(); + return args.next().map(|x| x.as_str()); } else if suffix.starts_with('=') { // This argument is `name=value`; get the value. // Strip leading `=`. - return Some(suffix[1..].to_owned()); + return Some(&suffix[1..]); } } + + None + } + + fn new() -> Self { + Arguments { + args: env::args().collect(), + } } } -fn get_arg_flag_value(name: &str) -> Option { - ArgFlagValueIter::new(name).next() +fn get_arg_flag_value(name: &str) -> Option<&'static str> { + static ARGS: LazyLock = LazyLock::new(Arguments::new); + ARGS.get_arg_flag_value(name) } fn find_rap() -> PathBuf { From 6a936b864ec616fc2d3b9e00b741c5f888ab4d97 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 10:27:10 +0800 Subject: [PATCH 05/30] feat: forwarding cargo args diretly --- rap/src/bin/cargo-rap.rs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/rap/src/bin/cargo-rap.rs b/rap/src/bin/cargo-rap.rs index a0dc13a..17e3c38 100644 --- a/rap/src/bin/cargo-rap.rs +++ b/rap/src/bin/cargo-rap.rs @@ -82,13 +82,30 @@ impl Arguments { args: env::args().collect(), } } + + /// `cargo rap [rap options] -- [cargo check options]` + /// + /// Options before the first `--` are arguments forwarding to rap. + /// Stuff all after the first `--` are arguments forwarding to cargo check. + fn rap_and_cargo_args(&self) -> [Vec<&str>; 2] { + dbg!(&self.args); + let mut args = self.args.iter().map(|arg| arg.as_str()).skip(2); + let rap_args = args.by_ref().take_while(|arg| *arg != "--").collect(); + let cargo_args = args.collect(); + [rap_args, cargo_args] + } } +static ARGS: LazyLock = LazyLock::new(Arguments::new); + fn get_arg_flag_value(name: &str) -> Option<&'static str> { - static ARGS: LazyLock = LazyLock::new(Arguments::new); ARGS.get_arg_flag_value(name) } +fn rap_and_cargo_args() -> [Vec<&'static str>; 2] { + ARGS.rap_and_cargo_args() +} + fn find_rap() -> PathBuf { let mut path = env::current_exe().expect("Current executable path invalid."); path.set_file_name("rap"); @@ -179,6 +196,9 @@ fn phase_cargo_rap() { Err(e) => rap_error_and_exit(format!("Cannot obtain cargo metadata: {}.", e)), }; + let [rap_args, cargo_args] = rap_and_cargo_args(); + rap_debug!("rap_args={rap_args:?}\tcargo_args={cargo_args:?}"); + let targets = find_targets(&mut metadata); for target in targets { /*Here we prepare the cargo command as cargo check, which is similar to build, but much faster*/ @@ -192,21 +212,15 @@ fn phase_cargo_rap() { } /* set the target as a filter for phase_rustc_rap */ - let host = version_info().host; - if get_arg_flag_value("--target").is_none() { - cmd.arg("--target"); - cmd.arg(&host); - } + // cmd.args(&cargo_args); // Serialize the remaining args into a special environment variable. // This will be read by `phase_rustc_rap` when we go to invoke // our actual target crate (the binary or the test we are running). - let args = env::args().skip(2); - let args_vec: Vec = args.collect(); cmd.env( "RAP_ARGS", - serde_json::to_string(&args_vec).expect("Failed to serialize args."), + serde_json::to_string(&rap_args).expect("Failed to serialize args."), ); // Invoke actual cargo for the job, but with different flags. From 52688b8db5d5e06045307d3b35f779b8c4920e6a Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 10:27:56 +0800 Subject: [PATCH 06/30] chore: clean up dead code is_target_crate fn is outdated, because --target may not be passed by user; but we don't need it to work: rustc can handle without it. --- rap/src/bin/cargo-rap.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/rap/src/bin/cargo-rap.rs b/rap/src/bin/cargo-rap.rs index 17e3c38..fad3fca 100644 --- a/rap/src/bin/cargo-rap.rs +++ b/rap/src/bin/cargo-rap.rs @@ -5,7 +5,6 @@ use cargo_metadata::{Metadata, MetadataCommand}; use rap::utils::log::{init_log, rap_error_and_exit}; use rap::{rap_debug, rap_error, rap_info}; -use rustc_version::VersionMeta; use std::env; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; @@ -112,11 +111,6 @@ fn find_rap() -> PathBuf { path } -fn version_info() -> VersionMeta { - let rap = Command::new(find_rap()); - VersionMeta::for_command(rap).expect("Failed to determine underlying rustc version of rap.") -} - /* The function finds a package under the current directory. */ @@ -255,9 +249,6 @@ fn phase_cargo_rap() { fn phase_rustc_wrapper() { rap_debug!("Launch cargo-rap again triggered by cargo check."); - fn is_target_crate() -> bool { - get_arg_flag_value("--target").is_some() - } // Determines if we are being invoked to build crate for local crate. // Cargo passes the file name as a relative address when building the local crate, @@ -315,7 +306,7 @@ fn phase_rustc_wrapper() { any_arg_flag("--crate--type", TargetKind::is_lib_str) } - let is_direct = is_current_compile_crate() && is_target_crate(); + let is_direct = is_current_compile_crate(); if is_direct { let mut cmd = Command::new(find_rap()); cmd.args(env::args().skip(2)); From 5404f0be34d02fa48230c828d042c5ab75d608d8 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 10:29:35 +0800 Subject: [PATCH 07/30] chore: remove rustc_version dependency --- rap/Cargo.lock | 10 ---------- rap/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/rap/Cargo.lock b/rap/Cargo.lock index 72e1ab2..f60f52b 100644 --- a/rap/Cargo.lock +++ b/rap/Cargo.lock @@ -409,7 +409,6 @@ dependencies = [ "fern", "log", "rustc-demangle", - "rustc_version", "serde_json", "snafu", "wait-timeout", @@ -457,15 +456,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "ryu" version = "1.0.15" diff --git a/rap/Cargo.toml b/rap/Cargo.toml index 57dd154..939d359 100644 --- a/rap/Cargo.toml +++ b/rap/Cargo.toml @@ -18,7 +18,7 @@ name = "rap" [dependencies] #lazy_static = "1.4" -rustc_version = "0.4.0" +# rustc_version = "0.4.0" cargo_metadata = "0.14.1" snafu = "0.7.0" chrono = "0.4.19" From bf8c689c04aee47605c42380acd13cdcb3364f6b Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 10:39:16 +0800 Subject: [PATCH 08/30] fix: forget to forward cargo args... --- rap/src/bin/cargo-rap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rap/src/bin/cargo-rap.rs b/rap/src/bin/cargo-rap.rs index fad3fca..9f65b20 100644 --- a/rap/src/bin/cargo-rap.rs +++ b/rap/src/bin/cargo-rap.rs @@ -206,7 +206,7 @@ fn phase_cargo_rap() { } /* set the target as a filter for phase_rustc_rap */ - // cmd.args(&cargo_args); + cmd.args(&cargo_args); // Serialize the remaining args into a special environment variable. // This will be read by `phase_rustc_rap` when we go to invoke From 04ff9183d470c894883bd2689d9c1cded62a901c Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 10:43:23 +0800 Subject: [PATCH 09/30] doc(RAP_HELP): cargo rap [rap options] -- [cargo check options] e.g. cargo rap -F -M -- --target riscv64gc-unknown-none-elf --- rap/src/bin/cargo-rap.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rap/src/bin/cargo-rap.rs b/rap/src/bin/cargo-rap.rs index 9f65b20..e94ae26 100644 --- a/rap/src/bin/cargo-rap.rs +++ b/rap/src/bin/cargo-rap.rs @@ -15,7 +15,9 @@ use wait_timeout::ChildExt; const RAP_HELP: &str = r#" Usage: - cargo rap [options...] + cargo rap [rap options] -- [cargo check options] + +Rap Options: Use-After-Free/double free detection. -F or -uaf command: "cargo rap -uaf" @@ -39,6 +41,9 @@ Debugging options: NOTE: multiple detections can be processed in single run by appending the options to the arguments. Like `cargo rap -F -M` will perform two kinds of detection in a row. + +e.g. detect use-after-free and memory leak for a riscv target: + cargo rap -F -M -- --target riscv64gc-unknown-none-elf "#; const RAP_VERSION: &str = r#" From 85fe0ad05de1ee93f1f01046822612f96013596d Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 10:47:36 +0800 Subject: [PATCH 10/30] doc(README): add cargo rap [rap options] -- [cargo check options] --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 42ba17e..0310346 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,19 @@ Navigate to your Rust project folder containing a `Cargo.toml` file. Then run `c [toolchain override shorthand syntax]: https://rust-lang.github.io/rustup/overrides.html#toolchain-override-shorthand ```shell -cargo +nightly-2024-06-30 rap # ... rest of options of cargo-rap +cargo rap [rap options] -- [cargo check options] + +where `-- [cargo check options]` is optional, and if specified, they are passed to cargo check. ``` Alternatively, you can switch to the pinned toolchain ahead of time: ```rust +# set up rap's toolchain as default rustup default nightly-2024-06-30 -cargo rap # ... rest of options of cargo-rap + +# run cargo rap without +toolchain syntax any more +cargo rap [rap options] -- [cargo check options] ``` Check out supported options with `-help`: From 7411d0352e87bbbc7d120261b171a9acedfc7d10 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 10:50:56 +0800 Subject: [PATCH 11/30] chore: rap/src/bin/cargo-rap.rs -> rap/src/bin/cargo-rap/main.rs --- rap/src/bin/{cargo-rap.rs => cargo-rap/main.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rap/src/bin/{cargo-rap.rs => cargo-rap/main.rs} (100%) diff --git a/rap/src/bin/cargo-rap.rs b/rap/src/bin/cargo-rap/main.rs similarity index 100% rename from rap/src/bin/cargo-rap.rs rename to rap/src/bin/cargo-rap/main.rs From 0e1cf84042a7711f9d13f8029d4603026d5120ce Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 10:57:06 +0800 Subject: [PATCH 12/30] chore: move RAP_HELP & RAP_VERSION to help.rs --- rap/src/bin/cargo-rap/help.rs | 38 +++++++++++++++++++++++++++++++ rap/src/bin/cargo-rap/main.rs | 43 +++-------------------------------- 2 files changed, 41 insertions(+), 40 deletions(-) create mode 100644 rap/src/bin/cargo-rap/help.rs diff --git a/rap/src/bin/cargo-rap/help.rs b/rap/src/bin/cargo-rap/help.rs new file mode 100644 index 0000000..1979636 --- /dev/null +++ b/rap/src/bin/cargo-rap/help.rs @@ -0,0 +1,38 @@ +pub const RAP_HELP: &str = r#" +Usage: + cargo rap [rap options] -- [cargo check options] + +Rap Options: + +Use-After-Free/double free detection. + -F or -uaf command: "cargo rap -uaf" + +Memory leakage detection. + -M or -mleak command: "cargo rap -mleak" + +Unsafe code tracing + -UI or -uig generate unsafe code isolation graphs + +Dataflow tracing + -dataflow generate dataflow graphs + +General command: + -H or -help: show help information + -V or -version: show the version of RAP + +Debugging options: + -mir print the MIR of each function + +NOTE: multiple detections can be processed in single run by +appending the options to the arguments. Like `cargo rap -F -M` +will perform two kinds of detection in a row. + +e.g. detect use-after-free and memory leak for a riscv target: + cargo rap -F -M -- --target riscv64gc-unknown-none-elf +"#; + +pub const RAP_VERSION: &str = r#" +rap version 0.1 +released at 2024-07-23 +developped by artisan-lab @ Fudan university +"#; diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index e94ae26..8ab3261 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -13,44 +13,7 @@ use std::sync::LazyLock; use std::time::Duration; use wait_timeout::ChildExt; -const RAP_HELP: &str = r#" -Usage: - cargo rap [rap options] -- [cargo check options] - -Rap Options: - -Use-After-Free/double free detection. - -F or -uaf command: "cargo rap -uaf" - -Memory leakage detection. - -M or -mleak command: "cargo rap -mleak" - -Unsafe code tracing - -UI or -uig generate unsafe code isolation graphs - -Dataflow tracing - -dataflow generate dataflow graphs - -General command: - -H or -help: show help information - -V or -version: show the version of RAP - -Debugging options: - -mir print the MIR of each function - -NOTE: multiple detections can be processed in single run by -appending the options to the arguments. Like `cargo rap -F -M` -will perform two kinds of detection in a row. - -e.g. detect use-after-free and memory leak for a riscv target: - cargo rap -F -M -- --target riscv64gc-unknown-none-elf -"#; - -const RAP_VERSION: &str = r#" -rap version 0.1 -released at 2024-07-23 -developped by artisan-lab @ Fudan university -"#; +mod help; struct Arguments { /// a collection of `std::env::args()` @@ -177,11 +140,11 @@ fn phase_cargo_rap() { }; match arg.as_str() { "-V" | "-version" => { - rap_info!("{}", RAP_VERSION); + rap_info!("{}", help::RAP_VERSION); return; } "-H" | "-help" | "--help" => { - rap_info!("{}", RAP_HELP); + rap_info!("{}", help::RAP_HELP); return; } _ => {} From d0dcd581cd1ba1f032753a049c13ec304ac9a4ea Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 11:02:42 +0800 Subject: [PATCH 13/30] chore: move Arguments to args.rs --- rap/src/bin/cargo-rap/args.rs | 58 ++++++++++++++++++++++++++++++++ rap/src/bin/cargo-rap/main.rs | 62 ++--------------------------------- 2 files changed, 60 insertions(+), 60 deletions(-) create mode 100644 rap/src/bin/cargo-rap/args.rs diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs new file mode 100644 index 0000000..9870ff9 --- /dev/null +++ b/rap/src/bin/cargo-rap/args.rs @@ -0,0 +1,58 @@ +use std::sync::LazyLock; + +struct Arguments { + /// a collection of `std::env::args()` + args: Vec, +} + +impl Arguments { + // Get value from `name=val` or `name val`. + fn get_arg_flag_value(&self, name: &str) -> Option<&str> { + let mut args = self.args.iter().take_while(|val| *val != "--"); + + while let Some(arg) = args.next() { + if !arg.starts_with(name) { + continue; + } + // Strip leading `name`. + let suffix = &arg[name.len()..]; + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return args.next().map(|x| x.as_str()); + } else if suffix.starts_with('=') { + // This argument is `name=value`; get the value. + // Strip leading `=`. + return Some(&suffix[1..]); + } + } + + None + } + + fn new() -> Self { + Arguments { + args: std::env::args().collect(), + } + } + + /// `cargo rap [rap options] -- [cargo check options]` + /// + /// Options before the first `--` are arguments forwarding to rap. + /// Stuff all after the first `--` are arguments forwarding to cargo check. + fn rap_and_cargo_args(&self) -> [Vec<&str>; 2] { + let mut args = self.args.iter().map(|arg| arg.as_str()).skip(2); + let rap_args = args.by_ref().take_while(|arg| *arg != "--").collect(); + let cargo_args = args.collect(); + [rap_args, cargo_args] + } +} + +static ARGS: LazyLock = LazyLock::new(Arguments::new); + +pub fn get_arg_flag_value(name: &str) -> Option<&'static str> { + ARGS.get_arg_flag_value(name) +} + +pub fn rap_and_cargo_args() -> [Vec<&'static str>; 2] { + ARGS.rap_and_cargo_args() +} diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index 8ab3261..b99de29 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -9,70 +9,12 @@ use std::env; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; use std::process::{self, Command}; -use std::sync::LazyLock; use std::time::Duration; use wait_timeout::ChildExt; +mod args; mod help; -struct Arguments { - /// a collection of `std::env::args()` - args: Vec, -} - -impl Arguments { - // Get value from `name=val` or `name val`. - fn get_arg_flag_value(&self, name: &str) -> Option<&str> { - let mut args = self.args.iter().take_while(|val| *val != "--"); - - while let Some(arg) = args.next() { - if !arg.starts_with(name) { - continue; - } - // Strip leading `name`. - let suffix = &arg[name.len()..]; - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return args.next().map(|x| x.as_str()); - } else if suffix.starts_with('=') { - // This argument is `name=value`; get the value. - // Strip leading `=`. - return Some(&suffix[1..]); - } - } - - None - } - - fn new() -> Self { - Arguments { - args: env::args().collect(), - } - } - - /// `cargo rap [rap options] -- [cargo check options]` - /// - /// Options before the first `--` are arguments forwarding to rap. - /// Stuff all after the first `--` are arguments forwarding to cargo check. - fn rap_and_cargo_args(&self) -> [Vec<&str>; 2] { - dbg!(&self.args); - let mut args = self.args.iter().map(|arg| arg.as_str()).skip(2); - let rap_args = args.by_ref().take_while(|arg| *arg != "--").collect(); - let cargo_args = args.collect(); - [rap_args, cargo_args] - } -} - -static ARGS: LazyLock = LazyLock::new(Arguments::new); - -fn get_arg_flag_value(name: &str) -> Option<&'static str> { - ARGS.get_arg_flag_value(name) -} - -fn rap_and_cargo_args() -> [Vec<&'static str>; 2] { - ARGS.rap_and_cargo_args() -} - fn find_rap() -> PathBuf { let mut path = env::current_exe().expect("Current executable path invalid."); path.set_file_name("rap"); @@ -158,7 +100,7 @@ fn phase_cargo_rap() { Err(e) => rap_error_and_exit(format!("Cannot obtain cargo metadata: {}.", e)), }; - let [rap_args, cargo_args] = rap_and_cargo_args(); + let [rap_args, cargo_args] = args::rap_and_cargo_args(); rap_debug!("rap_args={rap_args:?}\tcargo_args={cargo_args:?}"); let targets = find_targets(&mut metadata); From 9d94b3fdb38e6245b0fcbcc107ee8cc0205fd8c2 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 11:12:18 +0800 Subject: [PATCH 14/30] chore: add rap_args & cargo_args fields in Arguments --- rap/src/bin/cargo-rap/args.rs | 36 ++++++++++++++++++++++------------- rap/src/bin/cargo-rap/main.rs | 4 ++-- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index 9870ff9..47205b3 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -3,6 +3,10 @@ use std::sync::LazyLock; struct Arguments { /// a collection of `std::env::args()` args: Vec, + /// options as first half before -- in args + rap_args: Vec, + /// options as second half after -- in args + cargo_args: Vec, } impl Arguments { @@ -30,21 +34,25 @@ impl Arguments { } fn new() -> Self { + let args: Vec<_> = std::env::args().collect(); + let [rap_args, cargo_args] = new_rap_and_cargo_args(&args); Arguments { - args: std::env::args().collect(), + args, + rap_args, + cargo_args, } } +} - /// `cargo rap [rap options] -- [cargo check options]` - /// - /// Options before the first `--` are arguments forwarding to rap. - /// Stuff all after the first `--` are arguments forwarding to cargo check. - fn rap_and_cargo_args(&self) -> [Vec<&str>; 2] { - let mut args = self.args.iter().map(|arg| arg.as_str()).skip(2); - let rap_args = args.by_ref().take_while(|arg| *arg != "--").collect(); - let cargo_args = args.collect(); - [rap_args, cargo_args] - } +/// `cargo rap [rap options] -- [cargo check options]` +/// +/// Options before the first `--` are arguments forwarding to rap. +/// Stuff all after the first `--` are arguments forwarding to cargo check. +fn new_rap_and_cargo_args(args: &[String]) -> [Vec; 2] { + let mut args = args.iter().skip(2).map(|arg| arg.to_owned()); + let rap_args = args.by_ref().take_while(|arg| *arg != "--").collect(); + let cargo_args = args.collect(); + [rap_args, cargo_args] } static ARGS: LazyLock = LazyLock::new(Arguments::new); @@ -53,6 +61,8 @@ pub fn get_arg_flag_value(name: &str) -> Option<&'static str> { ARGS.get_arg_flag_value(name) } -pub fn rap_and_cargo_args() -> [Vec<&'static str>; 2] { - ARGS.rap_and_cargo_args() +/// Get rap & cargo check options from +/// `cargo rap [rap options] -- [cargo check options]`. +pub fn rap_and_cargo_args() -> [&'static [String]; 2] { + [&ARGS.rap_args, &ARGS.cargo_args] } diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index b99de29..545f5d5 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -116,7 +116,7 @@ fn phase_cargo_rap() { } /* set the target as a filter for phase_rustc_rap */ - cmd.args(&cargo_args); + cmd.args(cargo_args); // Serialize the remaining args into a special environment variable. // This will be read by `phase_rustc_rap` when we go to invoke @@ -124,7 +124,7 @@ fn phase_cargo_rap() { cmd.env( "RAP_ARGS", - serde_json::to_string(&rap_args).expect("Failed to serialize args."), + serde_json::to_string(rap_args).expect("Failed to serialize args."), ); // Invoke actual cargo for the job, but with different flags. From a9d3fd8d0c59bfcad063adb900bdb8f97a119fee Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 11:26:38 +0800 Subject: [PATCH 15/30] chore: move is_current_compile_crate to args.rs also rename rap_args => args_group1, cargo_args => args_group2, due to two phases in cargo-rap: in rustc phase, the field name is incorrect. --- rap/src/bin/cargo-rap/args.rs | 43 +++++++++++++++++++++++------------ rap/src/bin/cargo-rap/main.rs | 17 +------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index 47205b3..1eb4aac 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -1,12 +1,12 @@ -use std::sync::LazyLock; +use std::{path::Path, sync::LazyLock}; struct Arguments { /// a collection of `std::env::args()` args: Vec, /// options as first half before -- in args - rap_args: Vec, + args_group1: Vec, /// options as second half after -- in args - cargo_args: Vec, + args_group2: Vec, } impl Arguments { @@ -35,20 +35,28 @@ impl Arguments { fn new() -> Self { let args: Vec<_> = std::env::args().collect(); - let [rap_args, cargo_args] = new_rap_and_cargo_args(&args); + let [args_group1, args_group2] = split_args_by_double_dash(&args); Arguments { args, - rap_args, - cargo_args, + args_group1, + args_group2, } } + + // In rustc phase: + // Determines if we are being invoked to build crate for local crate. + // Cargo passes the file name as a relative address when building the local crate, + fn is_current_compile_crate(&self) -> bool { + let mut args = self.args.iter().take_while(|s| *s != "--"); + let entry_path = match args.find(|s| s.ends_with(".rs")) { + Some(path) => Path::new(path), + None => return false, + }; + entry_path.is_relative() + } } -/// `cargo rap [rap options] -- [cargo check options]` -/// -/// Options before the first `--` are arguments forwarding to rap. -/// Stuff all after the first `--` are arguments forwarding to cargo check. -fn new_rap_and_cargo_args(args: &[String]) -> [Vec; 2] { +fn split_args_by_double_dash(args: &[String]) -> [Vec; 2] { let mut args = args.iter().skip(2).map(|arg| arg.to_owned()); let rap_args = args.by_ref().take_while(|arg| *arg != "--").collect(); let cargo_args = args.collect(); @@ -61,8 +69,15 @@ pub fn get_arg_flag_value(name: &str) -> Option<&'static str> { ARGS.get_arg_flag_value(name) } -/// Get rap & cargo check options from -/// `cargo rap [rap options] -- [cargo check options]`. +/// `cargo rap [rap options] -- [cargo check options]` +/// +/// Options before the first `--` are arguments forwarding to rap. +/// Stuff all after the first `--` are arguments forwarding to cargo check. pub fn rap_and_cargo_args() -> [&'static [String]; 2] { - [&ARGS.rap_args, &ARGS.cargo_args] + [&ARGS.args_group1, &ARGS.args_group2] +} + +/// If a crate being compiled is local in rustc phase. +pub fn is_current_compile_crate() -> bool { + ARGS.is_current_compile_crate() } diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index 545f5d5..e7c7f35 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -160,21 +160,6 @@ fn phase_cargo_rap() { fn phase_rustc_wrapper() { rap_debug!("Launch cargo-rap again triggered by cargo check."); - // Determines if we are being invoked to build crate for local crate. - // Cargo passes the file name as a relative address when building the local crate, - fn is_current_compile_crate() -> bool { - fn find_arg_with_rs_suffix() -> Option { - let mut args = env::args().take_while(|s| s != "--"); - args.find(|s| s.ends_with(".rs")) - } - let arg_path = match find_arg_with_rs_suffix() { - Some(path) => path, - None => return false, - }; - let entry_path: &Path = arg_path.as_ref(); - entry_path.is_relative() - } - fn is_crate_type_lib() -> bool { fn any_arg_flag(name: &str, mut check: F) -> bool where @@ -216,7 +201,7 @@ fn phase_rustc_wrapper() { any_arg_flag("--crate--type", TargetKind::is_lib_str) } - let is_direct = is_current_compile_crate(); + let is_direct = args::is_current_compile_crate(); if is_direct { let mut cmd = Command::new(find_rap()); cmd.args(env::args().skip(2)); From 1310c895937a318a3f4bf06e6d52f9141cff5758 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 11:34:42 +0800 Subject: [PATCH 16/30] chore: move TargetKind to target_kind.rs --- rap/src/bin/cargo-rap/main.rs | 47 ++-------------------------- rap/src/bin/cargo-rap/target_kind.rs | 44 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 44 deletions(-) create mode 100644 rap/src/bin/cargo-rap/target_kind.rs diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index e7c7f35..41eec28 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -6,7 +6,6 @@ use cargo_metadata::{Metadata, MetadataCommand}; use rap::utils::log::{init_log, rap_error_and_exit}; use rap::{rap_debug, rap_error, rap_info}; use std::env; -use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; use std::process::{self, Command}; use std::time::Duration; @@ -15,6 +14,9 @@ use wait_timeout::ChildExt; mod args; mod help; +mod target_kind; +use target_kind::TargetKind; + fn find_rap() -> PathBuf { let mut path = env::current_exe().expect("Current executable path invalid."); path.set_file_name("rap"); @@ -218,49 +220,6 @@ fn phase_rustc_wrapper() { }; } -#[repr(u8)] -enum TargetKind { - Library, - Bin, - Unspecified, -} - -impl Display for TargetKind { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self { - TargetKind::Library => "lib", - TargetKind::Bin => "bin", - TargetKind::Unspecified => "unspecified", - } - ) - } -} - -impl From<&cargo_metadata::Target> for TargetKind { - fn from(target: &cargo_metadata::Target) -> Self { - if target - .kind - .iter() - .any(|s| s == "lib" || s == "rlib" || s == "staticlib") - { - TargetKind::Library - } else if target.kind.iter().any(|s| s == "bin") { - TargetKind::Bin - } else { - TargetKind::Unspecified - } - } -} - -impl TargetKind { - fn is_lib_str(s: &str) -> bool { - s == "lib" || s == "rlib" || s == "staticlib" - } -} - fn main() { /* This function will be enteredd twice: 1. When we run `cargo rap ...`, cargo dispatches the execution to cargo-rap. diff --git a/rap/src/bin/cargo-rap/target_kind.rs b/rap/src/bin/cargo-rap/target_kind.rs new file mode 100644 index 0000000..7317115 --- /dev/null +++ b/rap/src/bin/cargo-rap/target_kind.rs @@ -0,0 +1,44 @@ +use std::fmt::{Display, Formatter}; + +#[repr(u8)] +pub enum TargetKind { + Library, + Bin, + Unspecified, +} + +impl Display for TargetKind { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + TargetKind::Library => "lib", + TargetKind::Bin => "bin", + TargetKind::Unspecified => "unspecified", + } + ) + } +} + +impl From<&cargo_metadata::Target> for TargetKind { + fn from(target: &cargo_metadata::Target) -> Self { + if target + .kind + .iter() + .any(|s| s == "lib" || s == "rlib" || s == "staticlib") + { + TargetKind::Library + } else if target.kind.iter().any(|s| s == "bin") { + TargetKind::Bin + } else { + TargetKind::Unspecified + } + } +} + +impl TargetKind { + pub fn is_lib_str(s: &str) -> bool { + s == "lib" || s == "rlib" || s == "staticlib" + } +} From b7c3eea5bc33bff8a18d3ebd9bdde3fd7d744024 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 13:03:11 +0800 Subject: [PATCH 17/30] chore: move is_crate_type_lib to args.rs there is a typo in original code: --crate--type will be never matched, so it's needless to call it. In this commit, is_crate_type_lib is refactored with get_arg_flag_value. --- rap/src/bin/cargo-rap/args.rs | 10 +++++-- rap/src/bin/cargo-rap/main.rs | 52 ++++------------------------------- 2 files changed, 14 insertions(+), 48 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index 1eb4aac..5085309 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -12,7 +12,7 @@ struct Arguments { impl Arguments { // Get value from `name=val` or `name val`. fn get_arg_flag_value(&self, name: &str) -> Option<&str> { - let mut args = self.args.iter().take_while(|val| *val != "--"); + let mut args = self.args_group1.iter(); while let Some(arg) = args.next() { if !arg.starts_with(name) { @@ -47,7 +47,7 @@ impl Arguments { // Determines if we are being invoked to build crate for local crate. // Cargo passes the file name as a relative address when building the local crate, fn is_current_compile_crate(&self) -> bool { - let mut args = self.args.iter().take_while(|s| *s != "--"); + let mut args = self.args_group1.iter(); let entry_path = match args.find(|s| s.ends_with(".rs")) { Some(path) => Path::new(path), None => return false, @@ -81,3 +81,9 @@ pub fn rap_and_cargo_args() -> [&'static [String]; 2] { pub fn is_current_compile_crate() -> bool { ARGS.is_current_compile_crate() } + +pub fn is_crate_type_lib() -> bool { + get_arg_flag_value("--crate--type") + .map(crate::TargetKind::is_lib_str) + .unwrap_or(false) +} diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index 41eec28..5ba4349 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -162,47 +162,6 @@ fn phase_cargo_rap() { fn phase_rustc_wrapper() { rap_debug!("Launch cargo-rap again triggered by cargo check."); - fn is_crate_type_lib() -> bool { - fn any_arg_flag(name: &str, mut check: F) -> bool - where - F: FnMut(&str) -> bool, - { - // Stop searching at `--`. - let mut args = std::env::args().take_while(|val| val != "--"); - loop { - let arg = match args.next() { - Some(arg) => arg, - None => return false, - }; - if !arg.starts_with(name) { - continue; - } - - // Strip leading `name`. - let suffix = &arg[name.len()..]; - let value = if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - match args.next() { - Some(arg) => arg, - None => return false, - } - } else if suffix.starts_with('=') { - // This argument is `name=value`; get the value. - // Strip leading `=`. - suffix[1..].to_owned() - } else { - return false; - }; - - if check(&value) { - return true; - } - } - } - - any_arg_flag("--crate--type", TargetKind::is_lib_str) - } - let is_direct = args::is_current_compile_crate(); if is_direct { let mut cmd = Command::new(find_rap()); @@ -212,12 +171,13 @@ fn phase_rustc_wrapper() { serde_json::from_str(&magic).expect("Failed to deserialize RAP_ARGS."); cmd.args(rap_args); run_cmd(cmd); + return; } - if !is_direct || is_crate_type_lib() { - let mut cmd = Command::new("rustc"); - cmd.args(env::args().skip(2)); - run_cmd(cmd); - }; + + rap_info!("phase_rustc_wrapper: run rustc"); + let mut cmd = Command::new("rustc"); + cmd.args(env::args().skip(2)); + run_cmd(cmd); } fn main() { From bac630d4f96324eea6374ef441021c7170cc53e3 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 13:31:13 +0800 Subject: [PATCH 18/30] chore: move functions to utils.rs or target_kind.rs --- rap/src/bin/cargo-rap/main.rs | 68 ++-------------------------- rap/src/bin/cargo-rap/target_kind.rs | 52 +++++++++++++++++++-- rap/src/bin/cargo-rap/utils.rs | 23 ++++++++++ 3 files changed, 77 insertions(+), 66 deletions(-) create mode 100644 rap/src/bin/cargo-rap/utils.rs diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index 5ba4349..fb53add 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -5,75 +5,17 @@ use cargo_metadata::{Metadata, MetadataCommand}; use rap::utils::log::{init_log, rap_error_and_exit}; use rap::{rap_debug, rap_error, rap_info}; -use std::env; -use std::path::{Path, PathBuf}; -use std::process::{self, Command}; -use std::time::Duration; +use std::{env, process::Command, time::Duration}; use wait_timeout::ChildExt; mod args; mod help; -mod target_kind; -use target_kind::TargetKind; - -fn find_rap() -> PathBuf { - let mut path = env::current_exe().expect("Current executable path invalid."); - path.set_file_name("rap"); - path -} - -/* - The function finds a package under the current directory. -*/ -fn find_targets(metadata: &mut Metadata) -> Vec { - rap_info!("Search local targets for analysis."); - let current_dir = env::current_dir(); - let current_dir = current_dir.as_ref().expect("Cannot read current dir."); - let mut pkg_iter = metadata.packages.iter().filter(|package| { - let package_dir = Path::new(&package.manifest_path) - .parent() - .expect("Failed to find parent directory."); - rap_debug!("Package_dir: {:?}.", package_dir); - //FIXME: do we need to handle sub directories? - package_dir == current_dir || package_dir.starts_with(¤t_dir.to_str().unwrap()) - }); - let mut targets = Vec::new(); - while let Some(pkg) = pkg_iter.next() { - rap_info!("Find a new pakage: {:?}.", pkg.name); - let mut pkg_targets: Vec<_> = pkg.targets.clone().into_iter().collect(); - // Ensure `lib` is compiled before `bin` - pkg_targets.sort_by_key(|target| TargetKind::from(target) as u8); - targets.extend(pkg_targets); - } - targets -} - -fn is_identified_target(target: &cargo_metadata::Target, cmd: &mut Command) -> bool { - match TargetKind::from(target) { - TargetKind::Library => { - cmd.arg("--lib"); - true - } - TargetKind::Bin => { - cmd.arg("--bin").arg(&target.name); - true - } - TargetKind::Unspecified => false, - } -} +mod utils; +use crate::utils::*; -fn run_cmd(mut cmd: Command) { - rap_debug!("Command is: {:?}.", cmd); - match cmd.status() { - Ok(status) => { - if !status.success() { - process::exit(status.code().unwrap()); - } - } - Err(err) => panic!("Error in running {:?} {}.", cmd, err), - } -} +mod target_kind; +use target_kind::*; fn phase_cargo_rap() { rap_info!("Start cargo-rap"); diff --git a/rap/src/bin/cargo-rap/target_kind.rs b/rap/src/bin/cargo-rap/target_kind.rs index 7317115..aa43402 100644 --- a/rap/src/bin/cargo-rap/target_kind.rs +++ b/rap/src/bin/cargo-rap/target_kind.rs @@ -1,4 +1,9 @@ -use std::fmt::{Display, Formatter}; +use cargo_metadata::{Metadata, MetadataCommand, Target}; +use rap::{rap_debug, rap_error, rap_info}; +use std::{ + fmt::{Display, Formatter}, + process::Command, +}; #[repr(u8)] pub enum TargetKind { @@ -21,8 +26,8 @@ impl Display for TargetKind { } } -impl From<&cargo_metadata::Target> for TargetKind { - fn from(target: &cargo_metadata::Target) -> Self { +impl From<&Target> for TargetKind { + fn from(target: &Target) -> Self { if target .kind .iter() @@ -42,3 +47,44 @@ impl TargetKind { s == "lib" || s == "rlib" || s == "staticlib" } } + +pub fn is_identified_target(target: &Target, cmd: &mut Command) -> bool { + match TargetKind::from(target) { + TargetKind::Library => { + cmd.arg("--lib"); + true + } + TargetKind::Bin => { + cmd.arg("--bin").arg(&target.name); + true + } + TargetKind::Unspecified => false, + } +} + +/* + The function finds a package under the current directory. +*/ +pub fn find_targets(metadata: &mut Metadata) -> Vec { + rap_info!("Search local targets for analysis."); + let current_dir = std::env::current_dir(); + let current_dir = current_dir.as_ref().expect("Cannot read current dir."); + let mut pkg_iter = metadata.packages.iter().filter(|package| { + let package_dir = package + .manifest_path + .parent() + .expect("Failed to find parent directory."); + rap_debug!("Package_dir: {:?}.", package_dir); + //FIXME: do we need to handle sub directories? + package_dir == current_dir || package_dir.starts_with(¤t_dir.to_str().unwrap()) + }); + let mut targets = Vec::new(); + while let Some(pkg) = pkg_iter.next() { + rap_info!("Find a new pakage: {:?}.", pkg.name); + let mut pkg_targets: Vec<_> = pkg.targets.clone().into_iter().collect(); + // Ensure `lib` is compiled before `bin` + pkg_targets.sort_by_key(|target| TargetKind::from(target) as u8); + targets.extend(pkg_targets); + } + targets +} diff --git a/rap/src/bin/cargo-rap/utils.rs b/rap/src/bin/cargo-rap/utils.rs new file mode 100644 index 0000000..14f3676 --- /dev/null +++ b/rap/src/bin/cargo-rap/utils.rs @@ -0,0 +1,23 @@ +use rap::{rap_debug, rap_error, rap_info}; +use std::{ + path::PathBuf, + process::{self, Command}, +}; + +pub fn find_rap() -> PathBuf { + let mut path = std::env::current_exe().expect("Current executable path invalid."); + path.set_file_name("rap"); + path +} + +pub fn run_cmd(mut cmd: Command) { + rap_debug!("Command is: {:?}.", cmd); + match cmd.status() { + Ok(status) => { + if !status.success() { + process::exit(status.code().unwrap()); + } + } + Err(err) => panic!("Error in running {:?} {}.", cmd, err), + } +} From 47d40a82d1ba1cea506ec90ba59ad0ea27b0a77a Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 13:36:13 +0800 Subject: [PATCH 19/30] chore: #[macro_use] to import log macros into cargo-rap scope --- rap/src/bin/cargo-rap/main.rs | 5 ++++- rap/src/bin/cargo-rap/target_kind.rs | 1 - rap/src/bin/cargo-rap/utils.rs | 1 - rap/src/lib.rs | 4 +++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index fb53add..cb70e0d 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -2,9 +2,12 @@ This is a cargo program to start RAP. The file references the cargo file for Miri: https://github.com/rust-lang/miri/blob/master/cargo-miri/src/main.rs */ + +#[macro_use] +extern crate rap; + use cargo_metadata::{Metadata, MetadataCommand}; use rap::utils::log::{init_log, rap_error_and_exit}; -use rap::{rap_debug, rap_error, rap_info}; use std::{env, process::Command, time::Duration}; use wait_timeout::ChildExt; diff --git a/rap/src/bin/cargo-rap/target_kind.rs b/rap/src/bin/cargo-rap/target_kind.rs index aa43402..92ee1bf 100644 --- a/rap/src/bin/cargo-rap/target_kind.rs +++ b/rap/src/bin/cargo-rap/target_kind.rs @@ -1,5 +1,4 @@ use cargo_metadata::{Metadata, MetadataCommand, Target}; -use rap::{rap_debug, rap_error, rap_info}; use std::{ fmt::{Display, Formatter}, process::Command, diff --git a/rap/src/bin/cargo-rap/utils.rs b/rap/src/bin/cargo-rap/utils.rs index 14f3676..637aeb6 100644 --- a/rap/src/bin/cargo-rap/utils.rs +++ b/rap/src/bin/cargo-rap/utils.rs @@ -1,4 +1,3 @@ -use rap::{rap_debug, rap_error, rap_info}; use std::{ path::PathBuf, process::{self, Command}, diff --git a/rap/src/lib.rs b/rap/src/lib.rs index b02113b..4c37a32 100644 --- a/rap/src/lib.rs +++ b/rap/src/lib.rs @@ -2,9 +2,11 @@ #![feature(control_flow_enum)] #![feature(box_patterns)] -pub mod analysis; +#[macro_use] pub mod utils; +pub mod analysis; + extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; From 050257a78b0873702a8b655ddeeb59052ebfa69a Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 13:42:58 +0800 Subject: [PATCH 20/30] chore: define args::get_arg --- rap/src/bin/cargo-rap/args.rs | 4 ++++ rap/src/bin/cargo-rap/main.rs | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index 5085309..ee56d27 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -87,3 +87,7 @@ pub fn is_crate_type_lib() -> bool { .map(crate::TargetKind::is_lib_str) .unwrap_or(false) } + +pub fn get_arg(pos: usize) -> Option<&'static str> { + ARGS.args.get(pos).map(|x| x.as_str()) +} diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index cb70e0d..f269832 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -22,12 +22,13 @@ use target_kind::*; fn phase_cargo_rap() { rap_info!("Start cargo-rap"); - let mut args = env::args().skip(2); // here we skip two tokens: cargo rap - let Some(arg) = args.next() else { + + // here we skip two args: cargo rap + let Some(arg) = args::get_arg(2) else { rap_error!("Expect command: e.g., `cargo rap -help`."); return; }; - match arg.as_str() { + match arg { "-V" | "-version" => { rap_info!("{}", help::RAP_VERSION); return; @@ -137,8 +138,7 @@ fn main() { init_log().expect("Failed to init log."); rap_debug!("Enter cargo-rap; Received args: {:?}", env::args()); - let first_arg = env::args().nth(1); - match first_arg.unwrap() { + match args::get_arg(1).unwrap() { s if s.ends_with("rap") => phase_cargo_rap(), s if s.ends_with("rustc") => phase_rustc_wrapper(), _ => { From ec8a45569e734649e63a27b10863d8ae9989d8d1 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 13:44:21 +0800 Subject: [PATCH 21/30] chore: rename target_kind module to target --- rap/src/bin/cargo-rap/main.rs | 4 ++-- rap/src/bin/cargo-rap/{target_kind.rs => target.rs} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename rap/src/bin/cargo-rap/{target_kind.rs => target.rs} (100%) diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index f269832..1a13886 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -17,8 +17,8 @@ mod help; mod utils; use crate::utils::*; -mod target_kind; -use target_kind::*; +mod target; +use target::*; fn phase_cargo_rap() { rap_info!("Start cargo-rap"); diff --git a/rap/src/bin/cargo-rap/target_kind.rs b/rap/src/bin/cargo-rap/target.rs similarity index 100% rename from rap/src/bin/cargo-rap/target_kind.rs rename to rap/src/bin/cargo-rap/target.rs From e080f38b61cfd91c50e6865a311b576261314b06 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 13:51:51 +0800 Subject: [PATCH 22/30] chore: define run_rustc --- rap/src/bin/cargo-rap/args.rs | 4 ++++ rap/src/bin/cargo-rap/main.rs | 5 +---- rap/src/bin/cargo-rap/utils.rs | 6 ++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index ee56d27..a7be193 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -91,3 +91,7 @@ pub fn is_crate_type_lib() -> bool { pub fn get_arg(pos: usize) -> Option<&'static str> { ARGS.args.get(pos).map(|x| x.as_str()) } + +pub fn rustc() -> &'static [String] { + ARGS.args.get(2..).unwrap_or(&[]) +} diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index 1a13886..a8abace 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -120,10 +120,7 @@ fn phase_rustc_wrapper() { return; } - rap_info!("phase_rustc_wrapper: run rustc"); - let mut cmd = Command::new("rustc"); - cmd.args(env::args().skip(2)); - run_cmd(cmd); + run_rustc(); } fn main() { diff --git a/rap/src/bin/cargo-rap/utils.rs b/rap/src/bin/cargo-rap/utils.rs index 637aeb6..1e29a41 100644 --- a/rap/src/bin/cargo-rap/utils.rs +++ b/rap/src/bin/cargo-rap/utils.rs @@ -20,3 +20,9 @@ pub fn run_cmd(mut cmd: Command) { Err(err) => panic!("Error in running {:?} {}.", cmd, err), } } + +pub fn run_rustc() { + let mut cmd = Command::new("rustc"); + cmd.args(crate::args::rustc()); + run_cmd(cmd); +} From 0fcf1ea84a2dae2620684fd24b059bfeb0a72412 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 13:54:43 +0800 Subject: [PATCH 23/30] chore: define run_rap --- rap/src/bin/cargo-rap/args.rs | 2 +- rap/src/bin/cargo-rap/main.rs | 8 +------- rap/src/bin/cargo-rap/utils.rs | 13 ++++++++++++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index a7be193..db50f18 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -92,6 +92,6 @@ pub fn get_arg(pos: usize) -> Option<&'static str> { ARGS.args.get(pos).map(|x| x.as_str()) } -pub fn rustc() -> &'static [String] { +pub fn skip2() -> &'static [String] { ARGS.args.get(2..).unwrap_or(&[]) } diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index a8abace..1429a52 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -110,13 +110,7 @@ fn phase_rustc_wrapper() { let is_direct = args::is_current_compile_crate(); if is_direct { - let mut cmd = Command::new(find_rap()); - cmd.args(env::args().skip(2)); - let magic = env::var("RAP_ARGS").expect("Missing RAP_ARGS."); - let rap_args: Vec = - serde_json::from_str(&magic).expect("Failed to deserialize RAP_ARGS."); - cmd.args(rap_args); - run_cmd(cmd); + run_rap(); return; } diff --git a/rap/src/bin/cargo-rap/utils.rs b/rap/src/bin/cargo-rap/utils.rs index 1e29a41..4ee8486 100644 --- a/rap/src/bin/cargo-rap/utils.rs +++ b/rap/src/bin/cargo-rap/utils.rs @@ -1,3 +1,4 @@ +use crate::args; use std::{ path::PathBuf, process::{self, Command}, @@ -23,6 +24,16 @@ pub fn run_cmd(mut cmd: Command) { pub fn run_rustc() { let mut cmd = Command::new("rustc"); - cmd.args(crate::args::rustc()); + cmd.args(args::skip2()); + run_cmd(cmd); +} + +pub fn run_rap() { + let mut cmd = Command::new(find_rap()); + cmd.args(args::skip2()); + let magic = std::env::var("RAP_ARGS").expect("Missing RAP_ARGS."); + let rap_args: Vec = + serde_json::from_str(&magic).expect("Failed to deserialize RAP_ARGS."); + cmd.args(rap_args); run_cmd(cmd); } From 4a7edad0a50ead997b0d884b2be07b54807c8092 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 14:09:50 +0800 Subject: [PATCH 24/30] chore: define run_cargo_check --- rap/src/bin/cargo-rap/args.rs | 1 + rap/src/bin/cargo-rap/main.rs | 68 +----------------------------- rap/src/bin/cargo-rap/target.rs | 75 ++++++++++++++++++++++++++++++++- rap/src/bin/cargo-rap/utils.rs | 7 +-- 4 files changed, 79 insertions(+), 72 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index db50f18..c9763e3 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -35,6 +35,7 @@ impl Arguments { fn new() -> Self { let args: Vec<_> = std::env::args().collect(); + rap_debug!("Received args: {args:?}"); let [args_group1, args_group2] = split_args_by_double_dash(&args); Arguments { args, diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index 1429a52..ce7c10a 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -6,10 +6,7 @@ #[macro_use] extern crate rap; -use cargo_metadata::{Metadata, MetadataCommand}; use rap::utils::log::{init_log, rap_error_and_exit}; -use std::{env, process::Command, time::Duration}; -use wait_timeout::ChildExt; mod args; mod help; @@ -40,69 +37,7 @@ fn phase_cargo_rap() { _ => {} } - let cmd = MetadataCommand::new(); - rap_debug!("Please run `cargo metadata` if this step takes too long"); - let mut metadata = match cmd.exec() { - // execute command: `cargo metadata' - Ok(metadata) => metadata, - Err(e) => rap_error_and_exit(format!("Cannot obtain cargo metadata: {}.", e)), - }; - - let [rap_args, cargo_args] = args::rap_and_cargo_args(); - rap_debug!("rap_args={rap_args:?}\tcargo_args={cargo_args:?}"); - - let targets = find_targets(&mut metadata); - for target in targets { - /*Here we prepare the cargo command as cargo check, which is similar to build, but much faster*/ - let mut cmd = Command::new("cargo"); - cmd.arg("check"); - - /* We only process bin and lib targets, and ignore others */ - if !is_identified_target(&target, &mut cmd) { - rap_debug!("Ignore the target because it is neither bin or lib."); - continue; - } - - /* set the target as a filter for phase_rustc_rap */ - cmd.args(cargo_args); - - // Serialize the remaining args into a special environment variable. - // This will be read by `phase_rustc_rap` when we go to invoke - // our actual target crate (the binary or the test we are running). - - cmd.env( - "RAP_ARGS", - serde_json::to_string(rap_args).expect("Failed to serialize args."), - ); - - // Invoke actual cargo for the job, but with different flags. - let cargo_rap_path = env::current_exe().expect("Current executable path is invalid."); - cmd.env("RUSTC_WRAPPER", &cargo_rap_path); - - rap_debug!("Command is: {:?}.", cmd); - rap_info!( - "Running rap for target {}:{}", - TargetKind::from(&target), - &target.name - ); - - let mut child = cmd.spawn().expect("Could not run cargo check."); - match child - .wait_timeout(Duration::from_secs(60 * 60)) // 1 hour timeout - .expect("Failed to wait for subprocess.") - { - Some(status) => { - if !status.success() { - rap_error_and_exit("Finished with non-zero exit code."); - } - } - None => { - child.kill().expect("Failed to kill subprocess."); - child.wait().expect("Failed to wait for subprocess."); - rap_error_and_exit("Process killed due to timeout."); - } - }; - } + run_cargo_check(); } fn phase_rustc_wrapper() { @@ -127,7 +62,6 @@ fn main() { // Init the log_system init_log().expect("Failed to init log."); - rap_debug!("Enter cargo-rap; Received args: {:?}", env::args()); match args::get_arg(1).unwrap() { s if s.ends_with("rap") => phase_cargo_rap(), diff --git a/rap/src/bin/cargo-rap/target.rs b/rap/src/bin/cargo-rap/target.rs index 92ee1bf..2249798 100644 --- a/rap/src/bin/cargo-rap/target.rs +++ b/rap/src/bin/cargo-rap/target.rs @@ -1,9 +1,14 @@ use cargo_metadata::{Metadata, MetadataCommand, Target}; use std::{ + env, fmt::{Display, Formatter}, process::Command, + time::Duration, }; +use rap::utils::log::{init_log, rap_error_and_exit}; +use wait_timeout::ChildExt; + #[repr(u8)] pub enum TargetKind { Library, @@ -47,7 +52,7 @@ impl TargetKind { } } -pub fn is_identified_target(target: &Target, cmd: &mut Command) -> bool { +fn is_identified_target(target: &Target, cmd: &mut Command) -> bool { match TargetKind::from(target) { TargetKind::Library => { cmd.arg("--lib"); @@ -64,7 +69,7 @@ pub fn is_identified_target(target: &Target, cmd: &mut Command) -> bool { /* The function finds a package under the current directory. */ -pub fn find_targets(metadata: &mut Metadata) -> Vec { +fn find_targets(metadata: &mut Metadata) -> Vec { rap_info!("Search local targets for analysis."); let current_dir = std::env::current_dir(); let current_dir = current_dir.as_ref().expect("Cannot read current dir."); @@ -87,3 +92,69 @@ pub fn find_targets(metadata: &mut Metadata) -> Vec { } targets } + +pub fn run_cargo_check() { + let cmd = MetadataCommand::new(); + rap_debug!("Please run `cargo metadata` if this step takes too long"); + let mut metadata = match cmd.exec() { + // execute command: `cargo metadata' + Ok(metadata) => metadata, + Err(e) => rap_error_and_exit(format!("Cannot obtain cargo metadata: {}.", e)), + }; + + let [rap_args, cargo_args] = crate::args::rap_and_cargo_args(); + rap_debug!("rap_args={rap_args:?}\tcargo_args={cargo_args:?}"); + + let targets = find_targets(&mut metadata); + for target in targets { + /*Here we prepare the cargo command as cargo check, which is similar to build, but much faster*/ + let mut cmd = Command::new("cargo"); + cmd.arg("check"); + + /* We only process bin and lib targets, and ignore others */ + if !is_identified_target(&target, &mut cmd) { + rap_debug!("Ignore the target because it is neither bin or lib."); + continue; + } + + /* set the target as a filter for phase_rustc_rap */ + cmd.args(cargo_args); + + // Serialize the remaining args into a special environment variable. + // This will be read by `phase_rustc_rap` when we go to invoke + // our actual target crate (the binary or the test we are running). + + cmd.env( + "RAP_ARGS", + serde_json::to_string(rap_args).expect("Failed to serialize args."), + ); + + // Invoke actual cargo for the job, but with different flags. + let cargo_rap_path = env::current_exe().expect("Current executable path is invalid."); + cmd.env("RUSTC_WRAPPER", &cargo_rap_path); + + rap_debug!("Command is: {:?}.", cmd); + rap_info!( + "Running rap for target {}:{}", + TargetKind::from(&target), + &target.name + ); + + let mut child = cmd.spawn().expect("Could not run cargo check."); + match child + .wait_timeout(Duration::from_secs(60 * 60)) // 1 hour timeout + .expect("Failed to wait for subprocess.") + { + Some(status) => { + if !status.success() { + rap_error_and_exit("Finished with non-zero exit code."); + } + } + None => { + child.kill().expect("Failed to kill subprocess."); + child.wait().expect("Failed to wait for subprocess."); + rap_error_and_exit("Process killed due to timeout."); + } + }; + } +} diff --git a/rap/src/bin/cargo-rap/utils.rs b/rap/src/bin/cargo-rap/utils.rs index 4ee8486..b7498ab 100644 --- a/rap/src/bin/cargo-rap/utils.rs +++ b/rap/src/bin/cargo-rap/utils.rs @@ -1,11 +1,12 @@ use crate::args; use std::{ + env, path::PathBuf, process::{self, Command}, }; -pub fn find_rap() -> PathBuf { - let mut path = std::env::current_exe().expect("Current executable path invalid."); +fn find_rap() -> PathBuf { + let mut path = env::current_exe().expect("Current executable path invalid."); path.set_file_name("rap"); path } @@ -31,7 +32,7 @@ pub fn run_rustc() { pub fn run_rap() { let mut cmd = Command::new(find_rap()); cmd.args(args::skip2()); - let magic = std::env::var("RAP_ARGS").expect("Missing RAP_ARGS."); + let magic = env::var("RAP_ARGS").expect("Missing RAP_ARGS."); let rap_args: Vec = serde_json::from_str(&magic).expect("Failed to deserialize RAP_ARGS."); cmd.args(rap_args); From bbd9c48ecb7b01b90dae94ec9e48ccaf7e2cffac Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 14:17:22 +0800 Subject: [PATCH 25/30] chore: define args::current_exe_path --- rap/src/bin/cargo-rap/args.rs | 17 ++++++++++++++--- rap/src/bin/cargo-rap/target.rs | 10 +++++----- rap/src/bin/cargo-rap/utils.rs | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index c9763e3..655ef41 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -1,4 +1,8 @@ -use std::{path::Path, sync::LazyLock}; +use std::{ + env, + path::{Path, PathBuf}, + sync::LazyLock, +}; struct Arguments { /// a collection of `std::env::args()` @@ -7,6 +11,7 @@ struct Arguments { args_group1: Vec, /// options as second half after -- in args args_group2: Vec, + current_exe_path: PathBuf, } impl Arguments { @@ -34,13 +39,15 @@ impl Arguments { } fn new() -> Self { - let args: Vec<_> = std::env::args().collect(); - rap_debug!("Received args: {args:?}"); + let args: Vec<_> = env::args().collect(); + let path = env::current_exe().expect("Current executable path invalid."); + rap_debug!("Current exe: {path:?}\tReceived args: {args:?}"); let [args_group1, args_group2] = split_args_by_double_dash(&args); Arguments { args, args_group1, args_group2, + current_exe_path: path, } } @@ -96,3 +103,7 @@ pub fn get_arg(pos: usize) -> Option<&'static str> { pub fn skip2() -> &'static [String] { ARGS.args.get(2..).unwrap_or(&[]) } + +pub fn current_exe_path() -> &'static Path { + &ARGS.current_exe_path +} diff --git a/rap/src/bin/cargo-rap/target.rs b/rap/src/bin/cargo-rap/target.rs index 2249798..408e497 100644 --- a/rap/src/bin/cargo-rap/target.rs +++ b/rap/src/bin/cargo-rap/target.rs @@ -1,12 +1,12 @@ +use crate::args; use cargo_metadata::{Metadata, MetadataCommand, Target}; +use rap::utils::log::{init_log, rap_error_and_exit}; use std::{ env, fmt::{Display, Formatter}, process::Command, time::Duration, }; - -use rap::utils::log::{init_log, rap_error_and_exit}; use wait_timeout::ChildExt; #[repr(u8)] @@ -71,7 +71,7 @@ fn is_identified_target(target: &Target, cmd: &mut Command) -> bool { */ fn find_targets(metadata: &mut Metadata) -> Vec { rap_info!("Search local targets for analysis."); - let current_dir = std::env::current_dir(); + let current_dir = env::current_dir(); let current_dir = current_dir.as_ref().expect("Cannot read current dir."); let mut pkg_iter = metadata.packages.iter().filter(|package| { let package_dir = package @@ -130,8 +130,8 @@ pub fn run_cargo_check() { ); // Invoke actual cargo for the job, but with different flags. - let cargo_rap_path = env::current_exe().expect("Current executable path is invalid."); - cmd.env("RUSTC_WRAPPER", &cargo_rap_path); + let cargo_rap_path = args::current_exe_path(); + cmd.env("RUSTC_WRAPPER", cargo_rap_path); rap_debug!("Command is: {:?}.", cmd); rap_info!( diff --git a/rap/src/bin/cargo-rap/utils.rs b/rap/src/bin/cargo-rap/utils.rs index b7498ab..f6b1897 100644 --- a/rap/src/bin/cargo-rap/utils.rs +++ b/rap/src/bin/cargo-rap/utils.rs @@ -6,7 +6,7 @@ use std::{ }; fn find_rap() -> PathBuf { - let mut path = env::current_exe().expect("Current executable path invalid."); + let mut path = args::current_exe_path().to_owned(); path.set_file_name("rap"); path } From 9cbd3ee72d7c97e64cd2b2e62a5851069d7b2a40 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 15:34:37 +0800 Subject: [PATCH 26/30] chore: remove target filtering => cargo check is responsible to handle them --- rap/src/bin/cargo-rap/target.rs | 178 ++++++-------------------------- 1 file changed, 33 insertions(+), 145 deletions(-) diff --git a/rap/src/bin/cargo-rap/target.rs b/rap/src/bin/cargo-rap/target.rs index 408e497..1d7100e 100644 --- a/rap/src/bin/cargo-rap/target.rs +++ b/rap/src/bin/cargo-rap/target.rs @@ -1,160 +1,48 @@ use crate::args; -use cargo_metadata::{Metadata, MetadataCommand, Target}; -use rap::utils::log::{init_log, rap_error_and_exit}; -use std::{ - env, - fmt::{Display, Formatter}, - process::Command, - time::Duration, -}; +use rap::utils::log::rap_error_and_exit; +use std::{process::Command, time::Duration}; use wait_timeout::ChildExt; -#[repr(u8)] -pub enum TargetKind { - Library, - Bin, - Unspecified, -} - -impl Display for TargetKind { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self { - TargetKind::Library => "lib", - TargetKind::Bin => "bin", - TargetKind::Unspecified => "unspecified", - } - ) - } -} - -impl From<&Target> for TargetKind { - fn from(target: &Target) -> Self { - if target - .kind - .iter() - .any(|s| s == "lib" || s == "rlib" || s == "staticlib") - { - TargetKind::Library - } else if target.kind.iter().any(|s| s == "bin") { - TargetKind::Bin - } else { - TargetKind::Unspecified - } - } -} - -impl TargetKind { - pub fn is_lib_str(s: &str) -> bool { - s == "lib" || s == "rlib" || s == "staticlib" - } -} - -fn is_identified_target(target: &Target, cmd: &mut Command) -> bool { - match TargetKind::from(target) { - TargetKind::Library => { - cmd.arg("--lib"); - true - } - TargetKind::Bin => { - cmd.arg("--bin").arg(&target.name); - true - } - TargetKind::Unspecified => false, - } -} - -/* - The function finds a package under the current directory. -*/ -fn find_targets(metadata: &mut Metadata) -> Vec { - rap_info!("Search local targets for analysis."); - let current_dir = env::current_dir(); - let current_dir = current_dir.as_ref().expect("Cannot read current dir."); - let mut pkg_iter = metadata.packages.iter().filter(|package| { - let package_dir = package - .manifest_path - .parent() - .expect("Failed to find parent directory."); - rap_debug!("Package_dir: {:?}.", package_dir); - //FIXME: do we need to handle sub directories? - package_dir == current_dir || package_dir.starts_with(¤t_dir.to_str().unwrap()) - }); - let mut targets = Vec::new(); - while let Some(pkg) = pkg_iter.next() { - rap_info!("Find a new pakage: {:?}.", pkg.name); - let mut pkg_targets: Vec<_> = pkg.targets.clone().into_iter().collect(); - // Ensure `lib` is compiled before `bin` - pkg_targets.sort_by_key(|target| TargetKind::from(target) as u8); - targets.extend(pkg_targets); - } - targets -} - pub fn run_cargo_check() { - let cmd = MetadataCommand::new(); - rap_debug!("Please run `cargo metadata` if this step takes too long"); - let mut metadata = match cmd.exec() { - // execute command: `cargo metadata' - Ok(metadata) => metadata, - Err(e) => rap_error_and_exit(format!("Cannot obtain cargo metadata: {}.", e)), - }; - let [rap_args, cargo_args] = crate::args::rap_and_cargo_args(); rap_debug!("rap_args={rap_args:?}\tcargo_args={cargo_args:?}"); - let targets = find_targets(&mut metadata); - for target in targets { - /*Here we prepare the cargo command as cargo check, which is similar to build, but much faster*/ - let mut cmd = Command::new("cargo"); - cmd.arg("check"); + /*Here we prepare the cargo command as cargo check, which is similar to build, but much faster*/ + let mut cmd = Command::new("cargo"); + cmd.arg("check"); - /* We only process bin and lib targets, and ignore others */ - if !is_identified_target(&target, &mut cmd) { - rap_debug!("Ignore the target because it is neither bin or lib."); - continue; - } - - /* set the target as a filter for phase_rustc_rap */ - cmd.args(cargo_args); + /* set the target as a filter for phase_rustc_rap */ + cmd.args(cargo_args); - // Serialize the remaining args into a special environment variable. - // This will be read by `phase_rustc_rap` when we go to invoke - // our actual target crate (the binary or the test we are running). + // Serialize the remaining args into a special environment variable. + // This will be read by `phase_rustc_rap` when we go to invoke + // our actual target crate (the binary or the test we are running). - cmd.env( - "RAP_ARGS", - serde_json::to_string(rap_args).expect("Failed to serialize args."), - ); + cmd.env( + "RAP_ARGS", + serde_json::to_string(rap_args).expect("Failed to serialize args."), + ); - // Invoke actual cargo for the job, but with different flags. - let cargo_rap_path = args::current_exe_path(); - cmd.env("RUSTC_WRAPPER", cargo_rap_path); + // Invoke actual cargo for the job, but with different flags. + let cargo_rap_path = args::current_exe_path(); + cmd.env("RUSTC_WRAPPER", cargo_rap_path); - rap_debug!("Command is: {:?}.", cmd); - rap_info!( - "Running rap for target {}:{}", - TargetKind::from(&target), - &target.name - ); + rap_debug!("Command is: {:?}.", cmd); - let mut child = cmd.spawn().expect("Could not run cargo check."); - match child - .wait_timeout(Duration::from_secs(60 * 60)) // 1 hour timeout - .expect("Failed to wait for subprocess.") - { - Some(status) => { - if !status.success() { - rap_error_and_exit("Finished with non-zero exit code."); - } - } - None => { - child.kill().expect("Failed to kill subprocess."); - child.wait().expect("Failed to wait for subprocess."); - rap_error_and_exit("Process killed due to timeout."); + let mut child = cmd.spawn().expect("Could not run cargo check."); + match child + .wait_timeout(Duration::from_secs(60 * 60)) // 1 hour timeout + .expect("Failed to wait for subprocess.") + { + Some(status) => { + if !status.success() { + rap_error_and_exit("Finished with non-zero exit code."); } - }; - } + } + None => { + child.kill().expect("Failed to kill subprocess."); + child.wait().expect("Failed to wait for subprocess."); + rap_error_and_exit("Process killed due to timeout."); + } + }; } From a2de468ce219295856a331758fa7800c3eeba3a9 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 15:38:38 +0800 Subject: [PATCH 27/30] chore: remove get_arg_flag_value --- rap/src/bin/cargo-rap/args.rs | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/rap/src/bin/cargo-rap/args.rs b/rap/src/bin/cargo-rap/args.rs index 655ef41..c319255 100644 --- a/rap/src/bin/cargo-rap/args.rs +++ b/rap/src/bin/cargo-rap/args.rs @@ -15,29 +15,6 @@ struct Arguments { } impl Arguments { - // Get value from `name=val` or `name val`. - fn get_arg_flag_value(&self, name: &str) -> Option<&str> { - let mut args = self.args_group1.iter(); - - while let Some(arg) = args.next() { - if !arg.starts_with(name) { - continue; - } - // Strip leading `name`. - let suffix = &arg[name.len()..]; - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return args.next().map(|x| x.as_str()); - } else if suffix.starts_with('=') { - // This argument is `name=value`; get the value. - // Strip leading `=`. - return Some(&suffix[1..]); - } - } - - None - } - fn new() -> Self { let args: Vec<_> = env::args().collect(); let path = env::current_exe().expect("Current executable path invalid."); @@ -73,10 +50,6 @@ fn split_args_by_double_dash(args: &[String]) -> [Vec; 2] { static ARGS: LazyLock = LazyLock::new(Arguments::new); -pub fn get_arg_flag_value(name: &str) -> Option<&'static str> { - ARGS.get_arg_flag_value(name) -} - /// `cargo rap [rap options] -- [cargo check options]` /// /// Options before the first `--` are arguments forwarding to rap. @@ -90,12 +63,6 @@ pub fn is_current_compile_crate() -> bool { ARGS.is_current_compile_crate() } -pub fn is_crate_type_lib() -> bool { - get_arg_flag_value("--crate--type") - .map(crate::TargetKind::is_lib_str) - .unwrap_or(false) -} - pub fn get_arg(pos: usize) -> Option<&'static str> { ARGS.args.get(pos).map(|x| x.as_str()) } From 42165aa7ca654414965dd46e8b880b626abcf0fa Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 15:39:34 +0800 Subject: [PATCH 28/30] chore: remove cargo_metadata dependencies; and other dead deps --- rap/Cargo.lock | 41 ----------------------------------------- rap/Cargo.toml | 3 --- 2 files changed, 44 deletions(-) diff --git a/rap/Cargo.lock b/rap/Cargo.lock index f60f52b..9c7311f 100644 --- a/rap/Cargo.lock +++ b/rap/Cargo.lock @@ -94,37 +94,6 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - [[package]] name = "cc" version = "1.0.83" @@ -403,7 +372,6 @@ dependencies = [ name = "rap" version = "1.0.0" dependencies = [ - "cargo_metadata", "chrono", "colorful", "fern", @@ -462,15 +430,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" -[[package]] -name = "semver" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" -dependencies = [ - "serde", -] - [[package]] name = "serde" version = "1.0.188" diff --git a/rap/Cargo.toml b/rap/Cargo.toml index 939d359..9c541c3 100644 --- a/rap/Cargo.toml +++ b/rap/Cargo.toml @@ -17,9 +17,6 @@ name = "cargo-rap" name = "rap" [dependencies] -#lazy_static = "1.4" -# rustc_version = "0.4.0" -cargo_metadata = "0.14.1" snafu = "0.7.0" chrono = "0.4.19" serde_json = "1.0.72" From c8cec2f7a34b6b9dee54a15ab69aa46dc6db490c Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 15:45:11 +0800 Subject: [PATCH 29/30] doc(phase_rustc_wrapper): rap only checks local crates --- rap/src/bin/cargo-rap/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rap/src/bin/cargo-rap/main.rs b/rap/src/bin/cargo-rap/main.rs index ce7c10a..1c82f88 100644 --- a/rap/src/bin/cargo-rap/main.rs +++ b/rap/src/bin/cargo-rap/main.rs @@ -44,11 +44,13 @@ fn phase_rustc_wrapper() { rap_debug!("Launch cargo-rap again triggered by cargo check."); let is_direct = args::is_current_compile_crate(); + // rap only checks local crates if is_direct { run_rap(); return; } + // for dependencies, run rustc as usual run_rustc(); } From e94e68f5f7325092e1e65cf0e6e309fda6742b09 Mon Sep 17 00:00:00 2001 From: zjp Date: Sat, 26 Oct 2024 15:48:03 +0800 Subject: [PATCH 30/30] doc(RAP_HELP): more examples for cargo arguments --- rap/src/bin/cargo-rap/help.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rap/src/bin/cargo-rap/help.rs b/rap/src/bin/cargo-rap/help.rs index 1979636..27418c6 100644 --- a/rap/src/bin/cargo-rap/help.rs +++ b/rap/src/bin/cargo-rap/help.rs @@ -27,8 +27,13 @@ NOTE: multiple detections can be processed in single run by appending the options to the arguments. Like `cargo rap -F -M` will perform two kinds of detection in a row. -e.g. detect use-after-free and memory leak for a riscv target: - cargo rap -F -M -- --target riscv64gc-unknown-none-elf +e.g. +1. detect use-after-free and memory leak for a riscv target: + cargo rap -F -M -- --target riscv64gc-unknown-none-elf +2. detect use-after-free and memory leak for tests: + cargo rap -F -M -- --tests +3. detect use-after-free and memory leak for all members: + cargo rap -F -M -- --workspace "#; pub const RAP_VERSION: &str = r#"