@@ -21,7 +21,7 @@ use build_helper::{output, t};
2121use crate :: builder:: { Builder , RunConfig , ShouldRun , Step } ;
2222use crate :: config:: TargetSelection ;
2323use crate :: util:: { self , exe} ;
24- use crate :: GitRepo ;
24+ use crate :: { Build , GitRepo } ;
2525use build_helper:: up_to_date;
2626
2727pub struct Meta {
@@ -91,6 +91,85 @@ pub fn prebuilt_llvm_config(
9191 Err ( Meta { stamp, build_llvm_config, out_dir, root : root. into ( ) } )
9292}
9393
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+
94173#[ derive( Debug , Copy , Clone , Hash , PartialEq , Eq ) ]
95174pub struct Llvm {
96175 pub target : TargetSelection ,
@@ -128,6 +207,9 @@ impl Step for Llvm {
128207 Err ( m) => m,
129208 } ;
130209
210+ if !builder. config . dry_run {
211+ update_llvm_submodule ( builder) ;
212+ }
131213 if builder. config . llvm_link_shared
132214 && ( target. contains ( "windows" ) || target. contains ( "apple-darwin" ) )
133215 {
0 commit comments