@@ -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 target-specific information from rustc\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