1
1
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
2
2
3
+ use std:: fs;
4
+ use std:: path:: PathBuf ;
5
+
3
6
use crate :: core:: build_steps:: compile:: {
4
7
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
5
8
} ;
@@ -9,11 +12,11 @@ use crate::core::build_steps::tool::{
9
12
prepare_tool_cargo,
10
13
} ;
11
14
use crate :: core:: builder:: {
12
- self , Alias , Builder , Kind , RunConfig , ShouldRun , Step , StepMetadata , crate_description,
15
+ self , Alias , Builder , Cargo , Kind , RunConfig , ShouldRun , Step , StepMetadata , crate_description,
13
16
} ;
14
17
use crate :: core:: config:: TargetSelection ;
15
18
use crate :: utils:: build_stamp:: { self , BuildStamp } ;
16
- use crate :: { Compiler , Mode , Subcommand } ;
19
+ use crate :: { Compiler , Mode , Subcommand , t } ;
17
20
18
21
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
19
22
pub struct Std {
@@ -64,7 +67,8 @@ impl Step for Std {
64
67
65
68
let crates = std_crates_for_run_make ( & run) ;
66
69
run. builder . ensure ( Std {
67
- build_compiler : prepare_compiler_for_check ( run. builder , run. target , Mode :: Std ) ,
70
+ build_compiler : prepare_compiler_for_check ( run. builder , run. target , Mode :: Std )
71
+ . build_compiler ,
68
72
target : run. target ,
69
73
crates,
70
74
} ) ;
@@ -145,8 +149,65 @@ impl Step for Std {
145
149
}
146
150
}
147
151
148
- /// Checks rustc using `build_compiler` and copies the built
149
- /// .rmeta files into the sysroot of `build_compiler`.
152
+ /// Represents a proof that rustc was checked.
153
+ /// Contains directories that contain .rmeta files generated by checking rustc for a specific
154
+ /// target.
155
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
156
+ struct RustcRmetaSysroot {
157
+ host_dir : PathBuf ,
158
+ target_dir : PathBuf ,
159
+ }
160
+
161
+ impl RustcRmetaSysroot {
162
+ /// Configure the given cargo invocation so that the compiled crate will be able to use
163
+ /// rustc rmeta artifacts that were previously generated.
164
+ fn configure_cargo ( & self , cargo : & mut Cargo ) {
165
+ cargo. env (
166
+ "RUSTC_ADDITIONAL_SYSROOT_PATHS" ,
167
+ format ! ( "{},{}" , self . host_dir. display( ) , self . target_dir. display( ) ) ,
168
+ ) ;
169
+ }
170
+ }
171
+
172
+ /// Checks rustc using the given `build_compiler` for the given `target`, and produces
173
+ /// a sysroot in the build directory that stores the generated .rmeta files.
174
+ ///
175
+ /// This step exists so that we can separate the generated .rmeta artifacts into a separate
176
+ /// directory. Before, we used to copy them into the sysroot of `build_compiler`, but that
177
+ /// "pollutes" its sysroot, which is problematic especially for external stage0 rustc.
178
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
179
+ struct PrepareRustcRmetaSysroot {
180
+ build_compiler : Compiler ,
181
+ target : TargetSelection ,
182
+ }
183
+
184
+ impl Step for PrepareRustcRmetaSysroot {
185
+ type Output = RustcRmetaSysroot ;
186
+
187
+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
188
+ run. never ( )
189
+ }
190
+
191
+ fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
192
+ // Check rustc
193
+ let stamp = builder. ensure ( Rustc :: new ( builder, self . build_compiler , self . target ) ) ;
194
+
195
+ // Copy the generated rmeta artifacts to a separate directory
196
+ let dir = builder
197
+ . out
198
+ . join ( self . build_compiler . host )
199
+ . join ( format ! ( "stage{}-rustc-check-artifacts" , self . build_compiler. stage + 1 ) ) ;
200
+ let host_dir = dir. join ( "host" ) ;
201
+ let target_dir = dir. join ( self . target ) ;
202
+ let _ = fs:: remove_dir_all ( & dir) ;
203
+ t ! ( fs:: create_dir_all( & dir) ) ;
204
+ add_to_sysroot ( builder, & target_dir, & host_dir, & stamp) ;
205
+
206
+ RustcRmetaSysroot { host_dir, target_dir }
207
+ }
208
+ }
209
+
210
+ /// Checks rustc using `build_compiler`.
150
211
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
151
212
pub struct Rustc {
152
213
/// Compiler that will check this rustc.
@@ -172,7 +233,7 @@ impl Rustc {
172
233
}
173
234
174
235
impl Step for Rustc {
175
- type Output = ( ) ;
236
+ type Output = BuildStamp ;
176
237
const ONLY_HOSTS : bool = true ;
177
238
const DEFAULT : bool = true ;
178
239
@@ -184,7 +245,8 @@ impl Step for Rustc {
184
245
let crates = run. make_run_crates ( Alias :: Compiler ) ;
185
246
run. builder . ensure ( Rustc {
186
247
target : run. target ,
187
- build_compiler : prepare_compiler_for_check ( run. builder , run. target , Mode :: Rustc ) ,
248
+ build_compiler : prepare_compiler_for_check ( run. builder , run. target , Mode :: Rustc )
249
+ . build_compiler ,
188
250
crates,
189
251
} ) ;
190
252
}
@@ -196,7 +258,7 @@ impl Step for Rustc {
196
258
/// created will also be linked into the sysroot directory.
197
259
///
198
260
/// If we check a stage 2 compiler, we will have to first build a stage 1 compiler to check it.
199
- fn run ( self , builder : & Builder < ' _ > ) {
261
+ fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
200
262
let build_compiler = self . build_compiler ;
201
263
let target = self . target ;
202
264
@@ -238,53 +300,62 @@ impl Step for Rustc {
238
300
239
301
run_cargo ( builder, cargo, builder. config . free_args . clone ( ) , & stamp, vec ! [ ] , true , false ) ;
240
302
241
- let libdir = builder. sysroot_target_libdir ( build_compiler, target) ;
242
- let hostdir = builder. sysroot_target_libdir ( build_compiler, build_compiler. host ) ;
243
- add_to_sysroot ( builder, & libdir, & hostdir, & stamp) ;
303
+ stamp
244
304
}
245
305
246
306
fn metadata ( & self ) -> Option < StepMetadata > {
247
307
Some ( StepMetadata :: check ( "rustc" , self . target ) . built_by ( self . build_compiler ) )
248
308
}
249
309
}
250
310
311
+ /// Represents a compiler that can check something.
312
+ /// It optionally includes .rmeta artifacts from rustc that was already checked using
313
+ /// `build_compiler`.
314
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
315
+ struct CompilerForCheck {
316
+ build_compiler : Compiler ,
317
+ rustc_rmeta_sysroot : Option < RustcRmetaSysroot > ,
318
+ }
319
+
251
320
/// Prepares a compiler that will check something with the given `mode`.
252
321
fn prepare_compiler_for_check (
253
322
builder : & Builder < ' _ > ,
254
323
target : TargetSelection ,
255
324
mode : Mode ,
256
- ) -> Compiler {
325
+ ) -> CompilerForCheck {
257
326
let host = builder. host_target ;
258
327
259
- match mode {
328
+ let mut rmeta_sysroot = None ;
329
+ let build_compiler = match mode {
260
330
Mode :: ToolBootstrap => builder. compiler ( 0 , host) ,
261
331
Mode :: ToolTarget => get_tool_target_compiler ( builder, ToolTargetBuildMode :: Build ( target) ) ,
262
332
Mode :: ToolStd => {
263
333
if builder. config . compile_time_deps {
264
334
// When --compile-time-deps is passed, we can't use any rustc
265
335
// other than the bootstrap compiler. Luckily build scripts and
266
336
// proc macros for tools are unlikely to need nightly.
267
- return builder. compiler ( 0 , host) ;
337
+ builder. compiler ( 0 , host)
338
+ } else {
339
+ // These tools require the local standard library to be checked
340
+ let build_compiler = builder. compiler ( builder. top_stage , host) ;
341
+
342
+ // We need to build the host stdlib to check the tool itself.
343
+ // We need to build the target stdlib so that the tool can link to it.
344
+ builder. std ( build_compiler, host) ;
345
+ // We could only check this library in theory, but `check::Std` doesn't copy rmetas
346
+ // into `build_compiler`'s sysroot to avoid clashes with `.rlibs`, so we build it
347
+ // instead.
348
+ builder. std ( build_compiler, target) ;
349
+ build_compiler
268
350
}
269
-
270
- // These tools require the local standard library to be checked
271
- let build_compiler = builder. compiler ( builder. top_stage , host) ;
272
-
273
- // We need to build the host stdlib to check the tool itself.
274
- // We need to build the target stdlib so that the tool can link to it.
275
- builder. std ( build_compiler, host) ;
276
- // We could only check this library in theory, but `check::Std` doesn't copy rmetas
277
- // into `build_compiler`'s sysroot to avoid clashes with `.rlibs`, so we build it
278
- // instead.
279
- builder. std ( build_compiler, target) ;
280
- build_compiler
281
351
}
282
352
Mode :: ToolRustc | Mode :: Codegen => {
283
353
// FIXME: this is a hack, see description of Mode::Rustc below
284
354
let stage = if host == target { builder. top_stage - 1 } else { builder. top_stage } ;
285
355
// When checking tool stage N, we check it with compiler stage N-1
286
356
let build_compiler = builder. compiler ( stage, host) ;
287
- builder. ensure ( Rustc :: new ( builder, build_compiler, target) ) ;
357
+ rmeta_sysroot =
358
+ Some ( builder. ensure ( PrepareRustcRmetaSysroot { build_compiler, target } ) ) ;
288
359
build_compiler
289
360
}
290
361
Mode :: Rustc => {
@@ -304,15 +375,17 @@ fn prepare_compiler_for_check(
304
375
// stage 0 stdlib is used to compile build scripts and proc macros.
305
376
builder. compiler ( builder. top_stage , host)
306
377
}
307
- }
378
+ } ;
379
+ CompilerForCheck { build_compiler, rustc_rmeta_sysroot : rmeta_sysroot }
308
380
}
309
381
310
382
/// Checks a single codegen backend.
311
383
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
312
384
pub struct CodegenBackend {
313
- pub build_compiler : Compiler ,
314
- pub target : TargetSelection ,
315
- pub backend : & ' static str ,
385
+ build_compiler : Compiler ,
386
+ rmeta_sysroot : RustcRmetaSysroot ,
387
+ target : TargetSelection ,
388
+ backend : & ' static str ,
316
389
}
317
390
318
391
impl Step for CodegenBackend {
@@ -326,9 +399,17 @@ impl Step for CodegenBackend {
326
399
327
400
fn make_run ( run : RunConfig < ' _ > ) {
328
401
// FIXME: only check the backend(s) that were actually selected in run.paths
329
- let build_compiler = prepare_compiler_for_check ( run. builder , run. target , Mode :: Codegen ) ;
402
+ let CompilerForCheck { build_compiler, rustc_rmeta_sysroot : rmeta_sysroot } =
403
+ prepare_compiler_for_check ( run. builder , run. target , Mode :: Codegen ) ;
404
+ let rmeta_sysroot =
405
+ rmeta_sysroot. expect ( "Rustc rmeta sysroot missing for checking codegen" ) ;
330
406
for & backend in & [ "cranelift" , "gcc" ] {
331
- run. builder . ensure ( CodegenBackend { build_compiler, target : run. target , backend } ) ;
407
+ run. builder . ensure ( CodegenBackend {
408
+ build_compiler,
409
+ rmeta_sysroot : rmeta_sysroot. clone ( ) ,
410
+ target : run. target ,
411
+ backend,
412
+ } ) ;
332
413
}
333
414
}
334
415
@@ -351,6 +432,7 @@ impl Step for CodegenBackend {
351
432
target,
352
433
builder. kind ,
353
434
) ;
435
+ self . rmeta_sysroot . configure_cargo ( & mut cargo) ;
354
436
355
437
cargo
356
438
. arg ( "--manifest-path" )
@@ -388,8 +470,8 @@ macro_rules! tool_check_step {
388
470
) => {
389
471
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
390
472
pub struct $name {
391
- pub build_compiler : Compiler ,
392
- pub target: TargetSelection ,
473
+ compiler : CompilerForCheck ,
474
+ target: TargetSelection ,
393
475
}
394
476
395
477
impl Step for $name {
@@ -407,31 +489,31 @@ macro_rules! tool_check_step {
407
489
let builder = run. builder;
408
490
let mode = $mode( builder) ;
409
491
410
- let build_compiler = prepare_compiler_for_check( run. builder, target, mode) ;
492
+ let compiler = prepare_compiler_for_check( run. builder, target, mode) ;
411
493
412
494
// It doesn't make sense to cross-check bootstrap tools
413
495
if mode == Mode :: ToolBootstrap && target != run. builder. host_target {
414
496
println!( "WARNING: not checking bootstrap tool {} for target {target} as it is a bootstrap (host-only) tool" , stringify!( $path) ) ;
415
497
return ;
416
498
} ;
417
499
418
- run. builder. ensure( $name { target, build_compiler } ) ;
500
+ run. builder. ensure( $name { target, compiler } ) ;
419
501
}
420
502
421
503
fn run( self , builder: & Builder <' _>) {
422
- let Self { target, build_compiler } = self ;
504
+ let Self { target, compiler } = self ;
423
505
let allow_features = {
424
506
let mut _value = "" ;
425
507
$( _value = $allow_features; ) ?
426
508
_value
427
509
} ;
428
510
let extra_features: & [ & str ] = & [ $( $( $enable_features) ,* ) ?] ;
429
511
let mode = $mode( builder) ;
430
- run_tool_check_step( builder, build_compiler , target, $path, mode, allow_features, extra_features) ;
512
+ run_tool_check_step( builder, compiler , target, $path, mode, allow_features, extra_features) ;
431
513
}
432
514
433
515
fn metadata( & self ) -> Option <StepMetadata > {
434
- Some ( StepMetadata :: check( stringify!( $name) , self . target) . built_by( self . build_compiler) )
516
+ Some ( StepMetadata :: check( stringify!( $name) , self . target) . built_by( self . compiler . build_compiler) )
435
517
}
436
518
}
437
519
}
@@ -440,7 +522,7 @@ macro_rules! tool_check_step {
440
522
/// Used by the implementation of `Step::run` in `tool_check_step!`.
441
523
fn run_tool_check_step (
442
524
builder : & Builder < ' _ > ,
443
- build_compiler : Compiler ,
525
+ compiler : CompilerForCheck ,
444
526
target : TargetSelection ,
445
527
path : & str ,
446
528
mode : Mode ,
@@ -449,6 +531,8 @@ fn run_tool_check_step(
449
531
) {
450
532
let display_name = path. rsplit ( '/' ) . next ( ) . unwrap ( ) ;
451
533
534
+ let CompilerForCheck { build_compiler, rustc_rmeta_sysroot : rmeta_sysroot } = compiler;
535
+
452
536
let extra_features = extra_features. iter ( ) . map ( |f| f. to_string ( ) ) . collect :: < Vec < String > > ( ) ;
453
537
let mut cargo = prepare_tool_cargo (
454
538
builder,
@@ -465,6 +549,11 @@ fn run_tool_check_step(
465
549
& extra_features,
466
550
) ;
467
551
cargo. allow_features ( allow_features) ;
552
+ if mode == Mode :: ToolRustc {
553
+ let rmeta_sysroot =
554
+ rmeta_sysroot. expect ( "rustc rmeta sysroot missing for a ToolRustc tool" ) ;
555
+ rmeta_sysroot. configure_cargo ( & mut cargo) ;
556
+ }
468
557
469
558
// FIXME: check bootstrap doesn't currently work when multiple targets are checked
470
559
// FIXME: rust-analyzer does not work with --all-targets
0 commit comments