@@ -5,6 +5,7 @@ use crate::{
55 prelude:: * ,
66} ;
77use cargo_metadata:: { camino:: Utf8PathBuf , Message , Metadata , TargetKind } ;
8+ use semver:: Version ;
89use std:: process:: { exit, Command , Stdio } ;
910
1011struct BuildOptions < ' a > {
@@ -105,15 +106,23 @@ 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" ] ) ;
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 ) {
121+ let mut flags = Vec :: new ( ) ;
113122
114- let mut rust_flags = std:: env:: var ( "RUSTFLAGS" ) . unwrap_or_else ( |_| "" . into ( ) ) ;
115123 // Add debug info (equivalent to -g)
116- rust_flags. push_str ( " -C debuginfo=2" ) ;
124+ flags. push ( "-C" . to_string ( ) ) ;
125+ flags. push ( "debuginfo=2" . to_string ( ) ) ;
117126
118127 // Prevent debug info stripping
119128 // https://doc.rust-lang.org/cargo/reference/profiles.html#release
@@ -122,13 +131,70 @@ impl BuildOptions<'_> {
122131 // In practice, if we set debug info through RUSTFLAGS, cargo still strips them, most
123132 // likely because debug = false in the release profile.
124133 // We also need to disable stripping through rust flags.
125- rust_flags. push_str ( " -C strip=none" ) ;
134+ flags. push ( "-C" . to_string ( ) ) ;
135+ flags. push ( "strip=none" . to_string ( ) ) ;
126136
127137 // Add the codspeed cfg flag if instrumentation mode is enabled
128138 if measurement_mode == MeasurementMode :: Instrumentation {
129- rust_flags. push_str ( " --cfg codspeed" ) ;
139+ flags. push ( "--cfg" . to_string ( ) ) ;
140+ flags. push ( "codspeed" . to_string ( ) ) ;
141+ }
142+
143+ match std:: env:: var ( "RUSTFLAGS" ) {
144+ std:: result:: Result :: Ok ( existing_rustflags) => {
145+ // If RUSTFLAGS is set, append our flags to it
146+ let mut combined_flags = existing_rustflags;
147+ for flag in flags {
148+ combined_flags. push ( ' ' ) ;
149+ combined_flags. push_str ( & flag) ;
150+ }
151+ cargo. env ( "RUSTFLAGS" , combined_flags) ;
152+ }
153+ std:: result:: Result :: Err ( _) => {
154+ // Check if cargo version supports --config (Cargo 1.63+, 2022-08-11)
155+ if Self :: cargo_supports_config_from_cli ( ) {
156+ // Use --config to set rustflags
157+ let config_value = format ! (
158+ "build.rustflags=[{}]" ,
159+ flags. into_iter( ) . map( |f| format!( "\" {f}\" " ) ) . join( "," )
160+ ) ;
161+ cargo. arg ( "--config" ) . arg ( config_value) ;
162+ } else {
163+ // Fallback to RUSTFLAGS for older cargo versions
164+ let rustflags = flags. join ( " " ) ;
165+ cargo. env ( "RUSTFLAGS" , rustflags) ;
166+ }
167+ }
168+ }
169+ }
170+
171+ /// Check if cargo version supports --config flag (Cargo 1.63+)
172+ /// [https://doc.rust-lang.org/nightly/cargo/CHANGELOG.html#cargo-163-2022-08-11]
173+ fn cargo_supports_config_from_cli ( ) -> bool {
174+ let output = Command :: new ( "cargo" ) . arg ( "--version" ) . output ( ) ;
175+
176+ if let std:: result:: Result :: Ok ( output) = output {
177+ if let std:: result:: Result :: Ok ( version_str) = String :: from_utf8 ( output. stdout ) {
178+ // Parse version string like "cargo 1.70.0 (7fe40dc9c 2023-04-27)"
179+ if let Some ( version_part) = version_str. split_whitespace ( ) . nth ( 1 ) {
180+ if let std:: result:: Result :: Ok ( version) = Version :: parse ( version_part) {
181+ // Cargo 1.63.0 introduced --config support
182+ return version >= Version :: new ( 1 , 63 , 0 ) ;
183+ }
184+ }
185+ }
130186 }
131- cargo. env ( "RUSTFLAGS" , rust_flags) ;
187+
188+ false
189+ }
190+
191+ /// Generates a subcommand to build the benchmarks by invoking cargo and forwarding the filters
192+ /// This command explicitly ignores the `self.benches`: all benches are built
193+ fn build_command ( & self , measurement_mode : MeasurementMode ) -> Command {
194+ let mut cargo = Command :: new ( "cargo" ) ;
195+ cargo. args ( [ "build" , "--benches" ] ) ;
196+
197+ self . add_rust_flags ( & mut cargo, measurement_mode) ;
132198
133199 if let Some ( features) = self . features {
134200 cargo. arg ( "--features" ) . arg ( features. join ( "," ) ) ;
0 commit comments