@@ -35,7 +35,11 @@ lazy_static! {
3535 Mutex :: new( None ) ;
3636 static ref COMPILE_INLINE_CALL_VALUE_RESULT : Mutex <Option <anyhow:: Result <( ) >>> =
3737 Mutex :: new( None ) ;
38- static ref COMPILE_PARTITIONED_RANGES_RESULT : Mutex <Option <anyhow:: Result <( ) >>> =
38+ static ref COMPILE_PARTITIONED_RANGES_DEFAULT_RESULT : Mutex <Option <anyhow:: Result <( ) >>> =
39+ Mutex :: new( None ) ;
40+ static ref COMPILE_PARTITIONED_RANGES_GCC_DWARF5_FUNCTION_SECTIONS_RESULT : Mutex <Option <anyhow:: Result <( ) >>> =
41+ Mutex :: new( None ) ;
42+ static ref COMPILE_PARTITIONED_RANGES_CLANG_DWARF5_RNGLISTX_RESULT : Mutex <Option <anyhow:: Result <( ) >>> =
3943 Mutex :: new( None ) ;
4044 static ref COMPILE_CPP_COMPLEX_RESULT : Mutex <Option <anyhow:: Result <( ) >>> = Mutex :: new( None ) ;
4145 static ref COMPILE_STATIC_SCOPE_DEFAULT_RESULT : Mutex <Option <anyhow:: Result <( ) >>> =
@@ -211,6 +215,8 @@ pub fn init() {
211215 let _ = OptimizationLevel :: Stripped ;
212216 let _ = FixtureCompiler :: Default ;
213217 let _ = FixtureCompiler :: ClangDwarf5 ;
218+ let _ = FixtureCompiler :: GccDwarf5FunctionSections ;
219+ let _ = FixtureCompiler :: ClangDwarf5Rnglistx ;
214220
215221 // Exercise runner builder methods so they are referenced in all bins.
216222 let _ = runner:: GhostscopeRunner :: new ( )
@@ -257,13 +263,17 @@ pub enum OptimizationLevel {
257263pub enum FixtureCompiler {
258264 Default ,
259265 ClangDwarf5 ,
266+ GccDwarf5FunctionSections ,
267+ ClangDwarf5Rnglistx ,
260268}
261269
262270impl FixtureCompiler {
263271 pub ( crate ) fn binary_name ( & self , base : & str ) -> String {
264272 match self {
265273 FixtureCompiler :: Default => base. to_string ( ) ,
266274 FixtureCompiler :: ClangDwarf5 => format ! ( "{base}_clang_dwarf5" ) ,
275+ FixtureCompiler :: GccDwarf5FunctionSections => format ! ( "{base}_gcc_dwarf5_sections" ) ,
276+ FixtureCompiler :: ClangDwarf5Rnglistx => format ! ( "{base}_clang_dwarf5_rnglistx" ) ,
267277 }
268278 }
269279
@@ -275,18 +285,30 @@ impl FixtureCompiler {
275285 match self {
276286 FixtureCompiler :: Default => "default toolchain" ,
277287 FixtureCompiler :: ClangDwarf5 => "clang -gdwarf-5" ,
288+ FixtureCompiler :: GccDwarf5FunctionSections => "gcc -gdwarf-5 -ffunction-sections" ,
289+ FixtureCompiler :: ClangDwarf5Rnglistx => {
290+ "clang -gdwarf-5 -ffunction-sections -fbasic-block-sections=all"
291+ }
278292 }
279293 }
280294
281- fn apply_to_c_make ( & self , cmd : & mut Command , base : & str , clang_dwarf5_cflags : & str ) {
295+ fn apply_to_c_make ( & self , cmd : & mut Command , base : & str , compiler_cflags : & str ) {
282296 cmd. arg ( "all" )
283297 . arg ( format ! ( "BINARY={}" , self . binary_name( base) ) )
284298 . arg ( format ! ( "OBJ={}" , self . object_name( base) ) ) ;
285299
286- if matches ! ( self , FixtureCompiler :: ClangDwarf5 ) {
287- let clang = preferred_clang_binary ( ) . unwrap_or ( "clang" ) ;
288- cmd. arg ( format ! ( "CC={clang}" ) )
289- . arg ( format ! ( "CFLAGS={clang_dwarf5_cflags}" ) ) ;
300+ match self {
301+ FixtureCompiler :: Default => { }
302+ FixtureCompiler :: ClangDwarf5 | FixtureCompiler :: ClangDwarf5Rnglistx => {
303+ let clang = preferred_clang_binary ( ) . unwrap_or_else ( || "clang" . to_string ( ) ) ;
304+ cmd. arg ( format ! ( "CC={clang}" ) )
305+ . arg ( format ! ( "CFLAGS={compiler_cflags}" ) ) ;
306+ }
307+ FixtureCompiler :: GccDwarf5FunctionSections => {
308+ let gcc = preferred_gcc_binary ( ) . unwrap_or_else ( || "gcc" . to_string ( ) ) ;
309+ cmd. arg ( format ! ( "CC={gcc}" ) )
310+ . arg ( format ! ( "CFLAGS={compiler_cflags}" ) ) ;
311+ }
290312 }
291313 }
292314}
@@ -377,8 +399,8 @@ impl RegisteredFixture {
377399 Ok ( dir. join ( "inline_call_value_program" ) )
378400 }
379401 RegisteredFixtureKind :: PartitionedRanges => {
380- ensure_partitioned_ranges_program_compiled ( ) ?;
381- Ok ( dir. join ( "partitioned_ranges_program" ) )
402+ ensure_partitioned_ranges_program_compiled ( FixtureCompiler :: Default ) ?;
403+ Ok ( dir. join ( FixtureCompiler :: Default . binary_name ( self . name ) ) )
382404 }
383405 RegisteredFixtureKind :: CppComplex => {
384406 ensure_cpp_complex_program_compiled ( ) ?;
@@ -413,6 +435,12 @@ impl RegisteredFixture {
413435 . dir ( fixtures_base)
414436 . join ( compiler. binary_name ( self . name ) ) )
415437 }
438+ RegisteredFixtureKind :: PartitionedRanges => {
439+ ensure_partitioned_ranges_program_compiled ( compiler) ?;
440+ Ok ( self
441+ . dir ( fixtures_base)
442+ . join ( compiler. binary_name ( self . name ) ) )
443+ }
416444 RegisteredFixtureKind :: EntryValueRecovery => {
417445 ensure_entry_value_recovery_program_compiled ( compiler) ?;
418446 Ok ( self
@@ -451,6 +479,21 @@ pub(crate) fn fixture_compiler_available(compiler: FixtureCompiler) -> bool {
451479 ) ,
452480 ] )
453481 }
482+ FixtureCompiler :: GccDwarf5FunctionSections => {
483+ preferred_gcc_binary ( ) . is_some ( )
484+ || precompiled_outputs_available ( & [ fixture_binary_path (
485+ "partitioned_ranges_program" ,
486+ & FixtureCompiler :: GccDwarf5FunctionSections
487+ . binary_name ( "partitioned_ranges_program" ) ,
488+ ) ] )
489+ }
490+ FixtureCompiler :: ClangDwarf5Rnglistx => {
491+ preferred_clang_binary ( ) . is_some ( )
492+ || precompiled_outputs_available ( & [ fixture_binary_path (
493+ "partitioned_ranges_program" ,
494+ & FixtureCompiler :: ClangDwarf5Rnglistx . binary_name ( "partitioned_ranges_program" ) ,
495+ ) ] )
496+ }
454497 }
455498}
456499
@@ -462,14 +505,27 @@ fn command_available(name: &str) -> bool {
462505 . unwrap_or ( false )
463506}
464507
465- fn preferred_clang_binary ( ) -> Option < & ' static str > {
466- if command_available ( "clang-18" ) {
467- Some ( "clang-18" )
468- } else if command_available ( "clang" ) {
469- Some ( "clang" )
470- } else {
471- None
508+ fn preferred_clang_binary ( ) -> Option < String > {
509+ preferred_compiler_binary ( "CLANG_BIN" , & [ "clang-18" , "clang" ] )
510+ }
511+
512+ fn preferred_gcc_binary ( ) -> Option < String > {
513+ preferred_compiler_binary ( "GCC_BIN" , & [ "gcc" ] )
514+ }
515+
516+ fn preferred_compiler_binary ( env_var : & str , candidates : & [ & str ] ) -> Option < String > {
517+ if let Some ( override_bin) = std:: env:: var_os ( env_var) {
518+ let override_bin = override_bin. to_string_lossy ( ) . trim ( ) . to_string ( ) ;
519+ if !override_bin. is_empty ( ) {
520+ return command_available ( & override_bin) . then_some ( override_bin) ;
521+ }
472522 }
523+
524+ candidates
525+ . iter ( )
526+ . copied ( )
527+ . find ( |name| command_available ( name) )
528+ . map ( str:: to_string)
473529}
474530
475531fn fixture_binary_path ( fixture_name : & str , binary_name : & str ) -> PathBuf {
@@ -985,7 +1041,9 @@ static COMPILE_RUST_GLOBAL: Once = Once::new();
9851041static COMPILE_INLINE_CALLSITE_DEFAULT : Once = Once :: new ( ) ;
9861042static COMPILE_INLINE_CALLSITE_CLANG_DWARF5 : Once = Once :: new ( ) ;
9871043static COMPILE_INLINE_CALL_VALUE : Once = Once :: new ( ) ;
988- static COMPILE_PARTITIONED_RANGES : Once = Once :: new ( ) ;
1044+ static COMPILE_PARTITIONED_RANGES_DEFAULT : Once = Once :: new ( ) ;
1045+ static COMPILE_PARTITIONED_RANGES_GCC_DWARF5_FUNCTION_SECTIONS : Once = Once :: new ( ) ;
1046+ static COMPILE_PARTITIONED_RANGES_CLANG_DWARF5_RNGLISTX : Once = Once :: new ( ) ;
9891047static COMPILE_CPP_COMPLEX : Once = Once :: new ( ) ;
9901048static COMPILE_STATIC_SCOPE_DEFAULT : Once = Once :: new ( ) ;
9911049static COMPILE_STATIC_SCOPE_CLANG_DWARF5 : Once = Once :: new ( ) ;
@@ -1118,6 +1176,12 @@ fn ensure_inline_callsite_program_compiled(compiler: FixtureCompiler) -> anyhow:
11181176 & COMPILE_INLINE_CALLSITE_CLANG_DWARF5 ,
11191177 & * COMPILE_INLINE_CALLSITE_CLANG_DWARF5_RESULT ,
11201178 ) ,
1179+ _ => {
1180+ anyhow:: bail!(
1181+ "Compiler override {} is not wired for inline_callsite_program" ,
1182+ compiler. description( )
1183+ )
1184+ }
11211185 } ;
11221186
11231187 once. call_once ( || {
@@ -1175,9 +1239,43 @@ fn ensure_inline_call_value_program_compiled() -> anyhow::Result<()> {
11751239 }
11761240}
11771241
1178- fn ensure_partitioned_ranges_program_compiled ( ) -> anyhow:: Result < ( ) > {
1179- COMPILE_PARTITIONED_RANGES . call_once ( || {
1180- let compile_result = ( || -> anyhow:: Result < ( ) > {
1242+ fn ensure_partitioned_ranges_program_compiled ( compiler : FixtureCompiler ) -> anyhow:: Result < ( ) > {
1243+ let ( once, slot) : ( & Once , & Mutex < Option < anyhow:: Result < ( ) > > > ) = match compiler {
1244+ FixtureCompiler :: Default => (
1245+ & COMPILE_PARTITIONED_RANGES_DEFAULT ,
1246+ & * COMPILE_PARTITIONED_RANGES_DEFAULT_RESULT ,
1247+ ) ,
1248+ FixtureCompiler :: GccDwarf5FunctionSections => (
1249+ & COMPILE_PARTITIONED_RANGES_GCC_DWARF5_FUNCTION_SECTIONS ,
1250+ & * COMPILE_PARTITIONED_RANGES_GCC_DWARF5_FUNCTION_SECTIONS_RESULT ,
1251+ ) ,
1252+ FixtureCompiler :: ClangDwarf5Rnglistx => (
1253+ & COMPILE_PARTITIONED_RANGES_CLANG_DWARF5_RNGLISTX ,
1254+ & * COMPILE_PARTITIONED_RANGES_CLANG_DWARF5_RNGLISTX_RESULT ,
1255+ ) ,
1256+ _ => {
1257+ anyhow:: bail!(
1258+ "Compiler override {} is not wired for partitioned_ranges_program" ,
1259+ compiler. description( )
1260+ )
1261+ }
1262+ } ;
1263+
1264+ once. call_once ( || {
1265+ let compile_result = compile_partitioned_ranges_program ( compiler) ;
1266+ * slot. lock ( ) . unwrap ( ) = Some ( compile_result) ;
1267+ } ) ;
1268+
1269+ match slot. lock ( ) . unwrap ( ) . as_ref ( ) {
1270+ Some ( Ok ( ( ) ) ) => Ok ( ( ) ) ,
1271+ Some ( Err ( e) ) => Err ( anyhow:: anyhow!( "{e}" ) ) ,
1272+ None => panic ! ( "Compilation result should be set after call_once" ) ,
1273+ }
1274+ }
1275+
1276+ fn compile_partitioned_ranges_program ( compiler : FixtureCompiler ) -> anyhow:: Result < ( ) > {
1277+ match compiler {
1278+ FixtureCompiler :: Default => {
11811279 let base = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) )
11821280 . join ( "tests/fixtures/partitioned_ranges_program" ) ;
11831281 if let Some ( result) = use_precompiled_outputs (
@@ -1187,11 +1285,6 @@ fn ensure_partitioned_ranges_program_compiled() -> anyhow::Result<()> {
11871285 return result;
11881286 }
11891287 println ! ( "Compiling partitioned_ranges_program (Optimized O3) in {base:?}" ) ;
1190- let _ = Command :: new ( "make" )
1191- . arg ( "clean" )
1192- . current_dir ( base. clone ( ) )
1193- . status ( )
1194- . is_ok ( ) ;
11951288 let out = Command :: new ( "make" ) . arg ( "all" ) . current_dir ( base) . output ( ) ?;
11961289 if out. status . success ( ) {
11971290 println ! ( "✓ Successfully compiled partitioned_ranges_program" ) ;
@@ -1203,14 +1296,21 @@ fn ensure_partitioned_ranges_program_compiled() -> anyhow::Result<()> {
12031296 stderr
12041297 ) )
12051298 }
1206- } ) ( ) ;
1207- * COMPILE_PARTITIONED_RANGES_RESULT . lock ( ) . unwrap ( ) = Some ( compile_result) ;
1208- } ) ;
1209-
1210- match COMPILE_PARTITIONED_RANGES_RESULT . lock ( ) . unwrap ( ) . as_ref ( ) {
1211- Some ( Ok ( ( ) ) ) => Ok ( ( ) ) ,
1212- Some ( Err ( e) ) => Err ( anyhow:: anyhow!( "{e}" ) ) ,
1213- None => panic ! ( "Compilation result should be set after call_once" ) ,
1299+ }
1300+ FixtureCompiler :: GccDwarf5FunctionSections => compile_c_make_fixture (
1301+ "partitioned_ranges_program" ,
1302+ compiler,
1303+ "-Wall -Wextra -gdwarf-5 -O3 -DNDEBUG -ffunction-sections -freorder-blocks-and-partition" ,
1304+ ) ,
1305+ FixtureCompiler :: ClangDwarf5Rnglistx => compile_c_make_fixture (
1306+ "partitioned_ranges_program" ,
1307+ compiler,
1308+ "-Wall -Wextra -gdwarf-5 -O3 -DNDEBUG -ffunction-sections -fbasic-block-sections=all" ,
1309+ ) ,
1310+ _ => anyhow:: bail!(
1311+ "Compiler override {} is not wired for partitioned_ranges_program" ,
1312+ compiler. description( )
1313+ ) ,
12141314 }
12151315}
12161316
@@ -1255,7 +1355,7 @@ fn ensure_cpp_complex_program_compiled() -> anyhow::Result<()> {
12551355pub ( crate ) fn compile_c_make_fixture (
12561356 fixture_name : & str ,
12571357 compiler : FixtureCompiler ,
1258- clang_dwarf5_cflags : & str ,
1358+ compiler_cflags : & str ,
12591359) -> anyhow:: Result < ( ) > {
12601360 let base = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) )
12611361 . join ( "tests/fixtures" )
@@ -1273,7 +1373,7 @@ pub(crate) fn compile_c_make_fixture(
12731373 ) ;
12741374
12751375 let mut cmd = Command :: new ( "make" ) ;
1276- compiler. apply_to_c_make ( & mut cmd, fixture_name, clang_dwarf5_cflags ) ;
1376+ compiler. apply_to_c_make ( & mut cmd, fixture_name, compiler_cflags ) ;
12771377 let output = cmd. current_dir ( base) . output ( ) . map_err ( |e| {
12781378 anyhow:: anyhow!(
12791379 "Failed to run make for {fixture_name} {}: {}" ,
@@ -1308,6 +1408,12 @@ fn ensure_static_scope_program_compiled(compiler: FixtureCompiler) -> anyhow::Re
13081408 & COMPILE_STATIC_SCOPE_CLANG_DWARF5 ,
13091409 & * COMPILE_STATIC_SCOPE_CLANG_DWARF5_RESULT ,
13101410 ) ,
1411+ _ => {
1412+ anyhow:: bail!(
1413+ "Compiler override {} is not wired for static_scope_program" ,
1414+ compiler. description( )
1415+ )
1416+ }
13111417 } ;
13121418
13131419 once. call_once ( || {
@@ -1340,6 +1446,12 @@ fn ensure_entry_value_recovery_program_compiled(compiler: FixtureCompiler) -> an
13401446 & COMPILE_ENTRY_VALUE_RECOVERY_CLANG_DWARF5 ,
13411447 & * COMPILE_ENTRY_VALUE_RECOVERY_CLANG_DWARF5_RESULT ,
13421448 ) ,
1449+ _ => {
1450+ anyhow:: bail!(
1451+ "Compiler override {} is not wired for entry_value_recovery_program" ,
1452+ compiler. description( )
1453+ )
1454+ }
13431455 } ;
13441456
13451457 once. call_once ( || {
0 commit comments