Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move llvm submodule updates to rustbuild #81601

Merged
merged 2 commits into from
May 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions src/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,28 +991,20 @@ def update_submodules(self):
).decode(default_encoding).splitlines()]
filtered_submodules = []
submodules_names = []
llvm_checked_out = os.path.exists(os.path.join(self.rust_root, "src/llvm-project/.git"))
external_llvm_provided = self.get_toml('llvm-config') or self.downloading_llvm()
llvm_needed = not self.get_toml('codegen-backends', 'rust') \
or "llvm" in self.get_toml('codegen-backends', 'rust')
for module in submodules:
# This is handled by native::Llvm in rustbuild, not here
if module.endswith("llvm-project"):
# Don't sync the llvm-project submodule if an external LLVM was
# provided, if we are downloading LLVM or if the LLVM backend is
# not being built. Also, if the submodule has been initialized
# already, sync it anyways so that it doesn't mess up contributor
# pull requests.
Comment on lines -1002 to -1004
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sync is no longer done with this PR I believe when using ./x.py check instead of ./x.py build.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems fine though? x.py check shouldn't require building LLVM at all.

Copy link
Member

@bjorn3 bjorn3 Mar 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user pulls master with a LLVM update, makes some changes, does ./x.py check to verify their changes and then git add -a, the commit will contain a submodule change as the LLVM submodule wasn't updated when this PR is merged. This is what is meant with "messing up contributor pull requests". Before ./x.py check would update the submodule, ensuring that the right submodule version is commited.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm well I'm not 100% convinced how useful that is, but I'll change it for now to be consistent with bootstrap.py

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this doesn't work with init-repo.sh. Even if I call update_llvm_submodule unconditionally, if src/llvm-project/.git exists, it will skip the check unconditionally: https://github.com/rust-lang/rust/blob/6bda460cb0d21acef3cf44cc2ea8b379abc7d5c4/src/bootstrap/native.rs#L104-L109

I don't know how to fix this :/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I'm being dumb, init-repo.sh sets submodules = false, I can just use that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's critical that we update the submodule if it exists, independent of whether the LLVM step is hit.

if external_llvm_provided or not llvm_needed:
if self.get_toml('lld') != 'true' and not llvm_checked_out:
continue
continue
check = self.check_submodule(module, slow_submodules)
filtered_submodules.append((module, check))
submodules_names.append(module)
recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names,
cwd=self.rust_root, stdout=subprocess.PIPE)
recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines()
# { filename: hash }
recorded_submodules = {}
for data in recorded:
# [mode, kind, hash, filename]
data = data.split()
recorded_submodules[data[3]] = data[2]
for module in filtered_submodules:
Expand Down
10 changes: 10 additions & 0 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,12 +472,22 @@ impl Build {
slice::from_ref(&self.build.triple)
}

/// If the LLVM submodule has been initialized already, sync it unconditionally. This avoids
/// contributors checking in a submodule change by accident.
pub fn maybe_update_llvm_submodule(&self) {
if self.in_tree_llvm_info.is_git() {
native::update_llvm_submodule(self);
}
}

/// Executes the entire build, as configured by the flags and configuration.
pub fn build(&mut self) {
unsafe {
job::setup(self);
}

self.maybe_update_llvm_submodule();

if let Subcommand::Format { check, paths } = &self.config.cmd {
return format::format(self, *check, &paths);
}
Expand Down
84 changes: 83 additions & 1 deletion src/bootstrap/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use build_helper::{output, t};
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::config::TargetSelection;
use crate::util::{self, exe};
use crate::GitRepo;
use crate::{Build, GitRepo};
use build_helper::up_to_date;

pub struct Meta {
Expand Down Expand Up @@ -91,6 +91,85 @@ pub fn prebuilt_llvm_config(
Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() })
}

// modified from `check_submodule` and `update_submodule` in bootstrap.py
pub(crate) fn update_llvm_submodule(build: &Build) {
let llvm_project = &Path::new("src").join("llvm-project");

fn dir_is_empty(dir: &Path) -> bool {
t!(std::fs::read_dir(dir)).next().is_none()
}

// NOTE: The check for the empty directory is here because when running x.py
// the first time, the llvm submodule won't be checked out. Check it out
// now so we can build it.
if !build.in_tree_llvm_info.is_git() && !dir_is_empty(&build.config.src.join(llvm_project)) {
return;
}

// check_submodule
let checked_out = if build.config.fast_submodules {
Some(output(
Command::new("git")
.args(&["rev-parse", "HEAD"])
.current_dir(build.config.src.join(llvm_project)),
))
} else {
None
};

// update_submodules
let recorded = output(
Command::new("git")
.args(&["ls-tree", "HEAD"])
.arg(llvm_project)
.current_dir(&build.config.src),
);
let hash =
recorded.split(' ').nth(2).unwrap_or_else(|| panic!("unexpected output `{}`", recorded));

// update_submodule
if let Some(llvm_hash) = checked_out {
if hash == llvm_hash {
// already checked out
return;
}
}

println!("Updating submodule {}", llvm_project.display());
build.run(
Command::new("git")
.args(&["submodule", "-q", "sync"])
.arg(llvm_project)
.current_dir(&build.config.src),
);

// Try passing `--progress` to start, then run git again without if that fails.
let update = |progress: bool| {
let mut git = Command::new("git");
git.args(&["submodule", "update", "--init", "--recursive"]);
if progress {
git.arg("--progress");
}
git.arg(llvm_project).current_dir(&build.config.src);
git
};
// NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
if !update(true).status().map_or(false, |status| status.success()) {
build.run(&mut update(false));
}

build.run(
Command::new("git")
.args(&["reset", "-q", "--hard"])
.current_dir(build.config.src.join(llvm_project)),
);
build.run(
Command::new("git")
.args(&["clean", "-qdfx"])
.current_dir(build.config.src.join(llvm_project)),
);
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Llvm {
pub target: TargetSelection,
Expand Down Expand Up @@ -128,6 +207,9 @@ impl Step for Llvm {
Err(m) => m,
};

if !builder.config.dry_run {
update_llvm_submodule(builder);
}
if builder.config.llvm_link_shared
&& (target.contains("windows") || target.contains("apple-darwin"))
{
Expand Down
1 change: 1 addition & 0 deletions src/build_helper/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ pub fn make(host: &str) -> PathBuf {
}
}

#[track_caller]
pub fn output(cmd: &mut Command) -> String {
let output = match cmd.stderr(Stdio::inherit()).output() {
Ok(status) => status,
Expand Down