@@ -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,82 @@ 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
+ if build. config . fast_submodules {
111
+ let checked_out_hash = output (
112
+ Command :: new ( "git" )
113
+ . args ( & [ "rev-parse" , "HEAD" ] )
114
+ . current_dir ( build. config . src . join ( llvm_project) ) ,
115
+ ) ;
116
+ // update_submodules
117
+ let recorded = output (
118
+ Command :: new ( "git" )
119
+ . args ( & [ "ls-tree" , "HEAD" ] )
120
+ . arg ( llvm_project)
121
+ . current_dir ( & build. config . src ) ,
122
+ ) ;
123
+ let actual_hash = recorded
124
+ . split_whitespace ( )
125
+ . nth ( 2 )
126
+ . unwrap_or_else ( || panic ! ( "unexpected output `{}`" , recorded) ) ;
127
+
128
+ // update_submodule
129
+ if actual_hash == checked_out_hash. trim_end ( ) {
130
+ // already checked out
131
+ return ;
132
+ }
133
+ }
134
+
135
+ println ! ( "Updating submodule {}" , llvm_project. display( ) ) ;
136
+ build. run (
137
+ Command :: new ( "git" )
138
+ . args ( & [ "submodule" , "-q" , "sync" ] )
139
+ . arg ( llvm_project)
140
+ . current_dir ( & build. config . src ) ,
141
+ ) ;
142
+
143
+ // Try passing `--progress` to start, then run git again without if that fails.
144
+ let update = |progress : bool | {
145
+ let mut git = Command :: new ( "git" ) ;
146
+ git. args ( & [ "submodule" , "update" , "--init" , "--recursive" ] ) ;
147
+ if progress {
148
+ git. arg ( "--progress" ) ;
149
+ }
150
+ git. arg ( llvm_project) . current_dir ( & build. config . src ) ;
151
+ git
152
+ } ;
153
+ // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
154
+ if !update ( true ) . status ( ) . map_or ( false , |status| status. success ( ) ) {
155
+ build. run ( & mut update ( false ) ) ;
156
+ }
157
+
158
+ build. run (
159
+ Command :: new ( "git" )
160
+ . args ( & [ "reset" , "-q" , "--hard" ] )
161
+ . current_dir ( build. config . src . join ( llvm_project) ) ,
162
+ ) ;
163
+ build. run (
164
+ Command :: new ( "git" )
165
+ . args ( & [ "clean" , "-qdfx" ] )
166
+ . current_dir ( build. config . src . join ( llvm_project) ) ,
167
+ ) ;
168
+ }
169
+
94
170
#[ derive( Debug , Copy , Clone , Hash , PartialEq , Eq ) ]
95
171
pub struct Llvm {
96
172
pub target : TargetSelection ,
@@ -128,6 +204,9 @@ impl Step for Llvm {
128
204
Err ( m) => m,
129
205
} ;
130
206
207
+ if !builder. config . dry_run {
208
+ update_llvm_submodule ( builder) ;
209
+ }
131
210
if builder. config . llvm_link_shared
132
211
&& ( target. contains ( "windows" ) || target. contains ( "apple-darwin" ) )
133
212
{
0 commit comments