Skip to content

Commit 3f83906

Browse files
committed
Auto merge of #98483 - dvtkrlbs:bootstrap-dist, r=jyn514
Distribute bootstrap in CI This pre-compiles bootstrap from source and adds it to the existing `rust-dev` component. There are two main goals here: 1. Make it faster to build rust from source, both the first time and incrementally 2. Make it easier to add non-python entrypoints, since they can call out to bootstrap directly rather than having to figure out the right flags to pre-compile it. This second part is still in a bit of flux, see the tracking issue below for more information. There are also several changes to make bootstrap able to run on a machine other than the one it was built (particularly around `config.src` and `config.out` detection). I (`@jyn514)` am slightly concerned these will regress unless tested - maybe we should add an automated test that runs bootstrap in a chroot or something? Unclear whether the effort is worth the test coverage. Helps with #94829.
2 parents 6580010 + 2ef3d17 commit 3f83906

File tree

7 files changed

+122
-39
lines changed

7 files changed

+122
-39
lines changed

.github/workflows/ci.yml

+10-10
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ jobs:
297297
os: ubuntu-20.04-xl
298298
- name: dist-x86_64-apple
299299
env:
300-
SCRIPT: "./x.py dist --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
300+
SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
301301
RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
302302
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
303303
MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -308,7 +308,7 @@ jobs:
308308
os: macos-latest
309309
- name: dist-apple-various
310310
env:
311-
SCRIPT: "./x.py dist --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
311+
SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
312312
RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
313313
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
314314
MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -318,7 +318,7 @@ jobs:
318318
os: macos-latest
319319
- name: dist-x86_64-apple-alt
320320
env:
321-
SCRIPT: "./x.py dist"
321+
SCRIPT: "./x.py dist bootstrap --include-default-paths"
322322
RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
323323
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
324324
MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -350,7 +350,7 @@ jobs:
350350
os: macos-latest
351351
- name: dist-aarch64-apple
352352
env:
353-
SCRIPT: "./x.py dist --stage 2"
353+
SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
354354
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false"
355355
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
356356
USE_XCODE_CLANG: 1
@@ -424,33 +424,33 @@ jobs:
424424
- name: dist-x86_64-msvc
425425
env:
426426
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
427-
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist
427+
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
428428
DIST_REQUIRE_ALL_TOOLS: 1
429429
os: windows-latest-xl
430430
- name: dist-i686-msvc
431431
env:
432432
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler"
433-
SCRIPT: python x.py dist
433+
SCRIPT: python x.py dist bootstrap --include-default-paths
434434
DIST_REQUIRE_ALL_TOOLS: 1
435435
os: windows-latest-xl
436436
- name: dist-aarch64-msvc
437437
env:
438438
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
439-
SCRIPT: python x.py dist
439+
SCRIPT: python x.py dist bootstrap --include-default-paths
440440
DIST_REQUIRE_ALL_TOOLS: 1
441441
WINDOWS_SDK_20348_HACK: 1
442442
os: windows-latest-xl
443443
- name: dist-i686-mingw
444444
env:
445445
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
446446
NO_DOWNLOAD_CI_LLVM: 1
447-
SCRIPT: python x.py dist
447+
SCRIPT: python x.py dist bootstrap --include-default-paths
448448
CUSTOM_MINGW: 1
449449
DIST_REQUIRE_ALL_TOOLS: 1
450450
os: windows-latest-xl
451451
- name: dist-x86_64-mingw
452452
env:
453-
SCRIPT: python x.py dist
453+
SCRIPT: python x.py dist bootstrap --include-default-paths
454454
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
455455
NO_DOWNLOAD_CI_LLVM: 1
456456
CUSTOM_MINGW: 1
@@ -459,7 +459,7 @@ jobs:
459459
- name: dist-x86_64-msvc-alt
460460
env:
461461
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-extended --enable-profiler"
462-
SCRIPT: python x.py dist
462+
SCRIPT: python x.py dist bootstrap --include-default-paths
463463
os: windows-latest-xl
464464
timeout-minutes: 600
465465
runs-on: "${{ matrix.os }}"

src/bootstrap/builder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ impl<'a> Builder<'a> {
724724
dist::Miri,
725725
dist::LlvmTools,
726726
dist::RustDev,
727+
dist::Bootstrap,
727728
dist::Extended,
728729
// It seems that PlainSourceTarball somehow changes how some of the tools
729730
// perceive their dependencies (see #93033) which would invalidate fingerprints

src/bootstrap/config.rs

+52-4
Original file line numberDiff line numberDiff line change
@@ -772,21 +772,20 @@ impl Config {
772772

773773
// set by build.rs
774774
config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
775+
775776
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
776777
// Undo `src/bootstrap`
777778
config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned();
778779
config.out = PathBuf::from("build");
779780

780-
config.initial_cargo = PathBuf::from(env!("CARGO"));
781-
config.initial_rustc = PathBuf::from(env!("RUSTC"));
782-
783781
config
784782
}
785783

786784
pub fn parse(args: &[String]) -> Config {
787785
let flags = Flags::parse(&args);
788-
789786
let mut config = Config::default_opts();
787+
788+
// Set flags.
790789
config.exclude = flags.exclude.into_iter().map(|path| TaskPath::parse(path)).collect();
791790
config.include_default_paths = flags.include_default_paths;
792791
config.rustc_error_format = flags.rustc_error_format;
@@ -805,7 +804,49 @@ impl Config {
805804
config.llvm_profile_use = flags.llvm_profile_use;
806805
config.llvm_profile_generate = flags.llvm_profile_generate;
807806

807+
// Infer the rest of the configuration.
808+
809+
// Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
810+
// running on a completely machine from where it was compiled.
811+
let mut cmd = Command::new("git");
812+
// NOTE: we cannot support running from outside the repository because the only path we have available
813+
// is set at compile time, which can be wrong if bootstrap was downloaded from source.
814+
// We still support running outside the repository if we find we aren't in a git directory.
815+
cmd.arg("rev-parse").arg("--show-toplevel");
816+
// Discard stderr because we expect this to fail when building from a tarball.
817+
let output = cmd
818+
.stderr(std::process::Stdio::null())
819+
.output()
820+
.ok()
821+
.and_then(|output| if output.status.success() { Some(output) } else { None });
822+
if let Some(output) = output {
823+
let git_root = String::from_utf8(output.stdout).unwrap();
824+
// We need to canonicalize this path to make sure it uses backslashes instead of forward slashes.
825+
let git_root = PathBuf::from(git_root.trim()).canonicalize().unwrap();
826+
let s = git_root.to_str().unwrap();
827+
828+
// Bootstrap is quite bad at handling /? in front of paths
829+
config.src = match s.strip_prefix("\\\\?\\") {
830+
Some(p) => PathBuf::from(p),
831+
None => PathBuf::from(git_root),
832+
};
833+
} else {
834+
// We're building from a tarball, not git sources.
835+
// We don't support pre-downloaded bootstrap in this case.
836+
}
837+
838+
if cfg!(test) {
839+
// Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
840+
config.out = Path::new(
841+
&env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"),
842+
)
843+
.parent()
844+
.unwrap()
845+
.to_path_buf();
846+
}
847+
808848
let stage0_json = t!(std::fs::read(&config.src.join("src").join("stage0.json")));
849+
809850
config.stage0_metadata = t!(serde_json::from_slice::<Stage0Metadata>(&stage0_json));
810851

811852
#[cfg(test)]
@@ -860,6 +901,7 @@ impl Config {
860901
config.config = toml_path;
861902

862903
let build = toml.build.unwrap_or_default();
904+
let has_custom_rustc = build.rustc.is_some();
863905

864906
set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
865907
set(&mut config.out, flags.build_dir.or_else(|| build.build_dir.map(PathBuf::from)));
@@ -870,6 +912,12 @@ impl Config {
870912
config.out = crate::util::absolute(&config.out);
871913
}
872914

915+
if !has_custom_rustc && !config.initial_rustc.starts_with(&config.out) {
916+
config.initial_rustc = config.out.join(config.build.triple).join("stage0/bin/rustc");
917+
config.initial_cargo = config.out.join(config.build.triple).join("stage0/bin/cargo");
918+
}
919+
920+
// NOTE: it's important this comes *after* we set `initial_rustc` just above.
873921
if config.dry_run {
874922
let dir = config.out.join("tmp-dry-run");
875923
t!(fs::create_dir_all(&dir));

src/bootstrap/dist.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -1879,7 +1879,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
18791879
let mut cmd = Command::new(llvm_config);
18801880
cmd.arg("--libfiles");
18811881
builder.verbose(&format!("running {:?}", cmd));
1882-
let files = output(&mut cmd);
1882+
let files = if builder.config.dry_run { "".into() } else { output(&mut cmd) };
18831883
let build_llvm_out = &builder.llvm_out(builder.config.build);
18841884
let target_llvm_out = &builder.llvm_out(target);
18851885
for file in files.trim_end().split(' ') {
@@ -2057,6 +2057,41 @@ impl Step for RustDev {
20572057
}
20582058
}
20592059

2060+
// Tarball intended for internal consumption to ease rustc/std development.
2061+
//
2062+
// Should not be considered stable by end users.
2063+
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2064+
pub struct Bootstrap {
2065+
pub target: TargetSelection,
2066+
}
2067+
2068+
impl Step for Bootstrap {
2069+
type Output = Option<GeneratedTarball>;
2070+
const DEFAULT: bool = false;
2071+
const ONLY_HOSTS: bool = true;
2072+
2073+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2074+
run.alias("bootstrap")
2075+
}
2076+
2077+
fn make_run(run: RunConfig<'_>) {
2078+
run.builder.ensure(Bootstrap { target: run.target });
2079+
}
2080+
2081+
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2082+
let target = self.target;
2083+
2084+
let tarball = Tarball::new(builder, "bootstrap", &target.triple);
2085+
2086+
let bootstrap_outdir = &builder.bootstrap_out;
2087+
for file in &["bootstrap", "llvm-config-wrapper", "rustc", "rustdoc", "sccache-plus-cl"] {
2088+
tarball.add_file(bootstrap_outdir.join(exe(file, target)), "bootstrap/bin", 0o755);
2089+
}
2090+
2091+
Some(tarball.generate())
2092+
}
2093+
}
2094+
20602095
/// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the
20612096
/// release process to avoid cloning the monorepo and building stuff.
20622097
///

src/bootstrap/lib.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -458,19 +458,18 @@ impl Build {
458458
.expect("failed to read src/version");
459459
let version = version.trim();
460460

461-
let bootstrap_out = if std::env::var("BOOTSTRAP_PYTHON").is_ok() {
462-
out.join("bootstrap").join("debug")
463-
} else {
464-
let workspace_target_dir = std::env::var("CARGO_TARGET_DIR")
465-
.map(PathBuf::from)
466-
.unwrap_or_else(|_| src.join("target"));
467-
let bootstrap_out = workspace_target_dir.join("debug");
468-
if !bootstrap_out.join("rustc").exists() && !cfg!(test) {
469-
// this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
470-
panic!("run `cargo build --bins` before `cargo run`")
471-
}
472-
bootstrap_out
473-
};
461+
let bootstrap_out = std::env::current_exe()
462+
.expect("could not determine path to running process")
463+
.parent()
464+
.unwrap()
465+
.to_path_buf();
466+
if !bootstrap_out.join(exe("rustc", config.build)).exists() && !cfg!(test) {
467+
// this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
468+
panic!(
469+
"`rustc` not found in {}, run `cargo build --bins` before `cargo run`",
470+
bootstrap_out.display()
471+
)
472+
}
474473

475474
let mut build = Build {
476475
initial_rustc: config.initial_rustc.clone(),

src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ ENV RUST_CONFIGURE_ARGS \
8282
ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \
8383
--host $HOSTS --target $HOSTS \
8484
--include-default-paths \
85-
build-manifest
85+
build-manifest bootstrap
8686
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
8787

8888
# This is the only builder which will create source tarballs

src/ci/github-actions/ci.yml

+10-10
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ jobs:
462462

463463
- name: dist-x86_64-apple
464464
env:
465-
SCRIPT: ./x.py dist --host=x86_64-apple-darwin --target=x86_64-apple-darwin
465+
SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
466466
RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
467467
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
468468
MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -474,7 +474,7 @@ jobs:
474474

475475
- name: dist-apple-various
476476
env:
477-
SCRIPT: ./x.py dist --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim
477+
SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim
478478
RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
479479
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
480480
MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -485,7 +485,7 @@ jobs:
485485

486486
- name: dist-x86_64-apple-alt
487487
env:
488-
SCRIPT: ./x.py dist
488+
SCRIPT: ./x.py dist bootstrap --include-default-paths
489489
RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
490490
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
491491
MACOSX_DEPLOYMENT_TARGET: 10.7
@@ -515,7 +515,7 @@ jobs:
515515
# This target only needs to support 11.0 and up as nothing else supports the hardware
516516
- name: dist-aarch64-apple
517517
env:
518-
SCRIPT: ./x.py dist --stage 2
518+
SCRIPT: ./x.py dist bootstrap --include-default-paths --stage 2
519519
RUST_CONFIGURE_ARGS: >-
520520
--build=x86_64-apple-darwin
521521
--host=aarch64-apple-darwin
@@ -659,7 +659,7 @@ jobs:
659659
--target=x86_64-pc-windows-msvc
660660
--enable-full-tools
661661
--enable-profiler
662-
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist
662+
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
663663
DIST_REQUIRE_ALL_TOOLS: 1
664664
<<: *job-windows-xl
665665

@@ -671,7 +671,7 @@ jobs:
671671
--target=i686-pc-windows-msvc,i586-pc-windows-msvc
672672
--enable-full-tools
673673
--enable-profiler
674-
SCRIPT: python x.py dist
674+
SCRIPT: python x.py dist bootstrap --include-default-paths
675675
DIST_REQUIRE_ALL_TOOLS: 1
676676
<<: *job-windows-xl
677677

@@ -682,7 +682,7 @@ jobs:
682682
--host=aarch64-pc-windows-msvc
683683
--enable-full-tools
684684
--enable-profiler
685-
SCRIPT: python x.py dist
685+
SCRIPT: python x.py dist bootstrap --include-default-paths
686686
DIST_REQUIRE_ALL_TOOLS: 1
687687
# Hack around this SDK version, because it doesn't work with clang.
688688
# See https://github.com/rust-lang/rust/issues/88796
@@ -699,14 +699,14 @@ jobs:
699699
# We are intentionally allowing an old toolchain on this builder (and that's
700700
# incompatible with LLVM downloads today).
701701
NO_DOWNLOAD_CI_LLVM: 1
702-
SCRIPT: python x.py dist
702+
SCRIPT: python x.py dist bootstrap --include-default-paths
703703
CUSTOM_MINGW: 1
704704
DIST_REQUIRE_ALL_TOOLS: 1
705705
<<: *job-windows-xl
706706

707707
- name: dist-x86_64-mingw
708708
env:
709-
SCRIPT: python x.py dist
709+
SCRIPT: python x.py dist bootstrap --include-default-paths
710710
RUST_CONFIGURE_ARGS: >-
711711
--build=x86_64-pc-windows-gnu
712712
--enable-full-tools
@@ -722,7 +722,7 @@ jobs:
722722
- name: dist-x86_64-msvc-alt
723723
env:
724724
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
725-
SCRIPT: python x.py dist
725+
SCRIPT: python x.py dist bootstrap --include-default-paths
726726
<<: *job-windows-xl
727727

728728
try:

0 commit comments

Comments
 (0)