@@ -13,10 +13,11 @@ use std::path::{Path, PathBuf};
1313use std:: sync:: OnceLock ;
1414
1515use build_helper:: ci:: CiEnv ;
16+ use build_helper:: git:: get_closest_merge_commit;
1617
1718use crate :: Config ;
1819use crate :: core:: builder:: { Builder , Cargo , Kind , RunConfig , ShouldRun , Step } ;
19- use crate :: core:: config:: TargetSelection ;
20+ use crate :: core:: config:: { GccCiMode , TargetSelection } ;
2021use crate :: utils:: build_stamp:: { BuildStamp , generate_smart_stamp_hash} ;
2122use crate :: utils:: exec:: command;
2223use crate :: utils:: helpers:: { self , t} ;
@@ -89,17 +90,39 @@ pub enum GccBuildStatus {
8990 ShouldBuild ( Meta ) ,
9091}
9192
92- /// This returns whether we've already previously built GCC.
93+ /// Tries to download GCC from CI if it is enabled and GCC artifacts
94+ /// are available for the given target.
95+ /// Returns a path to the libgccjit.so file.
96+ fn try_download_gcc ( builder : & Builder < ' _ > , target : TargetSelection ) -> Option < PathBuf > {
97+ // Try to download GCC from CI if configured and available
98+ if !matches ! ( builder. config. gcc_ci_mode, GccCiMode :: DownloadFromCi ) {
99+ return None ;
100+ }
101+ if target != "x86_64-unknown-linux-gnu" {
102+ eprintln ! ( "GCC CI download is only available for the `x86_64-unknown-linux-gnu` target" ) ;
103+ return None ;
104+ }
105+ let sha =
106+ detect_gcc_sha ( & builder. config , builder. config . rust_info . is_managed_git_subrepository ( ) ) ;
107+ let root = ci_gcc_root ( & builder. config ) ;
108+ let gcc_stamp = BuildStamp :: new ( & root) . with_prefix ( "gcc" ) . add_stamp ( & sha) ;
109+ if !gcc_stamp. is_up_to_date ( ) && !builder. config . dry_run ( ) {
110+ builder. config . download_ci_gcc ( & sha, & root) ;
111+ t ! ( gcc_stamp. write( ) ) ;
112+ }
113+ // FIXME: put libgccjit.so into a lib directory in dist::Gcc
114+ Some ( root. join ( "libgccjit.so" ) )
115+ }
116+
117+ /// This returns information about whether GCC should be built or if it's already built.
118+ /// It transparently handles downloading GCC from CI if needed.
93119///
94120/// It's used to avoid busting caches during x.py check -- if we've already built
95121/// GCC, it's fine for us to not try to avoid doing so.
96122pub fn get_gcc_build_status ( builder : & Builder < ' _ > , target : TargetSelection ) -> GccBuildStatus {
97- // Initialize the gcc submodule if not initialized already.
98- builder. config . update_submodule ( "src/gcc" ) ;
99-
100- let root = builder. src . join ( "src/gcc" ) ;
101- let out_dir = builder. gcc_out ( target) . join ( "build" ) ;
102- let install_dir = builder. gcc_out ( target) . join ( "install" ) ;
123+ if let Some ( path) = try_download_gcc ( builder, target) {
124+ return GccBuildStatus :: AlreadyBuilt ( path) ;
125+ }
103126
104127 static STAMP_HASH_MEMO : OnceLock < String > = OnceLock :: new ( ) ;
105128 let smart_stamp_hash = STAMP_HASH_MEMO . get_or_init ( || {
@@ -110,6 +133,13 @@ pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> G
110133 )
111134 } ) ;
112135
136+ // Initialize the gcc submodule if not initialized already.
137+ builder. config . update_submodule ( "src/gcc" ) ;
138+
139+ let root = builder. src . join ( "src/gcc" ) ;
140+ let out_dir = builder. gcc_out ( target) . join ( "build" ) ;
141+ let install_dir = builder. gcc_out ( target) . join ( "install" ) ;
142+
113143 let stamp = BuildStamp :: new ( & out_dir) . with_prefix ( "gcc" ) . add_stamp ( smart_stamp_hash) ;
114144
115145 if stamp. is_up_to_date ( ) {
@@ -142,7 +172,7 @@ fn libgccjit_built_path(install_dir: &Path) -> PathBuf {
142172 install_dir. join ( "lib/libgccjit.so" )
143173}
144174
145- fn build_gcc ( metadata : & Meta , builder : & Builder , target : TargetSelection ) {
175+ fn build_gcc ( metadata : & Meta , builder : & Builder < ' _ > , target : TargetSelection ) {
146176 let Meta { stamp : _, out_dir, install_dir, root } = metadata;
147177
148178 t ! ( fs:: create_dir_all( out_dir) ) ;
@@ -202,21 +232,51 @@ fn build_gcc(metadata: &Meta, builder: &Builder, target: TargetSelection) {
202232 }
203233 configure_cmd. run ( builder) ;
204234
205- command ( "make" )
206- . current_dir ( & out_dir)
207- . arg ( "--silent" )
208- . arg ( format ! ( "-j{}" , builder. jobs( ) ) )
209- . run_capture_stdout ( builder) ;
210- command ( "make" )
211- . current_dir ( & out_dir)
212- . arg ( "--silent" )
213- . arg ( "install" )
214- . run_capture_stdout ( builder) ;
215- }
235+ command ( "make" )
236+ . current_dir ( & out_dir)
237+ . arg ( "--silent" )
238+ . arg ( format ! ( "-j{}" , builder. jobs( ) ) )
239+ . run_capture_stdout ( builder) ;
240+ command ( "make" )
241+ . current_dir ( & out_dir)
242+ . arg ( "--silent" )
243+ . arg ( "install" )
244+ . run_capture_stdout ( builder) ;
216245}
217246
218247/// Configures a Cargo invocation so that it can build the GCC codegen backend.
219248pub fn add_cg_gcc_cargo_flags ( cargo : & mut Cargo , gcc : & GccOutput ) {
220249 // Add the path to libgccjit.so to the linker search paths.
221250 cargo. rustflag ( & format ! ( "-L{}" , gcc. libgccjit. parent( ) . unwrap( ) . to_str( ) . unwrap( ) ) ) ;
222251}
252+
253+ /// The absolute path to the downloaded GCC artifacts.
254+ fn ci_gcc_root ( config : & Config ) -> PathBuf {
255+ config. out . join ( config. build ) . join ( "ci-gcc" )
256+ }
257+
258+ /// This retrieves the GCC sha we *want* to use, according to git history.
259+ fn detect_gcc_sha ( config : & Config , is_git : bool ) -> String {
260+ let gcc_sha = if is_git {
261+ get_closest_merge_commit (
262+ Some ( & config. src ) ,
263+ & config. git_config ( ) ,
264+ & [ config. src . join ( "src/gcc" ) , config. src . join ( "src/bootstrap/download-ci-gcc-stamp" ) ] ,
265+ )
266+ . unwrap ( )
267+ } else if let Some ( info) = crate :: utils:: channel:: read_commit_info_file ( & config. src ) {
268+ info. sha . trim ( ) . to_owned ( )
269+ } else {
270+ "" . to_owned ( )
271+ } ;
272+
273+ if gcc_sha. is_empty ( ) {
274+ eprintln ! ( "error: could not find commit hash for downloading GCC" ) ;
275+ eprintln ! ( "HELP: maybe your repository history is too shallow?" ) ;
276+ eprintln ! ( "HELP: consider disabling `download-ci-gcc`" ) ;
277+ eprintln ! ( "HELP: or fetch enough history to include one upstream commit" ) ;
278+ panic ! ( ) ;
279+ }
280+
281+ gcc_sha
282+ }
0 commit comments