@@ -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,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