11//! Implementation of compiling the compiler and standard library, in "check"-based modes.
22
3+ use std:: fs;
4+ use std:: path:: PathBuf ;
5+
36use crate :: core:: build_steps:: compile:: {
47 add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
58} ;
@@ -9,11 +12,11 @@ use crate::core::build_steps::tool::{
912 prepare_tool_cargo,
1013} ;
1114use 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,
1316} ;
1417use crate :: core:: config:: TargetSelection ;
1518use crate :: utils:: build_stamp:: { self , BuildStamp } ;
16- use crate :: { Compiler , Mode , Subcommand } ;
19+ use crate :: { Compiler , Mode , Subcommand , t } ;
1720
1821#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
1922pub struct Std {
@@ -64,7 +67,8 @@ impl Step for Std {
6467
6568 let crates = std_crates_for_run_make ( & run) ;
6669 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 ,
6872 target : run. target ,
6973 crates,
7074 } ) ;
@@ -145,8 +149,65 @@ impl Step for Std {
145149 }
146150}
147151
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`.
150211#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
151212pub struct Rustc {
152213 /// Compiler that will check this rustc.
@@ -172,7 +233,7 @@ impl Rustc {
172233}
173234
174235impl Step for Rustc {
175- type Output = ( ) ;
236+ type Output = BuildStamp ;
176237 const ONLY_HOSTS : bool = true ;
177238 const DEFAULT : bool = true ;
178239
@@ -184,7 +245,8 @@ impl Step for Rustc {
184245 let crates = run. make_run_crates ( Alias :: Compiler ) ;
185246 run. builder . ensure ( Rustc {
186247 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 ,
188250 crates,
189251 } ) ;
190252 }
@@ -196,7 +258,7 @@ impl Step for Rustc {
196258 /// created will also be linked into the sysroot directory.
197259 ///
198260 /// 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 {
200262 let build_compiler = self . build_compiler ;
201263 let target = self . target ;
202264
@@ -238,53 +300,62 @@ impl Step for Rustc {
238300
239301 run_cargo ( builder, cargo, builder. config . free_args . clone ( ) , & stamp, vec ! [ ] , true , false ) ;
240302
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
244304 }
245305
246306 fn metadata ( & self ) -> Option < StepMetadata > {
247307 Some ( StepMetadata :: check ( "rustc" , self . target ) . built_by ( self . build_compiler ) )
248308 }
249309}
250310
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+
251320/// Prepares a compiler that will check something with the given `mode`.
252321fn prepare_compiler_for_check (
253322 builder : & Builder < ' _ > ,
254323 target : TargetSelection ,
255324 mode : Mode ,
256- ) -> Compiler {
325+ ) -> CompilerForCheck {
257326 let host = builder. host_target ;
258327
259- match mode {
328+ let mut rmeta_sysroot = None ;
329+ let build_compiler = match mode {
260330 Mode :: ToolBootstrap => builder. compiler ( 0 , host) ,
261331 Mode :: ToolTarget => get_tool_target_compiler ( builder, ToolTargetBuildMode :: Build ( target) ) ,
262332 Mode :: ToolStd => {
263333 if builder. config . compile_time_deps {
264334 // When --compile-time-deps is passed, we can't use any rustc
265335 // other than the bootstrap compiler. Luckily build scripts and
266336 // 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
268350 }
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
281351 }
282352 Mode :: ToolRustc | Mode :: Codegen => {
283353 // FIXME: this is a hack, see description of Mode::Rustc below
284354 let stage = if host == target { builder. top_stage - 1 } else { builder. top_stage } ;
285355 // When checking tool stage N, we check it with compiler stage N-1
286356 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 } ) ) ;
288359 build_compiler
289360 }
290361 Mode :: Rustc => {
@@ -304,15 +375,17 @@ fn prepare_compiler_for_check(
304375 // stage 0 stdlib is used to compile build scripts and proc macros.
305376 builder. compiler ( builder. top_stage , host)
306377 }
307- }
378+ } ;
379+ CompilerForCheck { build_compiler, rustc_rmeta_sysroot : rmeta_sysroot }
308380}
309381
310382/// Checks a single codegen backend.
311383#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
312384pub 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 ,
316389}
317390
318391impl Step for CodegenBackend {
@@ -326,9 +399,17 @@ impl Step for CodegenBackend {
326399
327400 fn make_run ( run : RunConfig < ' _ > ) {
328401 // 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" ) ;
330406 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+ } ) ;
332413 }
333414 }
334415
@@ -351,6 +432,7 @@ impl Step for CodegenBackend {
351432 target,
352433 builder. kind ,
353434 ) ;
435+ self . rmeta_sysroot . configure_cargo ( & mut cargo) ;
354436
355437 cargo
356438 . arg ( "--manifest-path" )
@@ -388,8 +470,8 @@ macro_rules! tool_check_step {
388470 ) => {
389471 #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
390472 pub struct $name {
391- pub build_compiler : Compiler ,
392- pub target: TargetSelection ,
473+ compiler : CompilerForCheck ,
474+ target: TargetSelection ,
393475 }
394476
395477 impl Step for $name {
@@ -407,31 +489,31 @@ macro_rules! tool_check_step {
407489 let builder = run. builder;
408490 let mode = $mode( builder) ;
409491
410- let build_compiler = prepare_compiler_for_check( run. builder, target, mode) ;
492+ let compiler = prepare_compiler_for_check( run. builder, target, mode) ;
411493
412494 // It doesn't make sense to cross-check bootstrap tools
413495 if mode == Mode :: ToolBootstrap && target != run. builder. host_target {
414496 println!( "WARNING: not checking bootstrap tool {} for target {target} as it is a bootstrap (host-only) tool" , stringify!( $path) ) ;
415497 return ;
416498 } ;
417499
418- run. builder. ensure( $name { target, build_compiler } ) ;
500+ run. builder. ensure( $name { target, compiler } ) ;
419501 }
420502
421503 fn run( self , builder: & Builder <' _>) {
422- let Self { target, build_compiler } = self ;
504+ let Self { target, compiler } = self ;
423505 let allow_features = {
424506 let mut _value = "" ;
425507 $( _value = $allow_features; ) ?
426508 _value
427509 } ;
428510 let extra_features: & [ & str ] = & [ $( $( $enable_features) ,* ) ?] ;
429511 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) ;
431513 }
432514
433515 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) )
435517 }
436518 }
437519 }
@@ -440,7 +522,7 @@ macro_rules! tool_check_step {
440522/// Used by the implementation of `Step::run` in `tool_check_step!`.
441523fn run_tool_check_step (
442524 builder : & Builder < ' _ > ,
443- build_compiler : Compiler ,
525+ compiler : CompilerForCheck ,
444526 target : TargetSelection ,
445527 path : & str ,
446528 mode : Mode ,
@@ -449,6 +531,8 @@ fn run_tool_check_step(
449531) {
450532 let display_name = path. rsplit ( '/' ) . next ( ) . unwrap ( ) ;
451533
534+ let CompilerForCheck { build_compiler, rustc_rmeta_sysroot : rmeta_sysroot } = compiler;
535+
452536 let extra_features = extra_features. iter ( ) . map ( |f| f. to_string ( ) ) . collect :: < Vec < String > > ( ) ;
453537 let mut cargo = prepare_tool_cargo (
454538 builder,
@@ -465,6 +549,11 @@ fn run_tool_check_step(
465549 & extra_features,
466550 ) ;
467551 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+ }
468557
469558 // FIXME: check bootstrap doesn't currently work when multiple targets are checked
470559 // FIXME: rust-analyzer does not work with --all-targets
0 commit comments