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.
This commit is contained in:
Joshua Nelson 2022-09-14 18:19:28 -05:00
parent 63f6289db2
commit 55c040e529

View file

@ -772,21 +772,20 @@ impl Config {
// set by build.rs
config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
// Undo `src/bootstrap`
config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned();
config.out = PathBuf::from("build");
config.initial_cargo = PathBuf::from(env!("CARGO"));
config.initial_rustc = PathBuf::from(env!("RUSTC"));
config
}
pub fn parse(args: &[String]) -> Config {
let flags = Flags::parse(&args);
let mut config = Config::default_opts();
// Set flags.
config.exclude = flags.exclude.into_iter().map(|path| TaskPath::parse(path)).collect();
config.include_default_paths = flags.include_default_paths;
config.rustc_error_format = flags.rustc_error_format;
@ -805,7 +804,41 @@ impl Config {
config.llvm_profile_use = flags.llvm_profile_use;
config.llvm_profile_generate = flags.llvm_profile_generate;
// Infer the rest of the configuration.
// Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
// running on a completely machine from where it was compiled.
let mut cmd = Command::new("git");
// NOTE: we cannot support running from outside the repository because the only path we have available
// is set at compile time, which can be wrong if bootstrap was downloaded from source.
// We still support running outside the repository if we find we aren't in a git directory.
cmd.arg("rev-parse").arg("--show-toplevel");
// Discard stderr because we expect this to fail when building from a tarball.
let output = cmd
.stderr(std::process::Stdio::null())
.output()
.ok()
.and_then(|output| if output.status.success() { Some(output) } else { None });
if let Some(output) = output {
let git_root = String::from_utf8(output.stdout).unwrap();
config.src = PathBuf::from(git_root.trim().to_owned())
} else {
// We're building from a tarball, not git sources.
// We don't support pre-downloaded bootstrap in this case.
}
if cfg!(test) {
// Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
config.out = Path::new(
&env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"),
)
.parent()
.unwrap()
.to_path_buf();
}
let stage0_json = t!(std::fs::read(&config.src.join("src").join("stage0.json")));
config.stage0_metadata = t!(serde_json::from_slice::<Stage0Metadata>(&stage0_json));
#[cfg(test)]
@ -860,6 +893,7 @@ impl Config {
config.config = toml_path;
let build = toml.build.unwrap_or_default();
let has_custom_rustc = build.rustc.is_some();
set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
set(&mut config.out, flags.build_dir.or_else(|| build.build_dir.map(PathBuf::from)));
@ -870,6 +904,12 @@ impl Config {
config.out = crate::util::absolute(&config.out);
}
if !has_custom_rustc && !config.initial_rustc.starts_with(&config.out) {
config.initial_rustc = config.out.join(config.build.triple).join("stage0/bin/rustc");
config.initial_cargo = config.out.join(config.build.triple).join("stage0/bin/cargo");
}
// NOTE: it's important this comes *after* we set `initial_rustc` just above.
if config.dry_run {
let dir = config.out.join("tmp-dry-run");
t!(fs::create_dir_all(&dir));