@@ -1445,6 +1445,19 @@ impl Build {
14451445 }
14461446}
14471447
1448+ /// Source, object, and working directory for an `is_flag_supported` probe.
1449+ ///
1450+ /// Tempfiles, when used, are removed when this value is dropped.
1451+ struct FlagSupportProbeFiles < ' a > {
1452+ dir : Cow < ' a , Path > ,
1453+ src : PathBuf ,
1454+ obj : PathBuf ,
1455+ _temp_files : Option < (
1456+ crate :: tempfile:: NamedTempfile ,
1457+ crate :: tempfile:: NamedTempfile ,
1458+ ) > ,
1459+ }
1460+
14481461/// Invoke or fetch the compiler or archiver.
14491462impl Build {
14501463 /// Run the compiler to test if it accepts the given flag.
@@ -1466,25 +1479,81 @@ impl Build {
14661479 )
14671480 }
14681481
1469- fn ensure_check_file ( & self ) -> Result < PathBuf , Error > {
1470- let out_dir = self . get_out_dir ( ) ?;
1471- let src = if self . cuda {
1482+ fn flag_check_src_name ( & self ) -> & ' static str {
1483+ if self . cuda {
14721484 assert ! ( self . cpp) ;
1473- out_dir . join ( "flag_check.cu" )
1485+ "flag_check.cu"
14741486 } else if self . cpp {
1475- out_dir . join ( "flag_check.cpp" )
1487+ "flag_check.cpp"
14761488 } else {
1477- out_dir. join ( "flag_check.c" )
1478- } ;
1489+ "flag_check.c"
1490+ }
1491+ }
1492+
1493+ fn write_flag_check_src ( file : & mut fs:: File ) -> io:: Result < ( ) > {
1494+ write ! ( file, "int main(void) {{ return 0; }}" ) ?;
1495+ file. flush ( ) ?;
1496+ file. sync_data ( )
1497+ }
1498+
1499+ fn ensure_check_file ( & self ) -> Result < PathBuf , Error > {
1500+ let src = self . get_out_dir ( ) ?. join ( self . flag_check_src_name ( ) ) ;
14791501
14801502 if !src. exists ( ) {
14811503 let mut f = fs:: File :: create ( & src) ?;
1482- write ! ( f , "int main(void) {{ return 0; }}" ) ?;
1504+ Self :: write_flag_check_src ( & mut f ) ?;
14831505 }
14841506
14851507 Ok ( src)
14861508 }
14871509
1510+ /// Directory, source, and object for a flag-support probe.
1511+ ///
1512+ /// Cargo build scripts have `OUT_DIR`; reuse `flag_check.c` there so
1513+ /// probes stay cheap. Callers such as rustc bootstrap do not, and
1514+ /// treating a missing dir as "unsupported" silently drops flags.
1515+ /// Fall back to unique tempfiles instead of a shared name in `/tmp`.
1516+ fn flag_support_probe_files ( & self ) -> Result < FlagSupportProbeFiles < ' _ > , Error > {
1517+ match self . get_out_dir ( ) {
1518+ Ok ( dir) => {
1519+ let src = self . ensure_check_file ( ) ?;
1520+ let obj = dir. join ( "flag_check" ) ;
1521+ Ok ( FlagSupportProbeFiles {
1522+ dir,
1523+ src,
1524+ obj,
1525+ _temp_files : None ,
1526+ } )
1527+ }
1528+ Err ( _) => {
1529+ let dir = env:: temp_dir ( ) ;
1530+ fs:: create_dir_all ( & dir) ?;
1531+
1532+ let mut tmp_src =
1533+ crate :: tempfile:: NamedTempfile :: new ( & dir, self . flag_check_src_name ( ) ) ?;
1534+ let mut tmp_file = tmp_src. take_file ( ) . unwrap ( ) ;
1535+ Self :: write_flag_check_src ( & mut tmp_file) ?;
1536+ // Close the handle before invoking the compiler; Windows
1537+ // cannot open a file that another handle still holds.
1538+ drop ( tmp_file) ;
1539+
1540+ let mut tmp_obj = crate :: tempfile:: NamedTempfile :: new ( & dir, "flag_check" ) ?;
1541+ // Same as the source file: the compiler must be able to
1542+ // overwrite this path, so drop the open handle first.
1543+ drop ( tmp_obj. take_file ( ) ) ;
1544+
1545+ let src = tmp_src. path ( ) . to_owned ( ) ;
1546+ let obj = tmp_obj. path ( ) . to_owned ( ) ;
1547+ Ok ( FlagSupportProbeFiles {
1548+ dir : Cow :: Owned ( dir) ,
1549+ src,
1550+ obj,
1551+ _temp_files : Some ( ( tmp_src, tmp_obj) ) ,
1552+ } )
1553+ }
1554+ }
1555+ }
1556+
14881557 fn is_flag_supported_inner (
14891558 & self ,
14901559 flag : & OsStr ,
@@ -1507,9 +1576,7 @@ impl Build {
15071576 return Ok ( is_supported) ;
15081577 }
15091578
1510- let out_dir = self . get_out_dir ( ) ?;
1511- let src = self . ensure_check_file ( ) ?;
1512- let obj = out_dir. join ( "flag_check" ) ;
1579+ let probe = self . flag_support_probe_files ( ) ?;
15131580
15141581 let mut compiler = {
15151582 let mut cfg = Build :: new ( ) ;
@@ -1520,7 +1587,7 @@ impl Build {
15201587 . debug ( false )
15211588 . cpp ( self . cpp )
15221589 . cuda ( self . cuda )
1523- . out_dir ( & out_dir )
1590+ . out_dir ( & * probe . dir )
15241591 . inherit_rustflags ( false )
15251592 . inherit_trim_paths ( false )
15261593 . emit_rerun_if_env_changed ( self . emit_rerun_if_env_changed ) ;
@@ -1555,7 +1622,7 @@ impl Build {
15551622 cmd. set_flag_supported_env ( & self . env ) ;
15561623 command_add_output_file (
15571624 & mut cmd,
1558- & obj,
1625+ & probe . obj ,
15591626 CmdAddOutputFileArgs {
15601627 cuda : self . cuda ,
15611628 is_assembler_msvc : false ,
@@ -1577,7 +1644,7 @@ impl Build {
15771644 cmd. arg ( "--" ) ;
15781645 }
15791646
1580- cmd. arg ( & src) ;
1647+ cmd. arg ( & probe . src ) ;
15811648
15821649 if compiler. is_like_msvc ( ) {
15831650 // On MSVC we need to make sure the LIB directory is included
@@ -1590,10 +1657,11 @@ impl Build {
15901657 }
15911658 }
15921659
1593- cmd. current_dir ( out_dir ) ;
1660+ cmd. current_dir ( & * probe . dir ) ;
15941661 self . cargo_output
15951662 . print_debug ( & format_args ! ( "running: {cmd:?}" ) ) ;
15961663 let output = cmd. output ( ) ?;
1664+ drop ( probe) ;
15971665 let is_supported = output. status . success ( ) && output. stderr . is_empty ( ) ;
15981666
15991667 self . build_cache
0 commit comments