@@ -138,122 +138,148 @@ impl TargetInfo {
138
138
rustc : & Rustc ,
139
139
kind : CompileKind ,
140
140
) -> CargoResult < TargetInfo > {
141
- let rustflags = env_args (
141
+ let mut rustflags = env_args (
142
142
config,
143
143
requested_kinds,
144
144
& rustc. host ,
145
145
None ,
146
146
kind,
147
147
Flags :: Rust ,
148
148
) ?;
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
+ }
188
164
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
+ }
195
199
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 \
200
204
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
+
236
234
// recalculate `rustflags` from above now that we have `cfg`
237
235
// information
238
- rustflags : env_args (
236
+ let new_flags = env_args (
239
237
config,
240
238
requested_kinds,
241
239
& rustc. host ,
242
240
Some ( & cfg) ,
243
241
kind,
244
242
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
+ }
257
283
}
258
284
259
285
fn not_user_specific_cfg ( cfg : & CargoResult < Cfg > ) -> bool {
0 commit comments