@@ -8,10 +8,20 @@ use std::path::PathBuf;
88use std:: process:: Command ;
99use std:: sync:: Once ;
1010
11+ use std:: sync:: Mutex ;
12+
1113static INIT : Once = Once :: new ( ) ;
1214static COMPILE : Once = Once :: new ( ) ;
1315static REGISTER_CLEANUP : Once = Once :: new ( ) ;
1416
17+ lazy_static ! {
18+ static ref COMPILE_DEBUG_RESULT : Mutex <Option <anyhow:: Result <( ) >>> = Mutex :: new( None ) ;
19+ static ref COMPILE_OPT_RESULT : Mutex <Option <anyhow:: Result <( ) >>> = Mutex :: new( None ) ;
20+ static ref COMPILE_COMPLEX_DEBUG_RESULT : Mutex <Option <anyhow:: Result <( ) >>> = Mutex :: new( None ) ;
21+ static ref COMPILE_COMPLEX_OPT_RESULT : Mutex <Option <anyhow:: Result <( ) >>> = Mutex :: new( None ) ;
22+ static ref COMPILE_COMPLEX_NOPIE_RESULT : Mutex <Option <anyhow:: Result <( ) >>> = Mutex :: new( None ) ;
23+ }
24+
1525/// Initialize logging for tests (call once per test)
1626pub fn init ( ) {
1727 INIT . call_once ( || {
@@ -94,146 +104,145 @@ pub fn ensure_test_program_compiled() -> anyhow::Result<()> {
94104
95105/// Compile test program with specific optimization level
96106pub fn ensure_test_program_compiled_with_opt ( opt_level : OptimizationLevel ) -> anyhow:: Result < ( ) > {
97- let mut result = Ok ( ( ) ) ;
98-
99- let compile_fn = || {
100- let fixtures_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "tests/fixtures" ) ;
101- let sample_program_dir = fixtures_path. join ( "sample_program" ) ;
102-
103- println ! (
104- "Compiling sample_program {} in {:?}" ,
105- opt_level. description( ) ,
106- sample_program_dir
107- ) ;
108-
109- // Clean first (only for debug builds to avoid conflicts)
110- if opt_level == OptimizationLevel :: Debug {
111- let clean_output = Command :: new ( "make" )
112- . arg ( "clean" )
113- . current_dir ( & sample_program_dir)
114- . output ( ) ;
115-
116- match clean_output {
117- Ok ( _) => println ! ( "✓ Cleaned sample_program build directory" ) ,
118- Err ( e) => {
119- result = Err ( anyhow:: anyhow!( "Failed to clean sample_program: {}" , e) ) ;
120- return ;
121- }
122- }
123- }
124-
125- // Compile specific optimization level
126- let compile_output = Command :: new ( "make" )
127- . arg ( opt_level. as_make_target ( ) )
128- . current_dir ( & sample_program_dir)
129- . output ( ) ;
130-
131- match compile_output {
132- Ok ( output) => {
133- if output. status . success ( ) {
134- println ! (
135- "✓ Successfully compiled sample_program {}" ,
136- opt_level. description( )
137- ) ;
138- } else {
139- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
140- result = Err ( anyhow:: anyhow!(
141- "Failed to compile sample_program {}: {}" ,
142- opt_level. description( ) ,
143- stderr
144- ) ) ;
145- }
146- }
147- Err ( e) => {
148- result = Err ( anyhow:: anyhow!(
149- "Failed to run make for sample_program {}: {}" ,
150- opt_level. description( ) ,
151- e
152- ) ) ;
153- }
154- }
155- } ;
156-
157107 match opt_level {
158108 OptimizationLevel :: Debug => {
159- COMPILE . call_once ( compile_fn) ;
109+ COMPILE . call_once ( || {
110+ let compile_result = compile_sample_program ( opt_level) ;
111+ * COMPILE_DEBUG_RESULT . lock ( ) . unwrap ( ) = Some ( compile_result) ;
112+ } ) ;
113+ match COMPILE_DEBUG_RESULT . lock ( ) . unwrap ( ) . as_ref ( ) {
114+ Some ( Ok ( ( ) ) ) => Ok ( ( ) ) ,
115+ Some ( Err ( e) ) => Err ( anyhow:: anyhow!( "{}" , e) ) ,
116+ None => panic ! ( "Compilation result should be set after call_once" ) ,
117+ }
160118 }
161119 _ => {
162- COMPILE_OPTIMIZED . call_once ( compile_fn) ;
120+ COMPILE_OPTIMIZED . call_once ( || {
121+ let compile_result = compile_sample_program ( opt_level) ;
122+ * COMPILE_OPT_RESULT . lock ( ) . unwrap ( ) = Some ( compile_result) ;
123+ } ) ;
124+ match COMPILE_OPT_RESULT . lock ( ) . unwrap ( ) . as_ref ( ) {
125+ Some ( Ok ( ( ) ) ) => Ok ( ( ) ) ,
126+ Some ( Err ( e) ) => Err ( anyhow:: anyhow!( "{}" , e) ) ,
127+ None => panic ! ( "Compilation result should be set after call_once" ) ,
128+ }
163129 }
164130 }
131+ }
165132
166- result
133+ fn compile_sample_program ( opt_level : OptimizationLevel ) -> anyhow:: Result < ( ) > {
134+ let fixtures_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "tests/fixtures" ) ;
135+ let sample_program_dir = fixtures_path. join ( "sample_program" ) ;
136+
137+ println ! (
138+ "Compiling sample_program {} in {:?}" ,
139+ opt_level. description( ) ,
140+ sample_program_dir
141+ ) ;
142+
143+ // Compile specific optimization level
144+ let output = Command :: new ( "make" )
145+ . arg ( opt_level. as_make_target ( ) )
146+ . current_dir ( & sample_program_dir)
147+ . output ( )
148+ . map_err ( |e| {
149+ anyhow:: anyhow!(
150+ "Failed to run make for sample_program {}: {}" ,
151+ opt_level. description( ) ,
152+ e
153+ )
154+ } ) ?;
155+
156+ if output. status . success ( ) {
157+ println ! (
158+ "✓ Successfully compiled sample_program {}" ,
159+ opt_level. description( )
160+ ) ;
161+ Ok ( ( ) )
162+ } else {
163+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
164+ Err ( anyhow:: anyhow!(
165+ "Failed to compile sample_program {}: {}" ,
166+ opt_level. description( ) ,
167+ stderr
168+ ) )
169+ }
167170}
168171
169172static COMPILE_COMPLEX_DEBUG : Once = Once :: new ( ) ;
170173static COMPILE_COMPLEX_OPT : Once = Once :: new ( ) ;
171174static COMPILE_COMPLEX_NOPIE : Once = Once :: new ( ) ;
172175
173176fn ensure_complex_program_compiled_with_opt ( opt_level : OptimizationLevel ) -> anyhow:: Result < ( ) > {
174- let mut result = Ok ( ( ) ) ;
175- let compile_fn = || {
176- let fixtures_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "tests/fixtures" ) ;
177- let program_dir = fixtures_path. join ( "complex_types_program" ) ;
178-
179- println ! (
180- "Compiling complex_types_program {} in {:?}" ,
181- opt_level. description( ) ,
182- program_dir
183- ) ;
184-
185- // Clean first for debug builds
186- if opt_level == OptimizationLevel :: Debug {
187- let _ = Command :: new ( "make" )
188- . arg ( "clean" )
189- . current_dir ( & program_dir)
190- . output ( ) ;
191- }
192-
193- let target = match opt_level {
194- OptimizationLevel :: Debug => "complex_types_program" ,
195- OptimizationLevel :: O1 => "complex_types_program_o1" ,
196- OptimizationLevel :: O2 => "complex_types_program_o2" ,
197- OptimizationLevel :: O3 => "complex_types_program_o3" ,
198- } ;
199-
200- let compile_output = Command :: new ( "make" )
201- . arg ( target)
202- . current_dir ( & program_dir)
203- . output ( ) ;
204-
205- match compile_output {
206- Ok ( output) => {
207- if output. status . success ( ) {
208- println ! (
209- "✓ Successfully compiled complex_types_program {}" ,
210- opt_level. description( )
211- ) ;
212- } else {
213- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
214- result = Err ( anyhow:: anyhow!(
215- "Failed to compile complex_types_program {}: {}" ,
216- opt_level. description( ) ,
217- stderr
218- ) ) ;
219- }
177+ match opt_level {
178+ OptimizationLevel :: Debug => {
179+ COMPILE_COMPLEX_DEBUG . call_once ( || {
180+ let compile_result = compile_complex_program ( opt_level) ;
181+ * COMPILE_COMPLEX_DEBUG_RESULT . lock ( ) . unwrap ( ) = Some ( compile_result) ;
182+ } ) ;
183+ match COMPILE_COMPLEX_DEBUG_RESULT . lock ( ) . unwrap ( ) . as_ref ( ) {
184+ Some ( Ok ( ( ) ) ) => Ok ( ( ) ) ,
185+ Some ( Err ( e) ) => Err ( anyhow:: anyhow!( "{}" , e) ) ,
186+ None => panic ! ( "Compilation result should be set after call_once" ) ,
220187 }
221- Err ( e) => {
222- result = Err ( anyhow:: anyhow!(
223- "Failed to run make for complex_types_program {}: {}" ,
224- opt_level. description( ) ,
225- e
226- ) ) ;
188+ }
189+ _ => {
190+ COMPILE_COMPLEX_OPT . call_once ( || {
191+ let compile_result = compile_complex_program ( opt_level) ;
192+ * COMPILE_COMPLEX_OPT_RESULT . lock ( ) . unwrap ( ) = Some ( compile_result) ;
193+ } ) ;
194+ match COMPILE_COMPLEX_OPT_RESULT . lock ( ) . unwrap ( ) . as_ref ( ) {
195+ Some ( Ok ( ( ) ) ) => Ok ( ( ) ) ,
196+ Some ( Err ( e) ) => Err ( anyhow:: anyhow!( "{}" , e) ) ,
197+ None => panic ! ( "Compilation result should be set after call_once" ) ,
227198 }
228199 }
200+ }
201+ }
202+
203+ fn compile_complex_program ( opt_level : OptimizationLevel ) -> anyhow:: Result < ( ) > {
204+ let fixtures_path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "tests/fixtures" ) ;
205+ let program_dir = fixtures_path. join ( "complex_types_program" ) ;
206+
207+ println ! (
208+ "Compiling complex_types_program {} in {:?}" ,
209+ opt_level. description( ) ,
210+ program_dir
211+ ) ;
212+
213+ let target = match opt_level {
214+ OptimizationLevel :: Debug => "complex_types_program" ,
215+ OptimizationLevel :: O1 => "complex_types_program_o1" ,
216+ OptimizationLevel :: O2 => "complex_types_program_o2" ,
217+ OptimizationLevel :: O3 => "complex_types_program_o3" ,
229218 } ;
230219
231- match opt_level {
232- OptimizationLevel :: Debug => COMPILE_COMPLEX_DEBUG . call_once ( compile_fn) ,
233- _ => COMPILE_COMPLEX_OPT . call_once ( compile_fn) ,
220+ let output = Command :: new ( "make" )
221+ . arg ( target)
222+ . current_dir ( & program_dir)
223+ . output ( )
224+ . map_err ( |e| {
225+ anyhow:: anyhow!(
226+ "Failed to run make for complex_types_program {}: {}" ,
227+ opt_level. description( ) ,
228+ e
229+ )
230+ } ) ?;
231+
232+ if output. status . success ( ) {
233+ println ! (
234+ "✓ Successfully compiled complex_types_program {}" ,
235+ opt_level. description( )
236+ ) ;
237+ Ok ( ( ) )
238+ } else {
239+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
240+ Err ( anyhow:: anyhow!(
241+ "Failed to compile complex_types_program {}: {}" ,
242+ opt_level. description( ) ,
243+ stderr
244+ ) )
234245 }
235-
236- result
237246}
238247
239248/// Test fixtures manager
@@ -289,43 +298,48 @@ impl TestFixtures {
289298
290299 /// Build and return the non-PIE variant of complex_types_program
291300 pub fn get_test_binary_complex_nopie ( & self ) -> anyhow:: Result < PathBuf > {
292- // Ensure build once
293301 let program_dir = self . base_path . join ( "complex_types_program" ) ;
294- let mut result = Ok ( ( ) ) ;
302+
295303 COMPILE_COMPLEX_NOPIE . call_once ( || {
296- println ! (
297- "Compiling complex_types_program Non-PIE (ET_EXEC) in {:?}" ,
298- program_dir
299- ) ;
300- let _ = Command :: new ( "make" )
301- . arg ( "clean" )
302- . current_dir ( & program_dir)
303- . output ( ) ;
304- let compile_output = Command :: new ( "make" )
305- . arg ( "complex_types_program_nopie" )
306- . current_dir ( & program_dir)
307- . output ( ) ;
308- match compile_output {
309- Ok ( out) => {
310- if out. status . success ( ) {
311- println ! ( "✓ Successfully compiled complex_types_program Non-PIE" ) ;
312- } else {
313- let stderr = String :: from_utf8_lossy ( & out. stderr ) ;
314- result = Err ( anyhow:: anyhow!(
315- "Failed to compile complex_types_program Non-PIE: {}" ,
316- stderr
317- ) ) ;
318- }
319- }
320- Err ( e) => {
321- result = Err ( anyhow:: anyhow!(
322- "Failed to run make for complex_types_program Non-PIE: {}" ,
323- e
324- ) ) ;
304+ let compile_result = ( || -> anyhow:: Result < ( ) > {
305+ println ! (
306+ "Compiling complex_types_program Non-PIE (ET_EXEC) in {:?}" ,
307+ program_dir
308+ ) ;
309+
310+ let output = Command :: new ( "make" )
311+ . arg ( "complex_types_program_nopie" )
312+ . current_dir ( & program_dir)
313+ . output ( )
314+ . map_err ( |e| {
315+ anyhow:: anyhow!(
316+ "Failed to run make for complex_types_program Non-PIE: {}" ,
317+ e
318+ )
319+ } ) ?;
320+
321+ if output. status . success ( ) {
322+ println ! ( "✓ Successfully compiled complex_types_program Non-PIE" ) ;
323+ Ok ( ( ) )
324+ } else {
325+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
326+ Err ( anyhow:: anyhow!(
327+ "Failed to compile complex_types_program Non-PIE: {}" ,
328+ stderr
329+ ) )
325330 }
326- }
331+ } ) ( ) ;
332+
333+ * COMPILE_COMPLEX_NOPIE_RESULT . lock ( ) . unwrap ( ) = Some ( compile_result) ;
327334 } ) ;
328- result?;
335+
336+ // Check compilation result
337+ match COMPILE_COMPLEX_NOPIE_RESULT . lock ( ) . unwrap ( ) . as_ref ( ) {
338+ Some ( Ok ( ( ) ) ) => { }
339+ Some ( Err ( e) ) => return Err ( anyhow:: anyhow!( "{}" , e) ) ,
340+ None => panic ! ( "Compilation result should be set after call_once" ) ,
341+ }
342+
329343 let bin_path = program_dir. join ( "complex_types_program_nopie" ) ;
330344 if !bin_path. exists ( ) {
331345 anyhow:: bail!( "Non-PIE binary not found: {}" , bin_path. display( ) ) ;
0 commit comments