@@ -9,7 +9,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun,
99use crate :: core:: config:: TargetSelection ;
1010use crate :: utils:: channel:: GitInfo ;
1111use crate :: utils:: exec:: { command, BootstrapCommand } ;
12- use crate :: utils:: helpers:: { add_dylib_path, exe, t} ;
12+ use crate :: utils:: helpers:: { add_dylib_path, exe, get_closest_merge_base_commit , git , t} ;
1313use crate :: Compiler ;
1414use crate :: Mode ;
1515use crate :: { gha, Kind } ;
@@ -554,6 +554,57 @@ impl Step for Rustdoc {
554554 }
555555 let target = target_compiler. host ;
556556
557+ let bin_rustdoc = || {
558+ let sysroot = builder. sysroot ( target_compiler) ;
559+ let bindir = sysroot. join ( "bin" ) ;
560+ t ! ( fs:: create_dir_all( & bindir) ) ;
561+ let bin_rustdoc = bindir. join ( exe ( "rustdoc" , target_compiler. host ) ) ;
562+ let _ = fs:: remove_file ( & bin_rustdoc) ;
563+ bin_rustdoc
564+ } ;
565+
566+ // If CI rustc is enabled and we haven't modified the rustdoc sources,
567+ // use the precompiled rustdoc from CI rustc's sysroot to speed up bootstrapping.
568+ if builder. download_rustc ( )
569+ && target_compiler. stage > 0
570+ && builder. rust_info ( ) . is_managed_git_subrepository ( )
571+ {
572+ let commit = get_closest_merge_base_commit (
573+ Some ( & builder. config . src ) ,
574+ & builder. config . git_config ( ) ,
575+ & builder. config . stage0_metadata . config . git_merge_commit_email ,
576+ & [ ] ,
577+ )
578+ . unwrap ( ) ;
579+
580+ let librustdoc_src = builder. config . src . join ( "src/librustdoc" ) ;
581+ let rustdoc_src = builder. config . src . join ( "src/tools/rustdoc" ) ;
582+
583+ // FIXME: The change detection logic here is quite similar to `Config::download_ci_rustc_commit`.
584+ // It would be better to unify them.
585+ let has_changes = !git ( Some ( & builder. config . src ) )
586+ . allow_failure ( )
587+ . run_always ( )
588+ . args ( [ "diff-index" , "--quiet" , & commit] )
589+ . arg ( "--" )
590+ . arg ( librustdoc_src)
591+ . arg ( rustdoc_src)
592+ . run ( builder)
593+ . is_success ( ) ;
594+
595+ if !has_changes {
596+ let precompiled_rustdoc = builder
597+ . config
598+ . ci_rustc_dir ( )
599+ . join ( "bin" )
600+ . join ( exe ( "rustdoc" , target_compiler. host ) ) ;
601+
602+ let bin_rustdoc = bin_rustdoc ( ) ;
603+ builder. copy_link ( & precompiled_rustdoc, & bin_rustdoc) ;
604+ return bin_rustdoc;
605+ }
606+ }
607+
557608 let build_compiler = if builder. download_rustc ( ) && target_compiler. stage == 1 {
558609 // We already have the stage 1 compiler, we don't need to cut the stage.
559610 builder. compiler ( target_compiler. stage , builder. config . build )
@@ -614,11 +665,7 @@ impl Step for Rustdoc {
614665
615666 // don't create a stage0-sysroot/bin directory.
616667 if target_compiler. stage > 0 {
617- let sysroot = builder. sysroot ( target_compiler) ;
618- let bindir = sysroot. join ( "bin" ) ;
619- t ! ( fs:: create_dir_all( & bindir) ) ;
620- let bin_rustdoc = bindir. join ( exe ( "rustdoc" , target_compiler. host ) ) ;
621- let _ = fs:: remove_file ( & bin_rustdoc) ;
668+ let bin_rustdoc = bin_rustdoc ( ) ;
622669 builder. copy_link ( & tool_rustdoc, & bin_rustdoc) ;
623670 bin_rustdoc
624671 } else {
0 commit comments