@@ -138,122 +138,148 @@ impl TargetInfo {
138138        rustc :  & Rustc , 
139139        kind :  CompileKind , 
140140    )  -> CargoResult < TargetInfo >  { 
141-         let  rustflags = env_args ( 
141+         let  mut   rustflags = env_args ( 
142142            config, 
143143            requested_kinds, 
144144            & rustc. host , 
145145            None , 
146146            kind, 
147147            Flags :: Rust , 
148148        ) ?; 
149-         let  extra_fingerprint = kind. fingerprint_hash ( ) ; 
150-         let  mut  process = rustc. workspace_process ( ) ; 
151-         process
152-             . arg ( "-" ) 
153-             . arg ( "--crate-name" ) 
154-             . arg ( "___" ) 
155-             . arg ( "--print=file-names" ) 
156-             . args ( & rustflags) 
157-             . env_remove ( "RUSTC_LOG" ) ; 
158- 
159-         if  let  CompileKind :: Target ( target)  = kind { 
160-             process. arg ( "--target" ) . arg ( target. rustc_target ( ) ) ; 
161-         } 
162- 
163-         let  crate_type_process = process. clone ( ) ; 
164-         const  KNOWN_CRATE_TYPES :  & [ CrateType ]  = & [ 
165-             CrateType :: Bin , 
166-             CrateType :: Rlib , 
167-             CrateType :: Dylib , 
168-             CrateType :: Cdylib , 
169-             CrateType :: Staticlib , 
170-             CrateType :: ProcMacro , 
171-         ] ; 
172-         for  crate_type in  KNOWN_CRATE_TYPES . iter ( )  { 
173-             process. arg ( "--crate-type" ) . arg ( crate_type. as_str ( ) ) ; 
174-         } 
175-         let  supports_split_debuginfo = rustc
176-             . cached_output ( 
177-                 process. clone ( ) . arg ( "-Csplit-debuginfo=packed" ) , 
178-                 extra_fingerprint, 
179-             ) 
180-             . is_ok ( ) ; 
181- 
182-         process. arg ( "--print=sysroot" ) ; 
183-         process. arg ( "--print=cfg" ) ; 
184- 
185-         let  ( output,  error)  = rustc
186-             . cached_output ( & process,  extra_fingerprint) 
187-             . with_context ( || "failed to run `rustc` to learn about target-specific information" ) ?; 
149+         let  mut  turn = 0 ; 
150+         loop  { 
151+             let  extra_fingerprint = kind. fingerprint_hash ( ) ; 
152+             let  mut  process = rustc. workspace_process ( ) ; 
153+             process
154+                 . arg ( "-" ) 
155+                 . arg ( "--crate-name" ) 
156+                 . arg ( "___" ) 
157+                 . arg ( "--print=file-names" ) 
158+                 . args ( & rustflags) 
159+                 . env_remove ( "RUSTC_LOG" ) ; 
160+ 
161+             if  let  CompileKind :: Target ( target)  = kind { 
162+                 process. arg ( "--target" ) . arg ( target. rustc_target ( ) ) ; 
163+             } 
188164
189-         let  mut  lines = output. lines ( ) ; 
190-         let  mut  map = HashMap :: new ( ) ; 
191-         for  crate_type in  KNOWN_CRATE_TYPES  { 
192-             let  out = parse_crate_type ( crate_type,  & process,  & output,  & error,  & mut  lines) ?; 
193-             map. insert ( crate_type. clone ( ) ,  out) ; 
194-         } 
165+             let  crate_type_process = process. clone ( ) ; 
166+             const  KNOWN_CRATE_TYPES :  & [ CrateType ]  = & [ 
167+                 CrateType :: Bin , 
168+                 CrateType :: Rlib , 
169+                 CrateType :: Dylib , 
170+                 CrateType :: Cdylib , 
171+                 CrateType :: Staticlib , 
172+                 CrateType :: ProcMacro , 
173+             ] ; 
174+             for  crate_type in  KNOWN_CRATE_TYPES . iter ( )  { 
175+                 process. arg ( "--crate-type" ) . arg ( crate_type. as_str ( ) ) ; 
176+             } 
177+             let  supports_split_debuginfo = rustc
178+                 . cached_output ( 
179+                     process. clone ( ) . arg ( "-Csplit-debuginfo=packed" ) , 
180+                     extra_fingerprint, 
181+                 ) 
182+                 . is_ok ( ) ; 
183+ 
184+             process. arg ( "--print=sysroot" ) ; 
185+             process. arg ( "--print=cfg" ) ; 
186+ 
187+             let  ( output,  error)  = rustc
188+                 . cached_output ( & process,  extra_fingerprint) 
189+                 . with_context ( || { 
190+                     "failed to run `rustc` to learn about target-specific information" 
191+                 } ) ?; 
192+ 
193+             let  mut  lines = output. lines ( ) ; 
194+             let  mut  map = HashMap :: new ( ) ; 
195+             for  crate_type in  KNOWN_CRATE_TYPES  { 
196+                 let  out = parse_crate_type ( crate_type,  & process,  & output,  & error,  & mut  lines) ?; 
197+                 map. insert ( crate_type. clone ( ) ,  out) ; 
198+             } 
195199
196-         let  line = match  lines. next ( )  { 
197-             Some ( line)  => line, 
198-             None  => anyhow:: bail!( 
199-                 "output of --print=sysroot missing when learning about \  
200+              let  line = match  lines. next ( )  { 
201+                  Some ( line)  => line, 
202+                  None  => anyhow:: bail!( 
203+                      "output of --print=sysroot missing when learning about \  
200204\n {}", 
201-                 output_err_info( & process,  & output,  & error) 
202-             ) , 
203-         } ; 
204-         let  sysroot = PathBuf :: from ( line) ; 
205-         let  sysroot_host_libdir = if  cfg ! ( windows)  { 
206-             sysroot. join ( "bin" ) 
207-         }  else  { 
208-             sysroot. join ( "lib" ) 
209-         } ; 
210-         let  mut  sysroot_target_libdir = sysroot. clone ( ) ; 
211-         sysroot_target_libdir. push ( "lib" ) ; 
212-         sysroot_target_libdir. push ( "rustlib" ) ; 
213-         sysroot_target_libdir. push ( match  & kind { 
214-             CompileKind :: Host  => rustc. host . as_str ( ) , 
215-             CompileKind :: Target ( target)  => target. short_name ( ) , 
216-         } ) ; 
217-         sysroot_target_libdir. push ( "lib" ) ; 
218- 
219-         let  cfg = lines
220-             . map ( |line| Ok ( Cfg :: from_str ( line) ?) ) 
221-             . filter ( TargetInfo :: not_user_specific_cfg) 
222-             . collect :: < CargoResult < Vec < _ > > > ( ) 
223-             . with_context ( || { 
224-                 format ! ( 
225-                     "failed to parse the cfg from `rustc --print=cfg`, got:\n {}" , 
226-                     output
227-                 ) 
228-             } ) ?; 
229- 
230-         Ok ( TargetInfo  { 
231-             crate_type_process, 
232-             crate_types :  RefCell :: new ( map) , 
233-             sysroot, 
234-             sysroot_host_libdir, 
235-             sysroot_target_libdir, 
205+                     output_err_info( & process,  & output,  & error) 
206+                 ) , 
207+             } ; 
208+             let  sysroot = PathBuf :: from ( line) ; 
209+             let  sysroot_host_libdir = if  cfg ! ( windows)  { 
210+                 sysroot. join ( "bin" ) 
211+             }  else  { 
212+                 sysroot. join ( "lib" ) 
213+             } ; 
214+             let  mut  sysroot_target_libdir = sysroot. clone ( ) ; 
215+             sysroot_target_libdir. push ( "lib" ) ; 
216+             sysroot_target_libdir. push ( "rustlib" ) ; 
217+             sysroot_target_libdir. push ( match  & kind { 
218+                 CompileKind :: Host  => rustc. host . as_str ( ) , 
219+                 CompileKind :: Target ( target)  => target. short_name ( ) , 
220+             } ) ; 
221+             sysroot_target_libdir. push ( "lib" ) ; 
222+ 
223+             let  cfg = lines
224+                 . map ( |line| Ok ( Cfg :: from_str ( line) ?) ) 
225+                 . filter ( TargetInfo :: not_user_specific_cfg) 
226+                 . collect :: < CargoResult < Vec < _ > > > ( ) 
227+                 . with_context ( || { 
228+                     format ! ( 
229+                         "failed to parse the cfg from `rustc --print=cfg`, got:\n {}" , 
230+                         output
231+                     ) 
232+                 } ) ?; 
233+ 
236234            // recalculate `rustflags` from above now that we have `cfg` 
237235            // information 
238-             rustflags :  env_args ( 
236+             let  new_flags =  env_args ( 
239237                config, 
240238                requested_kinds, 
241239                & rustc. host , 
242240                Some ( & cfg) , 
243241                kind, 
244242                Flags :: Rust , 
245-             ) ?, 
246-             rustdocflags :  env_args ( 
247-                 config, 
248-                 requested_kinds, 
249-                 & rustc. host , 
250-                 Some ( & cfg) , 
251-                 kind, 
252-                 Flags :: Rustdoc , 
253-             ) ?, 
254-             cfg, 
255-             supports_split_debuginfo, 
256-         } ) 
243+             ) ?; 
244+ 
245+             // Tricky: `RUSTFLAGS` defines the set of active `cfg` flags, active 
246+             // `cfg` flags define which `.cargo/config` sections apply, and they 
247+             // in turn can affect `RUSTFLAGS`! This is a bona fide mutual 
248+             // dependency, and it can even diverge (see `cfg_paradox` test). 
249+             // 
250+             // So what we do here is running at most *two* iterations of 
251+             // fixed-point iteration, which should be enough to cover 
252+             // practically useful cases, and warn if that's not enough for 
253+             // convergence. 
254+             let  reached_fixed_point = new_flags == rustflags; 
255+             if  !reached_fixed_point && turn == 0  { 
256+                 turn += 1 ; 
257+                 rustflags = new_flags; 
258+                 continue ; 
259+             } 
260+             if  !reached_fixed_point { 
261+                 config. shell ( ) . warn ( "non-trivial mutual dependency between target-specific configuration and RUSTFLAGS" ) ?; 
262+             } 
263+ 
264+             return  Ok ( TargetInfo  { 
265+                 crate_type_process, 
266+                 crate_types :  RefCell :: new ( map) , 
267+                 sysroot, 
268+                 sysroot_host_libdir, 
269+                 sysroot_target_libdir, 
270+                 rustflags, 
271+                 rustdocflags :  env_args ( 
272+                     config, 
273+                     requested_kinds, 
274+                     & rustc. host , 
275+                     Some ( & cfg) , 
276+                     kind, 
277+                     Flags :: Rustdoc , 
278+                 ) ?, 
279+                 cfg, 
280+                 supports_split_debuginfo, 
281+             } ) ; 
282+         } 
257283    } 
258284
259285    fn  not_user_specific_cfg ( cfg :  & CargoResult < Cfg > )  -> bool  { 
0 commit comments