Skip to content

Commit a40b294

Browse files
authored
Rollup merge of rust-lang#127463 - onur-ozkan:precompiled-rustdoc, r=Kobzol
use precompiled rustdoc with CI rustc When CI rustc is enabled and rustdoc sources are unchanged, we can use the precompiled rustdoc from the CI rustc's sysroot. This speeds up bootstrapping quite a lot by avoiding unnecessary rustdoc compilation.
2 parents 1afc5fd + 0636293 commit a40b294

File tree

5 files changed

+107
-47
lines changed

5 files changed

+107
-47
lines changed

src/bootstrap/src/core/build_steps/llvm.rs

+12-21
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind};
2626

2727
use crate::utils::exec::command;
2828
use build_helper::ci::CiEnv;
29-
use build_helper::git::get_git_merge_base;
3029

3130
#[derive(Clone)]
3231
pub struct LlvmResult {
@@ -154,26 +153,18 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
154153
/// This retrieves the LLVM sha we *want* to use, according to git history.
155154
pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
156155
let llvm_sha = if is_git {
157-
// We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we
158-
// walk back further to the last bors merge commit that actually changed LLVM. The first
159-
// step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD`
160-
// in that case.
161-
let closest_upstream = get_git_merge_base(&config.git_config(), Some(&config.src))
162-
.unwrap_or_else(|_| "HEAD".into());
163-
let mut rev_list = helpers::git(Some(&config.src));
164-
rev_list.args(&[
165-
PathBuf::from("rev-list"),
166-
format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(),
167-
"-n1".into(),
168-
"--first-parent".into(),
169-
closest_upstream.into(),
170-
"--".into(),
171-
config.src.join("src/llvm-project"),
172-
config.src.join("src/bootstrap/download-ci-llvm-stamp"),
173-
// the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
174-
config.src.join("src/version"),
175-
]);
176-
output(rev_list.as_command_mut()).trim().to_owned()
156+
helpers::get_closest_merge_base_commit(
157+
Some(&config.src),
158+
&config.git_config(),
159+
&config.stage0_metadata.config.git_merge_commit_email,
160+
&[
161+
config.src.join("src/llvm-project"),
162+
config.src.join("src/bootstrap/download-ci-llvm-stamp"),
163+
// the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
164+
config.src.join("src/version"),
165+
],
166+
)
167+
.unwrap()
177168
} else if let Some(info) = channel::read_commit_info_file(&config.src) {
178169
info.sha.trim().to_owned()
179170
} else {

src/bootstrap/src/core/build_steps/tool.rs

+53-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun,
99
use crate::core::config::TargetSelection;
1010
use crate::utils::channel::GitInfo;
1111
use 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};
1313
use crate::Compiler;
1414
use crate::Mode;
1515
use 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 {

src/bootstrap/src/core/config/config.rs

+17-19
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::core::build_steps::llvm;
2020
use crate::core::config::flags::{Color, Flags, Warnings};
2121
use crate::utils::cache::{Interned, INTERNER};
2222
use crate::utils::channel::{self, GitInfo};
23-
use crate::utils::helpers::{self, exe, output, t};
23+
use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t};
2424
use build_helper::exit;
2525
use serde::{Deserialize, Deserializer};
2626
use serde_derive::Deserialize;
@@ -2471,14 +2471,13 @@ impl Config {
24712471

24722472
// Look for a version to compare to based on the current commit.
24732473
// Only commits merged by bors will have CI artifacts.
2474-
let merge_base = output(
2475-
helpers::git(Some(&self.src))
2476-
.arg("rev-list")
2477-
.arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
2478-
.args(["-n1", "--first-parent", "HEAD"])
2479-
.as_command_mut(),
2480-
);
2481-
let commit = merge_base.trim_end();
2474+
let commit = get_closest_merge_base_commit(
2475+
Some(&self.src),
2476+
&self.git_config(),
2477+
&self.stage0_metadata.config.git_merge_commit_email,
2478+
&[],
2479+
)
2480+
.unwrap();
24822481
if commit.is_empty() {
24832482
println!("ERROR: could not find commit hash for downloading rustc");
24842483
println!("HELP: maybe your repository history is too shallow?");
@@ -2489,7 +2488,7 @@ impl Config {
24892488

24902489
// Warn if there were changes to the compiler or standard library since the ancestor commit.
24912490
let has_changes = !t!(helpers::git(Some(&self.src))
2492-
.args(["diff-index", "--quiet", commit])
2491+
.args(["diff-index", "--quiet", &commit])
24932492
.arg("--")
24942493
.args([self.src.join("compiler"), self.src.join("library")])
24952494
.as_command_mut()
@@ -2565,14 +2564,13 @@ impl Config {
25652564
) -> Option<String> {
25662565
// Look for a version to compare to based on the current commit.
25672566
// Only commits merged by bors will have CI artifacts.
2568-
let merge_base = output(
2569-
helpers::git(Some(&self.src))
2570-
.arg("rev-list")
2571-
.arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
2572-
.args(["-n1", "--first-parent", "HEAD"])
2573-
.as_command_mut(),
2574-
);
2575-
let commit = merge_base.trim_end();
2567+
let commit = get_closest_merge_base_commit(
2568+
Some(&self.src),
2569+
&self.git_config(),
2570+
&self.stage0_metadata.config.git_merge_commit_email,
2571+
&[],
2572+
)
2573+
.unwrap();
25762574
if commit.is_empty() {
25772575
println!("error: could not find commit hash for downloading components from CI");
25782576
println!("help: maybe your repository history is too shallow?");
@@ -2583,7 +2581,7 @@ impl Config {
25832581

25842582
// Warn if there were changes to the compiler or standard library since the ancestor commit.
25852583
let mut git = helpers::git(Some(&self.src));
2586-
git.args(["diff-index", "--quiet", commit, "--"]);
2584+
git.args(["diff-index", "--quiet", &commit, "--"]);
25872585

25882586
// Handle running from a directory other than the top level
25892587
let top_level = &self.src;

src/bootstrap/src/utils/helpers.rs

+24
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! Simple things like testing the various filesystem operations here and there,
44
//! not a lot of interesting happenings here unfortunately.
55
6+
use build_helper::git::{get_git_merge_base, output_result, GitConfig};
67
use build_helper::util::fail;
78
use std::env;
89
use std::ffi::OsStr;
@@ -521,3 +522,26 @@ pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
521522

522523
git
523524
}
525+
526+
/// Returns the closest commit available from upstream for the given `author` and `target_paths`.
527+
///
528+
/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD.
529+
pub fn get_closest_merge_base_commit(
530+
source_dir: Option<&Path>,
531+
config: &GitConfig<'_>,
532+
author: &str,
533+
target_paths: &[PathBuf],
534+
) -> Result<String, String> {
535+
let mut git = git(source_dir).capture_stdout();
536+
537+
let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into());
538+
539+
git.arg(Path::new("rev-list"));
540+
git.args([&format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
541+
542+
if !target_paths.is_empty() {
543+
git.arg("--").args(target_paths);
544+
}
545+
546+
Ok(output_result(git.as_command_mut())?.trim().to_owned())
547+
}

src/tools/build_helper/src/git.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub struct GitConfig<'a> {
77
}
88

99
/// Runs a command and returns the output
10-
fn output_result(cmd: &mut Command) -> Result<String, String> {
10+
pub fn output_result(cmd: &mut Command) -> Result<String, String> {
1111
let output = match cmd.stderr(Stdio::inherit()).output() {
1212
Ok(status) => status,
1313
Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)),

0 commit comments

Comments
 (0)