@@ -10,6 +10,9 @@ use std::os::unix::ffi::OsStrExt;
1010use std:: os:: unix:: process:: ExitStatusExt ;
1111use std:: path:: Path ;
1212use std:: process:: ExitStatus ;
13+ use std:: sync:: Once ;
14+
15+ static BUILD_ONCE : Once = Once :: new ( ) ;
1316
1417fn init ( ) {
1518 let _ = env_logger:: builder ( )
@@ -71,22 +74,54 @@ fn run_command(input: &Path) -> std::process::Output {
7174 }
7275 b"args" => {
7376 let args = input_string;
74- let _cargo_build_output = std:: process:: Command :: new ( "cargo" )
75- . arg ( "build" )
76- . output ( )
77- . unwrap ( ) ;
77+
78+ // Get the workspace root from CARGO_MANIFEST_DIR (set at compile time)
79+ // CARGO_MANIFEST_DIR points to the m4 crate directory, so parent is workspace root
80+ let manifest_dir = env ! ( "CARGO_MANIFEST_DIR" ) ;
81+ let workspace_root = std:: path:: Path :: new ( manifest_dir)
82+ . parent ( )
83+ . expect ( "m4 crate should have parent directory" ) ;
7884
7985 // Determine the target directory - cargo-llvm-cov uses a custom target dir
8086 let target_dir = std:: env:: var ( "CARGO_TARGET_DIR" )
8187 . or_else ( |_| std:: env:: var ( "CARGO_LLVM_COV_TARGET_DIR" ) )
8288 . unwrap_or_else ( |_| String :: from ( "target" ) ) ;
83- let m4_path = format ! ( "../{}/debug/m4" , target_dir) ;
8489
90+ // Check for release binary first (if running release tests), then debug
91+ let release_path = workspace_root. join ( & target_dir) . join ( "release" ) . join ( "m4" ) ;
92+ let debug_path = workspace_root. join ( & target_dir) . join ( "debug" ) . join ( "m4" ) ;
93+
94+ let m4_path = if release_path. exists ( ) {
95+ release_path
96+ } else {
97+ // Build debug binary if release doesn't exist
98+ // Use Once to ensure cargo build runs only once, avoiding race conditions
99+ // when multiple .args tests run in parallel
100+ BUILD_ONCE . call_once ( || {
101+ let cargo_build_output = std:: process:: Command :: new ( "cargo" )
102+ . arg ( "build" )
103+ . arg ( "-p" )
104+ . arg ( "posixutils-m4" )
105+ . current_dir ( workspace_root)
106+ . output ( )
107+ . unwrap ( ) ;
108+ if !cargo_build_output. status . success ( ) {
109+ panic ! (
110+ "cargo build failed: {}" ,
111+ String :: from_utf8_lossy( & cargo_build_output. stderr)
112+ ) ;
113+ }
114+ } ) ;
115+ debug_path
116+ } ;
117+
118+ log:: info!( "Using m4 binary at: {}" , m4_path. display( ) ) ;
85119 log:: info!( "RUST_LOG is ignored for this test because it interferes with output" ) ;
86120 let output = std:: process:: Command :: new ( "sh" )
87121 . env ( "RUST_LOG" , "" ) // Disable rust log output because it interferes with the test.
88122 . arg ( "-c" )
89- . arg ( format ! ( "{m4_path} {args}" ) )
123+ . arg ( format ! ( "{} {args}" , m4_path. display( ) ) )
124+ . current_dir ( manifest_dir)
90125 . output ( )
91126 . unwrap ( ) ;
92127
0 commit comments