Skip to content

Commit b8f25dd

Browse files
feat(cargo-codspeed): handle rustflags from .cargo/config.toml
1 parent 422c564 commit b8f25dd

File tree

4 files changed

+78
-11
lines changed

4 files changed

+78
-11
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ itertools = "0.14.0"
2020
serde = { version = "1.0.217", features = ["derive"] }
2121
serde_json = "1.0.138"
2222
tempfile = "3.7.0"
23+
semver = "1.0"

crates/cargo-codspeed/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ itertools = { workspace = true }
2626
anstyle = "1.0.8"
2727
serde = { workspace = true }
2828
serde_json = { workspace = true }
29+
semver = { workspace = true }
2930
codspeed = { path = "../codspeed", version = "=3.0.2" }
3031

3132
[dev-dependencies]

crates/cargo-codspeed/src/build.rs

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{
55
prelude::*,
66
};
77
use cargo_metadata::{camino::Utf8PathBuf, Message, Metadata, TargetKind};
8+
use semver::Version;
89
use std::process::{exit, Command, Stdio};
910

1011
struct BuildOptions<'a> {
@@ -105,15 +106,21 @@ impl BuildOptions<'_> {
105106
Ok(built_benches)
106107
}
107108

108-
/// Generates a subcommand to build the benchmarks by invoking cargo and forwarding the filters
109-
/// This command explicitly ignores the `self.benches`: all benches are built
110-
fn build_command(&self, measurement_mode: MeasurementMode) -> Command {
111-
let mut cargo = Command::new("cargo");
112-
cargo.args(["build", "--benches"]);
113-
114-
let mut rust_flags = std::env::var("RUSTFLAGS").unwrap_or_else(|_| "".into());
109+
/// Adds debug flags and codspeed compilation
110+
///
111+
/// If the user has set `RUSTFLAGS`, it will append the flags to it.
112+
/// Else, and if the cargo version allows it, it will set the cargo config through
113+
/// `--config 'build.rustflags=[ ... ]'`
114+
///
115+
/// # Why we do this
116+
/// As tracked in [https://github.com/rust-lang/cargo/issues/5376], setting `RUSTFLAGS`
117+
/// completely overrides rustflags from rust config
118+
/// We use the cargo built-in config mechanism to set the flags if the user has not set
119+
/// `RUSTFLAGS`.
120+
fn add_rust_flags(&self, cargo: &mut Command, measurement_mode: MeasurementMode) {
115121
// Add debug info (equivalent to -g)
116-
rust_flags.push_str(" -C debuginfo=2");
122+
let mut flags = vec!["-C".to_string()];
123+
flags.push("debuginfo=2".to_string());
117124

118125
// Prevent debug info stripping
119126
// https://doc.rust-lang.org/cargo/reference/profiles.html#release
@@ -122,13 +129,70 @@ impl BuildOptions<'_> {
122129
// In practice, if we set debug info through RUSTFLAGS, cargo still strips them, most
123130
// likely because debug = false in the release profile.
124131
// We also need to disable stripping through rust flags.
125-
rust_flags.push_str(" -C strip=none");
132+
flags.push("-C".to_string());
133+
flags.push("strip=none".to_string());
126134

127135
// Add the codspeed cfg flag if instrumentation mode is enabled
128136
if measurement_mode == MeasurementMode::Instrumentation {
129-
rust_flags.push_str(" --cfg codspeed");
137+
flags.push("--cfg".to_string());
138+
flags.push("codspeed".to_string());
139+
}
140+
141+
match std::env::var("RUSTFLAGS") {
142+
std::result::Result::Ok(existing_rustflags) => {
143+
// If RUSTFLAGS is set, append our flags to it
144+
let mut combined_flags = existing_rustflags;
145+
for flag in flags {
146+
combined_flags.push(' ');
147+
combined_flags.push_str(&flag);
148+
}
149+
cargo.env("RUSTFLAGS", combined_flags);
150+
}
151+
std::result::Result::Err(_) => {
152+
// Check if cargo version supports --config (Cargo 1.63+, 2022-08-11)
153+
if Self::cargo_supports_config_from_cli() {
154+
// Use --config to set rustflags
155+
let config_value = format!(
156+
"build.rustflags=[{}]",
157+
flags.into_iter().map(|f| format!("\"{f}\"")).join(",")
158+
);
159+
cargo.arg("--config").arg(config_value);
160+
} else {
161+
// Fallback to RUSTFLAGS for older cargo versions
162+
let rustflags = flags.join(" ");
163+
cargo.env("RUSTFLAGS", rustflags);
164+
}
165+
}
130166
}
131-
cargo.env("RUSTFLAGS", rust_flags);
167+
}
168+
169+
/// Check if cargo version supports --config flag (Cargo 1.63+)
170+
/// [https://doc.rust-lang.org/nightly/cargo/CHANGELOG.html#cargo-163-2022-08-11]
171+
fn cargo_supports_config_from_cli() -> bool {
172+
let output = Command::new("cargo").arg("--version").output();
173+
174+
if let std::result::Result::Ok(output) = output {
175+
if let std::result::Result::Ok(version_str) = String::from_utf8(output.stdout) {
176+
// Parse version string like "cargo 1.70.0 (7fe40dc9c 2023-04-27)"
177+
if let Some(version_part) = version_str.split_whitespace().nth(1) {
178+
if let std::result::Result::Ok(version) = Version::parse(version_part) {
179+
// Cargo 1.63.0 introduced --config support
180+
return version >= Version::new(1, 63, 0);
181+
}
182+
}
183+
}
184+
}
185+
186+
false
187+
}
188+
189+
/// Generates a subcommand to build the benchmarks by invoking cargo and forwarding the filters
190+
/// This command explicitly ignores the `self.benches`: all benches are built
191+
fn build_command(&self, measurement_mode: MeasurementMode) -> Command {
192+
let mut cargo = Command::new("cargo");
193+
cargo.args(["build", "--benches"]);
194+
195+
self.add_rust_flags(&mut cargo, measurement_mode);
132196

133197
if let Some(features) = self.features {
134198
cargo.arg("--features").arg(features.join(","));

0 commit comments

Comments
 (0)