@@ -21,7 +21,7 @@ use build_helper::{output, t};
21
21
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
22
22
use crate::config::TargetSelection;
23
23
use crate::util::{self, exe};
24
- use crate::GitRepo;
24
+ use crate::{Build, GitRepo} ;
25
25
use build_helper::up_to_date;
26
26
27
27
pub struct Meta {
@@ -91,6 +91,85 @@ pub fn prebuilt_llvm_config(
91
91
Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() })
92
92
}
93
93
94
+ // modified from `check_submodule` and `update_submodule` in bootstrap.py
95
+ pub(crate) fn update_llvm_submodule(build: &Build) {
96
+ let llvm_project = &Path::new("src").join("llvm-project");
97
+
98
+ fn dir_is_empty(dir: &Path) -> bool {
99
+ t!(std::fs::read_dir(dir)).next().is_none()
100
+ }
101
+
102
+ // NOTE: The check for the empty directory is here because when running x.py
103
+ // the first time, the llvm submodule won't be checked out. Check it out
104
+ // now so we can build it.
105
+ if !build.in_tree_llvm_info.is_git() && !dir_is_empty(&build.config.src.join(llvm_project)) {
106
+ return;
107
+ }
108
+
109
+ // check_submodule
110
+ let checked_out = if build.config.fast_submodules {
111
+ Some(output(
112
+ Command::new("git")
113
+ .args(&["rev-parse", "HEAD"])
114
+ .current_dir(build.config.src.join(llvm_project)),
115
+ ))
116
+ } else {
117
+ None
118
+ };
119
+
120
+ // update_submodules
121
+ let recorded = output(
122
+ Command::new("git")
123
+ .args(&["ls-tree", "HEAD"])
124
+ .arg(llvm_project)
125
+ .current_dir(&build.config.src),
126
+ );
127
+ let hash =
128
+ recorded.split(' ').nth(2).unwrap_or_else(|| panic!("unexpected output `{}`", recorded));
129
+
130
+ // update_submodule
131
+ if let Some(llvm_hash) = checked_out {
132
+ if hash == llvm_hash {
133
+ // already checked out
134
+ return;
135
+ }
136
+ }
137
+
138
+ println!("Updating submodule {}", llvm_project.display());
139
+ build.run(
140
+ Command::new("git")
141
+ .args(&["submodule", "-q", "sync"])
142
+ .arg(llvm_project)
143
+ .current_dir(&build.config.src),
144
+ );
145
+
146
+ // Try passing `--progress` to start, then run git again without if that fails.
147
+ let update = |progress: bool| {
148
+ let mut git = Command::new("git");
149
+ git.args(&["submodule", "update", "--init", "--recursive"]);
150
+ if progress {
151
+ git.arg("--progress");
152
+ }
153
+ git.arg(llvm_project).current_dir(&build.config.src);
154
+ git
155
+ };
156
+ // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
157
+ if !update(true).status().map_or(false, |status| status.success()) {
158
+ build.run(&mut update(false));
159
+ }
160
+
161
+ build.run(
162
+ Command::new("git")
163
+ .args(&["reset", "-q", "--hard"])
164
+ .current_dir(build.config.src.join(llvm_project)),
165
+ );
166
+ build.run(
167
+ Command::new("git")
168
+ .args(&["clean", "-qdfx"])
169
+ .current_dir(build.config.src.join(llvm_project)),
170
+ );
171
+ }
172
+
94
173
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
95
174
pub struct Llvm {
96
175
pub target: TargetSelection,
@@ -128,6 +207,9 @@ impl Step for Llvm {
128
207
Err(m) => m,
129
208
};
130
209
210
+ if !builder.config.dry_run {
211
+ update_llvm_submodule(builder);
212
+ }
131
213
if builder.config.llvm_link_shared
132
214
&& (target.contains("windows") || target.contains("apple-darwin"))
133
215
{
0 commit comments