1
1
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
2
2
3
3
use std:: fs;
4
- use std:: path:: PathBuf ;
4
+ use std:: path:: { Path , PathBuf } ;
5
5
6
6
use crate :: core:: build_steps:: compile:: {
7
7
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
@@ -36,7 +36,7 @@ impl Std {
36
36
}
37
37
38
38
impl Step for Std {
39
- type Output = ( ) ;
39
+ type Output = BuildStamp ;
40
40
const DEFAULT : bool = true ;
41
41
42
42
fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
@@ -70,7 +70,7 @@ impl Step for Std {
70
70
} ) ;
71
71
}
72
72
73
- fn run ( self , builder : & Builder < ' _ > ) {
73
+ fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
74
74
let build_compiler = self . build_compiler ;
75
75
let target = self . target ;
76
76
@@ -101,14 +101,23 @@ impl Step for Std {
101
101
target,
102
102
) ;
103
103
104
- let stamp = build_stamp:: libstd_stamp ( builder, build_compiler, target) . with_prefix ( "check" ) ;
105
- run_cargo ( builder, cargo, builder. config . free_args . clone ( ) , & stamp, vec ! [ ] , true , false ) ;
104
+ let check_stamp =
105
+ build_stamp:: libstd_stamp ( builder, build_compiler, target) . with_prefix ( "check" ) ;
106
+ run_cargo (
107
+ builder,
108
+ cargo,
109
+ builder. config . free_args . clone ( ) ,
110
+ & check_stamp,
111
+ vec ! [ ] ,
112
+ true ,
113
+ false ,
114
+ ) ;
106
115
107
116
drop ( _guard) ;
108
117
109
118
// don't check test dependencies if we haven't built libtest
110
119
if !self . crates . iter ( ) . any ( |krate| krate == "test" ) {
111
- return ;
120
+ return check_stamp ;
112
121
}
113
122
114
123
// Then run cargo again, once we've put the rmeta files for the library
@@ -145,6 +154,7 @@ impl Step for Std {
145
154
target,
146
155
) ;
147
156
run_cargo ( builder, cargo, builder. config . free_args . clone ( ) , & stamp, vec ! [ ] , true , false ) ;
157
+ check_stamp
148
158
}
149
159
150
160
fn metadata ( & self ) -> Option < StepMetadata > {
@@ -156,12 +166,28 @@ impl Step for Std {
156
166
/// Contains directories with .rmeta files generated by checking rustc for a specific
157
167
/// target.
158
168
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
159
- struct RustcRmetaSysroot {
169
+ struct RmetaSysroot {
160
170
host_dir : PathBuf ,
161
171
target_dir : PathBuf ,
162
172
}
163
173
164
- impl RustcRmetaSysroot {
174
+ impl RmetaSysroot {
175
+ /// Copy rmeta artifacts from the given `stamp` into a sysroot located at `directory`.
176
+ fn from_stamp (
177
+ builder : & Builder < ' _ > ,
178
+ stamp : BuildStamp ,
179
+ target : TargetSelection ,
180
+ directory : & Path ,
181
+ ) -> Self {
182
+ let host_dir = directory. join ( "host" ) ;
183
+ let target_dir = directory. join ( target) ;
184
+ let _ = fs:: remove_dir_all ( directory) ;
185
+ t ! ( fs:: create_dir_all( directory) ) ;
186
+ add_to_sysroot ( builder, & target_dir, & host_dir, & stamp) ;
187
+
188
+ Self { host_dir, target_dir }
189
+ }
190
+
165
191
/// Configure the given cargo invocation so that the compiled crate will be able to use
166
192
/// rustc .rmeta artifacts that were previously generated.
167
193
fn configure_cargo ( & self , cargo : & mut Cargo ) {
@@ -180,42 +206,90 @@ impl RustcRmetaSysroot {
180
206
/// "pollute" it (that is especially problematic for the external stage0 rustc).
181
207
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
182
208
struct PrepareRustcRmetaSysroot {
183
- build_compiler : Compiler ,
209
+ build_compiler : CompilerForCheck ,
184
210
target : TargetSelection ,
185
211
}
186
212
213
+ impl PrepareRustcRmetaSysroot {
214
+ fn new ( build_compiler : CompilerForCheck , target : TargetSelection ) -> Self {
215
+ Self { build_compiler, target }
216
+ }
217
+ }
218
+
187
219
impl Step for PrepareRustcRmetaSysroot {
188
- type Output = RustcRmetaSysroot ;
220
+ type Output = RmetaSysroot ;
189
221
190
222
fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
191
223
run. never ( )
192
224
}
193
225
194
226
fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
195
227
// Check rustc
196
- let stamp =
197
- builder. ensure ( Rustc :: from_build_compiler ( self . build_compiler , self . target , vec ! [ ] ) ) ;
228
+ let stamp = builder. ensure ( Rustc :: from_build_compiler (
229
+ self . build_compiler . clone ( ) ,
230
+ self . target ,
231
+ vec ! [ ] ,
232
+ ) ) ;
233
+
234
+ let build_compiler = self . build_compiler . build_compiler ( ) ;
235
+
236
+ // Copy the generated rmeta artifacts to a separate directory
237
+ let dir = builder
238
+ . out
239
+ . join ( build_compiler. host )
240
+ . join ( format ! ( "stage{}-rustc-rmeta-artifacts" , build_compiler. stage + 1 ) ) ;
241
+ RmetaSysroot :: from_stamp ( builder, stamp, self . target , & dir)
242
+ }
243
+ }
244
+
245
+ /// Checks std using the given `build_compiler` for the given `target`, and produces
246
+ /// a sysroot in the build directory that stores the generated .rmeta files.
247
+ ///
248
+ /// This step exists so that we can store the generated .rmeta artifacts into a separate
249
+ /// directory, instead of copying them into the sysroot of `build_compiler`, which would
250
+ /// "pollute" it (that is especially problematic for the external stage0 rustc).
251
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
252
+ struct PrepareStdRmetaSysroot {
253
+ build_compiler : Compiler ,
254
+ target : TargetSelection ,
255
+ }
256
+
257
+ impl PrepareStdRmetaSysroot {
258
+ fn new ( build_compiler : Compiler , target : TargetSelection ) -> Self {
259
+ Self { build_compiler, target }
260
+ }
261
+ }
262
+
263
+ impl Step for PrepareStdRmetaSysroot {
264
+ type Output = RmetaSysroot ;
265
+
266
+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
267
+ run. never ( )
268
+ }
269
+
270
+ fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
271
+ // Check std
272
+ let stamp = builder. ensure ( Std {
273
+ build_compiler : self . build_compiler ,
274
+ target : self . target ,
275
+ crates : vec ! [ ] ,
276
+ } ) ;
198
277
199
278
// Copy the generated rmeta artifacts to a separate directory
200
279
let dir = builder
201
280
. out
202
281
. join ( self . build_compiler . host )
203
- . join ( format ! ( "stage{}-rustc-check-artifacts" , self . build_compiler. stage + 1 ) ) ;
204
- let host_dir = dir. join ( "host" ) ;
205
- let target_dir = dir. join ( self . target ) ;
206
- let _ = fs:: remove_dir_all ( & dir) ;
207
- t ! ( fs:: create_dir_all( & dir) ) ;
208
- add_to_sysroot ( builder, & target_dir, & host_dir, & stamp) ;
282
+ . join ( format ! ( "stage{}-std-rmeta-artifacts" , self . build_compiler. stage) ) ;
209
283
210
- RustcRmetaSysroot { host_dir , target_dir }
284
+ RmetaSysroot :: from_stamp ( builder , stamp , self . target , & dir )
211
285
}
212
286
}
213
287
214
288
/// Checks rustc using `build_compiler`.
215
289
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
216
290
pub struct Rustc {
217
291
/// Compiler that will check this rustc.
218
- pub build_compiler : Compiler ,
292
+ pub build_compiler : CompilerForCheck ,
219
293
pub target : TargetSelection ,
220
294
/// Whether to build only a subset of crates.
221
295
///
@@ -227,13 +301,12 @@ pub struct Rustc {
227
301
228
302
impl Rustc {
229
303
pub fn new ( builder : & Builder < ' _ > , target : TargetSelection , crates : Vec < String > ) -> Self {
230
- let build_compiler =
231
- prepare_compiler_for_check ( builder, target, Mode :: Rustc ) . build_compiler ;
304
+ let build_compiler = prepare_compiler_for_check ( builder, target, Mode :: Rustc ) ;
232
305
Self :: from_build_compiler ( build_compiler, target, crates)
233
306
}
234
307
235
308
fn from_build_compiler (
236
- build_compiler : Compiler ,
309
+ build_compiler : CompilerForCheck ,
237
310
target : TargetSelection ,
238
311
crates : Vec < String > ,
239
312
) -> Self {
@@ -263,7 +336,7 @@ impl Step for Rustc {
263
336
///
264
337
/// If we check a stage 2 compiler, we will have to first build a stage 1 compiler to check it.
265
338
fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
266
- let build_compiler = self . build_compiler ;
339
+ let build_compiler = self . build_compiler . build_compiler ;
267
340
let target = self . target ;
268
341
269
342
let mut cargo = builder:: Cargo :: new (
@@ -276,6 +349,7 @@ impl Step for Rustc {
276
349
) ;
277
350
278
351
rustc_cargo ( builder, & mut cargo, target, & build_compiler, & self . crates ) ;
352
+ self . build_compiler . configure_cargo ( & mut cargo) ;
279
353
280
354
// Explicitly pass -p for all compiler crates -- this will force cargo
281
355
// to also check the tests/benches/examples for these crates, rather
@@ -288,7 +362,7 @@ impl Step for Rustc {
288
362
Kind :: Check ,
289
363
format_args ! ( "compiler artifacts{}" , crate_description( & self . crates) ) ,
290
364
Mode :: Rustc ,
291
- self . build_compiler ,
365
+ self . build_compiler . build_compiler ( ) ,
292
366
target,
293
367
) ;
294
368
@@ -301,7 +375,8 @@ impl Step for Rustc {
301
375
}
302
376
303
377
fn metadata ( & self ) -> Option < StepMetadata > {
304
- let metadata = StepMetadata :: check ( "rustc" , self . target ) . built_by ( self . build_compiler ) ;
378
+ let metadata = StepMetadata :: check ( "rustc" , self . target )
379
+ . built_by ( self . build_compiler . build_compiler ( ) ) ;
305
380
let metadata = if self . crates . is_empty ( ) {
306
381
metadata
307
382
} else {
@@ -322,7 +397,8 @@ impl Step for Rustc {
322
397
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
323
398
pub struct CompilerForCheck {
324
399
build_compiler : Compiler ,
325
- rustc_rmeta_sysroot : Option < RustcRmetaSysroot > ,
400
+ rustc_rmeta_sysroot : Option < RmetaSysroot > ,
401
+ std_rmeta_sysroot : Option < RmetaSysroot > ,
326
402
}
327
403
328
404
impl CompilerForCheck {
@@ -336,6 +412,30 @@ impl CompilerForCheck {
336
412
if let Some ( sysroot) = & self . rustc_rmeta_sysroot {
337
413
sysroot. configure_cargo ( cargo) ;
338
414
}
415
+ if let Some ( sysroot) = & self . std_rmeta_sysroot {
416
+ sysroot. configure_cargo ( cargo) ;
417
+ }
418
+ }
419
+ }
420
+
421
+ /// Prepare the standard library for checking something (that requires stdlib) using
422
+ /// `build_compiler`.
423
+ fn prepare_std (
424
+ builder : & Builder < ' _ > ,
425
+ build_compiler : Compiler ,
426
+ target : TargetSelection ,
427
+ ) -> Option < RmetaSysroot > {
428
+ // We need to build the host stdlib even if we only check, to compile build scripts and proc
429
+ // macros
430
+ builder. std ( build_compiler, builder. host_target ) ;
431
+
432
+ // If we're cross-compiling, we generate the rmeta files for the given target
433
+ // This check has to be here, because if we generate both .so and .rmeta files, rustc will fail,
434
+ // as it will have multiple candidates for linking.
435
+ if builder. host_target != target {
436
+ Some ( builder. ensure ( PrepareStdRmetaSysroot :: new ( build_compiler, target) ) )
437
+ } else {
438
+ None
339
439
}
340
440
}
341
441
@@ -347,9 +447,13 @@ pub fn prepare_compiler_for_check(
347
447
) -> CompilerForCheck {
348
448
let host = builder. host_target ;
349
449
350
- let mut rmeta_sysroot = None ;
450
+ let mut rustc_rmeta_sysroot = None ;
451
+ let mut std_rmeta_sysroot = None ;
351
452
let build_compiler = match mode {
352
453
Mode :: ToolBootstrap => builder. compiler ( 0 , host) ,
454
+ // We could also only check std here and use `prepare_std`, but `ToolTarget` is currently
455
+ // only used for running in-tree Clippy on bootstrap tools, so it does not seem worth it to
456
+ // optimize it. Therefore, here we build std for the target, instead of just checking it.
353
457
Mode :: ToolTarget => get_tool_target_compiler ( builder, ToolTargetBuildMode :: Build ( target) ) ,
354
458
Mode :: ToolStd => {
355
459
if builder. config . compile_time_deps {
@@ -360,14 +464,7 @@ pub fn prepare_compiler_for_check(
360
464
} else {
361
465
// These tools require the local standard library to be checked
362
466
let build_compiler = builder. compiler ( builder. top_stage , host) ;
363
-
364
- // We need to build the host stdlib to check the tool itself.
365
- // We need to build the target stdlib so that the tool can link to it.
366
- builder. std ( build_compiler, host) ;
367
- // We could only check this library in theory, but `check::Std` doesn't copy rmetas
368
- // into `build_compiler`'s sysroot to avoid clashes with `.rlibs`, so we build it
369
- // instead.
370
- builder. std ( build_compiler, target) ;
467
+ std_rmeta_sysroot = prepare_std ( builder, build_compiler, target) ;
371
468
build_compiler
372
469
}
373
470
}
@@ -376,11 +473,14 @@ pub fn prepare_compiler_for_check(
376
473
// return the build compiler that was used to check rustc.
377
474
// We do not need to check examples/tests/etc. of Rustc for rustc_private, so we pass
378
475
// an empty set of crates, which will avoid using `cargo -p`.
379
- let check = Rustc :: new ( builder, target, vec ! [ ] ) ;
380
- let build_compiler = check. build_compiler ;
381
- builder. ensure ( check) ;
382
- rmeta_sysroot =
383
- Some ( builder. ensure ( PrepareRustcRmetaSysroot { build_compiler, target } ) ) ;
476
+ let compiler_for_rustc = prepare_compiler_for_check ( builder, target, Mode :: Rustc ) ;
477
+ rustc_rmeta_sysroot = Some (
478
+ builder. ensure ( PrepareRustcRmetaSysroot :: new ( compiler_for_rustc. clone ( ) , target) ) ,
479
+ ) ;
480
+ let build_compiler = compiler_for_rustc. build_compiler ( ) ;
481
+
482
+ // To check a rustc_private tool, we also need to check std that it will link to
483
+ std_rmeta_sysroot = prepare_std ( builder, build_compiler, target) ;
384
484
build_compiler
385
485
}
386
486
Mode :: Rustc => {
@@ -394,15 +494,8 @@ pub fn prepare_compiler_for_check(
394
494
let stage = if host == target { builder. top_stage - 1 } else { builder. top_stage } ;
395
495
let build_compiler = builder. compiler ( stage, host) ;
396
496
397
- // Build host std for compiling build scripts
398
- builder. std ( build_compiler, build_compiler. host ) ;
399
-
400
- // Build target std so that the checked rustc can link to it during the check
401
- // FIXME: maybe we can a way to only do a check of std here?
402
- // But for that we would have to copy the stdlib rmetas to the sysroot of the build
403
- // compiler, which conflicts with std rlibs, if we also build std.
404
- builder. std ( build_compiler, target) ;
405
-
497
+ // To check rustc, we need to check std that it will link to
498
+ std_rmeta_sysroot = prepare_std ( builder, build_compiler, target) ;
406
499
build_compiler
407
500
}
408
501
Mode :: Std => {
@@ -412,7 +505,7 @@ pub fn prepare_compiler_for_check(
412
505
builder. compiler ( builder. top_stage , host)
413
506
}
414
507
} ;
415
- CompilerForCheck { build_compiler, rustc_rmeta_sysroot : rmeta_sysroot }
508
+ CompilerForCheck { build_compiler, rustc_rmeta_sysroot, std_rmeta_sysroot }
416
509
}
417
510
418
511
/// Check the Cranelift codegen backend.
0 commit comments