Skip to content

Commit bc00a84

Browse files
committed
feat(build): add target argument
Adapt target resolving, such that guessing fails when bin target is non-unique. Additionally, cache `cargo_metadata` in `Common` struct (now an argument for every subcmd).
1 parent 1dafb09 commit bc00a84

12 files changed

Lines changed: 600 additions & 506 deletions

File tree

src/bin/cargo-ziggy/add_seeds.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use crate::*;
2-
use anyhow::bail;
1+
use crate::{AddSeeds, Common};
2+
use anyhow::{Context, bail};
33
use std::{env, process};
44

55
impl AddSeeds {
6-
pub fn add_seeds(&self) -> Result<(), anyhow::Error> {
6+
pub fn add_seeds(&self, common: &Common) -> Result<(), anyhow::Error> {
77
eprintln!("Adding seeds to AFL");
88

99
let req = semver::VersionReq::parse(">=0.14.5").unwrap();
@@ -27,11 +27,11 @@ impl AddSeeds {
2727
);
2828
}
2929

30-
let target = find_target(&self.target)?;
30+
let target = common.resolve_bin(self.target.clone())?;
3131
let input = self.input.display().to_string();
3232

33-
let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
34-
process::Command::new(&cargo)
33+
common
34+
.cargo()
3535
.args([
3636
"afl",
3737
"addseeds",

src/bin/cargo-ziggy/build.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
1-
use crate::Build;
2-
use anyhow::{Context, Result, bail};
1+
use crate::{Build, Common, util::Context};
2+
use anyhow::{Context as _, Result, bail};
33
use console::style;
44
use std::{env, process};
55

66
impl Build {
77
/// Build the fuzzers
8-
pub fn build(&self) -> Result<(), anyhow::Error> {
8+
pub fn build(&self, common: &Common) -> Result<(), anyhow::Error> {
99
// No fuzzers for you
1010
if self.no_afl && self.no_honggfuzz {
1111
bail!("Pick at least one fuzzer");
1212
}
1313

14-
// The cargo executable
15-
let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
14+
let cx = Context::new(common, self.target.clone())?;
1615

1716
if !self.no_afl {
1817
eprintln!(" {} afl", style("Building").red().bold());
19-
let target_dir = format!("--target-dir={}", super::target_dir().join("afl"));
20-
let mut afl_args = vec!["afl", "build", "--features=ziggy/afl", &target_dir];
18+
let target_dir = format!("--target-dir={}", cx.target_dir.join("afl"));
19+
let mut afl_args = vec![
20+
"afl",
21+
"build",
22+
"--features=ziggy/afl",
23+
&target_dir,
24+
"--bin",
25+
&cx.bin_target,
26+
];
2127

2228
// Add the --release argument if self.release is true
2329
if self.release {
@@ -29,7 +35,8 @@ impl Build {
2935
let mut rust_doc_flags = env::var("RUSTDOCFLAGS").unwrap_or_default();
3036

3137
// First fuzzer we build: AFL++
32-
let run = process::Command::new(&cargo)
38+
let run = common
39+
.cargo()
3340
.args(&afl_args)
3441
.env("AFL_QUIET", "1")
3542
.env("AFL_LLVM_CMPLOG", "1") // for afl.rs feature "plugins"
@@ -57,7 +64,8 @@ impl Build {
5764
rust_flags.push_str("-Copt-level=0");
5865
rust_doc_flags.push_str(" -Zsanitizer=address ");
5966

60-
let run = process::Command::new(&cargo)
67+
let run = common
68+
.cargo()
6169
.args(afl_args)
6270
.env("AFL_QUIET", "1")
6371
// need to specify for afl.rs so that we build with -Copt-level=0
@@ -85,9 +93,10 @@ impl Build {
8593
eprintln!(" {} honggfuzz", style("Building").red().bold());
8694

8795
// Second fuzzer we build: Honggfuzz
88-
let run = process::Command::new(&cargo)
89-
.args(["hfuzz", "build"])
90-
.env("CARGO_TARGET_DIR", super::target_dir().join("honggfuzz"))
96+
let run = common
97+
.cargo()
98+
.args(["hfuzz", "build", "--bin", &cx.bin_target])
99+
.env("CARGO_TARGET_DIR", cx.target_dir.join("honggfuzz"))
91100
.env("HFUZZ_BUILD_ARGS", "--features=ziggy/honggfuzz")
92101
.env("RUSTFLAGS", env::var("RUSTFLAGS").unwrap_or_default())
93102
.stdout(process::Stdio::piped())

src/bin/cargo-ziggy/clean.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1-
use crate::Clean;
1+
use crate::{Clean, Common};
22
use anyhow::{Error, bail};
3-
use std::{env, process::Command};
43

54
impl Clean {
6-
pub fn clean(&self) -> Result<(), Error> {
7-
let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
8-
5+
pub fn clean(&self, common: &Common) -> Result<(), Error> {
6+
let Ok(target_dir) = common.target_dir() else {
7+
return Ok(());
8+
};
99
let clean = |target, target_triple: Option<&str>, try_release| -> Result<(), Error> {
1010
let already_profile = self
1111
.args
1212
.iter()
1313
.any(|arg| arg.as_encoded_bytes().starts_with(b"--profile") || arg == "--release");
14-
let status = Command::new(&cargo)
14+
let status = common
15+
.cargo()
1516
.arg("clean")
1617
.arg("-q")
1718
.args(&self.args)
1819
.args(target_triple.map(|triple| format!("--target={triple}")))
1920
.args((!already_profile && try_release).then_some("--release"))
20-
.env("CARGO_TARGET_DIR", super::target_dir().join(target))
21+
.env("CARGO_TARGET_DIR", target_dir.join(target))
2122
.status()
2223
.expect("Error running cargo clean command");
2324
if !status.success() {

src/bin/cargo-ziggy/coverage.rs

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use crate::{Cover, find_target};
2-
use anyhow::{Context, Result, bail};
3-
use cargo_metadata::camino::Utf8PathBuf;
1+
use crate::{Common, Cover, util::Context, util::Utf8PathBuf};
2+
use anyhow::{Context as _, Result, bail};
43
use glob::glob;
54
use indicatif::{ProgressBar, ProgressStyle};
65
use rayon::iter::{IntoParallelIterator, ParallelIterator};
@@ -16,37 +15,35 @@ thread_local! {
1615
}
1716

1817
impl Cover {
19-
pub fn generate_coverage(&mut self) -> Result<(), anyhow::Error> {
18+
pub fn generate_coverage(&self, common: &Common) -> Result<(), anyhow::Error> {
19+
let cx = Context::new(common, self.target.clone())?;
2020
process::Command::new("grcov")
2121
.arg("--version")
2222
.output()
2323
.context("grcov not found - please install by running `cargo install grcov`")?;
2424

2525
eprintln!("Generating coverage");
2626

27-
self.target =
28-
find_target(&self.target).context("⚠️ couldn't find the target to start coverage")?;
29-
3027
if let Some(path) = &self.source
3128
&& !path.try_exists()?
3229
{
3330
bail!("Source directory specified, but path does not exist!");
3431
}
3532

3633
// build the runner
37-
Self::build_runner()?;
34+
Self::build_runner(common)?;
3835

3936
if !self.keep {
4037
// We remove the previous coverage files
41-
Self::clean_old_cov()?;
38+
Self::clean_old_cov(&cx)?;
4239
}
4340

4441
let input_path = PathBuf::from(
4542
self.input
4643
.display()
4744
.to_string()
4845
.replace("{ziggy_output}", &self.ziggy_output.display().to_string())
49-
.replace("{target_name}", &self.target),
46+
.replace("{target_name}", &cx.bin_target),
5047
);
5148

5249
let coverage_corpus = if input_path.is_dir() {
@@ -71,16 +68,16 @@ impl Cover {
7168
.display()
7269
.to_string()
7370
.replace("{ziggy_output}", &self.ziggy_output.display().to_string())
74-
.replace("{target_name}", &self.target);
71+
.replace("{target_name}", &cx.bin_target);
7572

7673
delete_dir_or_file(&coverage_dir)?;
7774

7875
// Get the absolute path for the coverage directory to ensure .profraw files
7976
// are created in the correct location, even in workspace scenarios
80-
let base_dir = super::target_dir().join("coverage/debug");
77+
let base_dir = cx.target_dir.join("coverage/debug");
8178
let coverage_target_dir = base_dir.join("deps");
8279
let cfg = Cfg::new(
83-
base_dir.join(&self.target),
80+
base_dir.join(&cx.bin_target),
8481
coverage_target_dir.join("coverage-%p-%m.profraw"),
8582
);
8683

@@ -93,7 +90,7 @@ impl Cover {
9390
.unwrap()
9491
.progress_chars("#>-"),
9592
);
96-
let log_dir = self.ziggy_output.join(format!("{}/logs", &self.target));
93+
let log_dir = self.ziggy_output.join(format!("{}/logs", &cx.bin_target));
9794
fs::create_dir_all(&log_dir)?;
9895
let log_file = std::sync::Mutex::new(std::fs::File::create(log_dir.join("coverage.log"))?);
9996
coverage_corpus.into_par_iter().for_each(|file| {
@@ -121,7 +118,7 @@ impl Cover {
121118
// We generate the code coverage report
122119
eprintln!("\n Generating coverage report");
123120
Self::run_grcov(
124-
&self.target,
121+
&cx,
125122
output_types,
126123
&coverage_dir,
127124
&source_or_workspace_root,
@@ -130,22 +127,25 @@ impl Cover {
130127
}
131128

132129
/// Build the runner with the appropriate flags for coverage
133-
pub fn build_runner() -> Result<(), anyhow::Error> {
134-
// The cargo executable
135-
let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
130+
pub fn build_runner(common: &Common) -> Result<(), anyhow::Error> {
131+
let target_dir = common.target_dir()?;
136132

137133
let mut coverage_rustflags =
138134
env::var("COVERAGE_RUSTFLAGS").unwrap_or_else(|_| "-Cinstrument-coverage".to_string());
139135
coverage_rustflags.push(' ');
140136
coverage_rustflags.push_str(&env::var("RUSTFLAGS").unwrap_or_default());
141-
let target_dir = format!("--target-dir={}", super::target_dir().join("coverage"));
142137

143-
let build = process::Command::new(&cargo)
144-
.args(["rustc", "--features=ziggy/coverage", &target_dir])
138+
let build = common
139+
.cargo()
140+
.args([
141+
"rustc",
142+
"--features=ziggy/coverage",
143+
&format!("--target-dir={}", target_dir.join("coverage")),
144+
])
145145
.env("RUSTFLAGS", coverage_rustflags)
146146
.env(
147147
"LLVM_PROFILE_FILE",
148-
super::target_dir().join("coverage/debug/deps/build-%p-%m.profraw"),
148+
target_dir.join("coverage/debug/deps/build-%p-%m.profraw"),
149149
)
150150
.spawn()
151151
.context("⚠️ couldn't spawn rustc for coverage")?
@@ -158,16 +158,16 @@ impl Cover {
158158
}
159159

160160
pub fn run_grcov(
161-
target: &str,
161+
cx: &Context,
162162
output_types: &str,
163163
coverage_dir: &str,
164164
source_or_workspace_root: &str,
165165
threads: Option<usize>,
166166
) -> Result<(), anyhow::Error> {
167167
let coverage = process::Command::new("grcov")
168168
.args([
169-
crate::target_dir().join("coverage/debug/deps").as_str(),
170-
&format!("-b={}/coverage/debug/{target}", super::target_dir()),
169+
cx.target_dir.join("coverage/debug/deps").as_str(),
170+
&format!("-b={}/coverage/debug/{}", cx.target_dir, cx.bin_target),
171171
&format!("-s={source_or_workspace_root}"),
172172
&format!("-t={output_types}"),
173173
"--llvm",
@@ -186,10 +186,9 @@ impl Cover {
186186
Ok(())
187187
}
188188

189-
pub fn clean_old_cov() -> Result<(), anyhow::Error> {
189+
pub fn clean_old_cov(cx: &Context) -> Result<(), anyhow::Error> {
190190
// Use absolute path to ensure we clean the correct location in workspaces
191-
let coverage_deps_dir = super::target_dir().join("coverage/debug/deps");
192-
let pattern = coverage_deps_dir.join("*.profraw");
191+
let pattern = cx.target_dir.join("*.profraw");
193192

194193
if let Ok(profile_files) = glob(pattern.as_str()) {
195194
for file in profile_files.flatten() {

0 commit comments

Comments
 (0)