Skip to content

Commit 55c040e

Browse files
committed
Make it possible to run bootstrap on a different machine than the one it was built
- Default to trying git rev-parse for the root directory CARGO_MANIFEST_DIR is a path on the build machine, not the running machine. Don't require this to succeed, to allow building from a tarball; in that case fall back to CARGO_MANIFEST_DIR. - Set `initial_rustc` to a path based on the path of the running executable, not CARGO_MANIFEST_DIR. We only reset `initial_rustc` if we're sure this isn't the working tree bootstrap was originally built in, since I'm paranoid that setting this in other cases will cause things to break; it's not clear to me when $RUSTC differs from `build/$TARGET/stage0/bin/rustc` (maybe never? but better to be sure). Instead, only set this when a) We are not using a custom rustc. If someone has specified a custom rustc we should respect their wishes. b) We are in a checkout of rust-lang/rust other than the one bootstrap was built in.
1 parent 63f6289 commit 55c040e

File tree

1 file changed

+44
-4
lines changed

1 file changed

+44
-4
lines changed

src/bootstrap/config.rs

Lines changed: 44 additions & 4 deletions
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,41 @@ 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+
config.src = PathBuf::from(git_root.trim().to_owned())
825+
} else {
826+
// We're building from a tarball, not git sources.
827+
// We don't support pre-downloaded bootstrap in this case.
828+
}
829+
830+
if cfg!(test) {
831+
// Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
832+
config.out = Path::new(
833+
&env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"),
834+
)
835+
.parent()
836+
.unwrap()
837+
.to_path_buf();
838+
}
839+
808840
let stage0_json = t!(std::fs::read(&config.src.join("src").join("stage0.json")));
841+
809842
config.stage0_metadata = t!(serde_json::from_slice::<Stage0Metadata>(&stage0_json));
810843

811844
#[cfg(test)]
@@ -860,6 +893,7 @@ impl Config {
860893
config.config = toml_path;
861894

862895
let build = toml.build.unwrap_or_default();
896+
let has_custom_rustc = build.rustc.is_some();
863897

864898
set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
865899
set(&mut config.out, flags.build_dir.or_else(|| build.build_dir.map(PathBuf::from)));
@@ -870,6 +904,12 @@ impl Config {
870904
config.out = crate::util::absolute(&config.out);
871905
}
872906

907+
if !has_custom_rustc && !config.initial_rustc.starts_with(&config.out) {
908+
config.initial_rustc = config.out.join(config.build.triple).join("stage0/bin/rustc");
909+
config.initial_cargo = config.out.join(config.build.triple).join("stage0/bin/cargo");
910+
}
911+
912+
// NOTE: it's important this comes *after* we set `initial_rustc` just above.
873913
if config.dry_run {
874914
let dir = config.out.join("tmp-dry-run");
875915
t!(fs::create_dir_all(&dir));

0 commit comments

Comments
 (0)