@@ -4,7 +4,9 @@ use crate::{
44 measurement_mode:: MeasurementMode ,
55 prelude:: * ,
66} ;
7+ use anyhow:: Context ;
78use cargo_metadata:: { camino:: Utf8PathBuf , Message , Metadata , TargetKind } ;
9+ use std:: collections:: HashMap ;
810use std:: process:: { exit, Command , Stdio } ;
911
1012struct BuildOptions < ' a > {
@@ -31,6 +33,50 @@ pub struct BuildConfig {
3133 pub passthrough_flags : Vec < String > ,
3234}
3335
36+ fn get_bench_harness_value (
37+ manifest_path : & Utf8PathBuf ,
38+ bench_name : & str ,
39+ cache : & mut HashMap < Utf8PathBuf , toml:: Table > ,
40+ ) -> Result < bool > {
41+ let manifest_table = if let Some ( table) = cache. get ( manifest_path) {
42+ table
43+ } else {
44+ // Read and parse the Cargo.toml file
45+ let manifest_content = std:: fs:: read_to_string ( manifest_path)
46+ . with_context ( || format ! ( "Failed to read manifest at {manifest_path}" ) ) ?;
47+ let table: toml:: Table = toml:: from_str ( & manifest_content)
48+ . with_context ( || format ! ( "Failed to parse TOML in {manifest_path}" ) ) ?;
49+ cache. insert ( manifest_path. clone ( ) , table) ;
50+ cache. get ( manifest_path) . unwrap ( )
51+ } ;
52+
53+ // Look for [[bench]] sections
54+ let Some ( benches) = manifest_table. get ( "bench" ) . and_then ( |v| v. as_array ( ) ) else {
55+ // If no [[bench]] sections, it's not an error, benches present in <root>/benches/<name>.rs
56+ // are still collected with harness = true
57+ return Ok ( true ) ;
58+ } ;
59+
60+ // Find the bench entry with matching name
61+ let matching_bench = benches
62+ . iter ( )
63+ . filter_map ( |bench| bench. as_table ( ) )
64+ . find ( |bench_table| {
65+ bench_table
66+ . get ( "name" )
67+ . and_then ( |v| v. as_str ( ) )
68+ . is_some_and ( |name| name == bench_name)
69+ } ) ;
70+
71+ // Check if harness is enabled (defaults to true)
72+ let harness_enabled = matching_bench
73+ . and_then ( |bench_table| bench_table. get ( "harness" ) )
74+ . and_then ( |v| v. as_bool ( ) )
75+ . unwrap_or ( true ) ;
76+
77+ Ok ( harness_enabled)
78+ }
79+
3480impl BuildOptions < ' _ > {
3581 /// Builds the benchmarks by invoking cargo
3682 /// Returns a list of built benchmarks, with path to associated executables
@@ -60,6 +106,8 @@ impl BuildOptions<'_> {
60106 ) ;
61107
62108 let mut built_benches = Vec :: new ( ) ;
109+ let mut bench_targets_with_default_harness = Vec :: new ( ) ;
110+ let mut manifest_cache = HashMap :: new ( ) ;
63111
64112 let package_names = self
65113 . package_filters
@@ -95,6 +143,15 @@ impl BuildOptions<'_> {
95143 let add_bench_to_codspeed_dir = package_names. iter ( ) . contains ( & package. name ) ;
96144
97145 if add_bench_to_codspeed_dir {
146+ if get_bench_harness_value (
147+ & package. manifest_path ,
148+ & bench_target_name,
149+ & mut manifest_cache,
150+ ) ? {
151+ bench_targets_with_default_harness
152+ . push ( ( package. name . to_string ( ) , bench_target_name. clone ( ) ) ) ;
153+ }
154+
98155 built_benches. push ( BuiltBench {
99156 package : package. name . to_string ( ) ,
100157 bench : bench_target_name,
@@ -114,6 +171,25 @@ impl BuildOptions<'_> {
114171 exit ( status. code ( ) . expect ( "Could not get exit code" ) ) ;
115172 }
116173
174+ if !bench_targets_with_default_harness. is_empty ( ) {
175+ let targets_list = bench_targets_with_default_harness
176+ . into_iter ( )
177+ . map ( |( package, bench) | format ! ( " - `{bench}` in package `{package}`" ) )
178+ . join ( "\n " ) ;
179+
180+ bail ! ( "\
181+ CodSpeed will not work with the following benchmark targets:
182+ {targets_list}
183+
184+ CodSpeed requires benchmark targets to disable the default test harness because benchmark frameworks handle harnessing themselves.
185+
186+ Either disable the default harness by adding `harness = false` to the corresponding \
187+ `[[bench]]` section in the Cargo.toml, or specify which targets to build by using \
188+ `cargo codspeed build -p package_name --bench first_target --bench second_target`.
189+
190+ See `cargo codspeed build --help` for more information." ) ;
191+ }
192+
117193 for built_bench in & built_benches {
118194 eprintln ! (
119195 "Built benchmark `{}` in package `{}`" ,
0 commit comments