@@ -13,10 +13,11 @@ use std::path::{Path, PathBuf};
13
13
use std:: sync:: OnceLock ;
14
14
15
15
use build_helper:: ci:: CiEnv ;
16
+ use build_helper:: git:: get_closest_merge_commit;
16
17
17
18
use crate :: Config ;
18
19
use crate :: core:: builder:: { Builder , Cargo , Kind , RunConfig , ShouldRun , Step } ;
19
- use crate :: core:: config:: TargetSelection ;
20
+ use crate :: core:: config:: { GccCiMode , TargetSelection } ;
20
21
use crate :: utils:: build_stamp:: { BuildStamp , generate_smart_stamp_hash} ;
21
22
use crate :: utils:: exec:: command;
22
23
use crate :: utils:: helpers:: { self , t} ;
@@ -89,18 +90,12 @@ pub enum GccBuildStatus {
89
90
ShouldBuild ( Meta ) ,
90
91
}
91
92
92
- /// This returns whether we've already previously built GCC.
93
+ /// This returns information about whether GCC should be built or if it's already built.
94
+ /// It transparently handles downloading GCC from CI if needed.
93
95
///
94
96
/// It's used to avoid busting caches during x.py check -- if we've already built
95
97
/// GCC, it's fine for us to not try to avoid doing so.
96
98
pub 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" ) ;
103
-
104
99
static STAMP_HASH_MEMO : OnceLock < String > = OnceLock :: new ( ) ;
105
100
let smart_stamp_hash = STAMP_HASH_MEMO . get_or_init ( || {
106
101
generate_smart_stamp_hash (
@@ -110,6 +105,35 @@ pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> G
110
105
)
111
106
} ) ;
112
107
108
+ // Try to download GCC from CI if configured and available
109
+ if let GccCiMode :: DownloadFromCi = & builder. config . gcc_ci_mode {
110
+ if builder. build . build == "x86_64-unknown-linux-gnu" {
111
+ let sha = detect_gcc_sha (
112
+ & builder. config ,
113
+ builder. config . rust_info . is_managed_git_subrepository ( ) ,
114
+ ) ;
115
+ let root = ci_gcc_root ( & builder. config ) ;
116
+ let gcc_stamp = BuildStamp :: new ( & root) . with_prefix ( "gcc" ) . add_stamp ( & sha) ;
117
+ if !gcc_stamp. is_up_to_date ( ) && !builder. config . dry_run ( ) {
118
+ builder. config . download_ci_gcc ( & sha, & root) ;
119
+ t ! ( gcc_stamp. write( ) ) ;
120
+ }
121
+ // FIXME: put libgccjit.so into a lib directory in dist::Gcc
122
+ return GccBuildStatus :: AlreadyBuilt ( root. join ( "libgccjit.so" ) ) ;
123
+ } else {
124
+ eprintln ! (
125
+ "GCC CI download is only available for the `x86_64-unknown-linux-gnu` target"
126
+ ) ;
127
+ }
128
+ }
129
+
130
+ // Initialize the gcc submodule if not initialized already.
131
+ builder. config . update_submodule ( "src/gcc" ) ;
132
+
133
+ let root = builder. src . join ( "src/gcc" ) ;
134
+ let out_dir = builder. gcc_out ( target) . join ( "build" ) ;
135
+ let install_dir = builder. gcc_out ( target) . join ( "install" ) ;
136
+
113
137
let stamp = BuildStamp :: new ( & out_dir) . with_prefix ( "gcc" ) . add_stamp ( smart_stamp_hash) ;
114
138
115
139
if stamp. is_up_to_date ( ) {
@@ -142,7 +166,7 @@ fn libgccjit_built_path(install_dir: &Path) -> PathBuf {
142
166
install_dir. join ( "lib/libgccjit.so" )
143
167
}
144
168
145
- fn build_gcc ( metadata : & Meta , builder : & Builder , target : TargetSelection ) {
169
+ fn build_gcc ( metadata : & Meta , builder : & Builder < ' _ > , target : TargetSelection ) {
146
170
let Meta { stamp : _, out_dir, install_dir, root } = metadata;
147
171
148
172
t ! ( fs:: create_dir_all( out_dir) ) ;
@@ -210,3 +234,34 @@ pub fn add_cg_gcc_cargo_flags(cargo: &mut Cargo, gcc: &GccOutput) {
210
234
// Add the path to libgccjit.so to the linker search paths.
211
235
cargo. rustflag ( & format ! ( "-L{}" , gcc. libgccjit. parent( ) . unwrap( ) . to_str( ) . unwrap( ) ) ) ;
212
236
}
237
+
238
+ /// The absolute path to the downloaded GCC artifacts.
239
+ fn ci_gcc_root ( config : & Config ) -> PathBuf {
240
+ config. out . join ( config. build ) . join ( "ci-gcc" )
241
+ }
242
+
243
+ /// This retrieves the GCC sha we *want* to use, according to git history.
244
+ fn detect_gcc_sha ( config : & Config , is_git : bool ) -> String {
245
+ let gcc_sha = if is_git {
246
+ get_closest_merge_commit (
247
+ Some ( & config. src ) ,
248
+ & config. git_config ( ) ,
249
+ & [ config. src . join ( "src/gcc" ) , config. src . join ( "src/bootstrap/download-ci-gcc-stamp" ) ] ,
250
+ )
251
+ . unwrap ( )
252
+ } else if let Some ( info) = crate :: utils:: channel:: read_commit_info_file ( & config. src ) {
253
+ info. sha . trim ( ) . to_owned ( )
254
+ } else {
255
+ "" . to_owned ( )
256
+ } ;
257
+
258
+ if gcc_sha. is_empty ( ) {
259
+ eprintln ! ( "error: could not find commit hash for downloading GCC" ) ;
260
+ eprintln ! ( "HELP: maybe your repository history is too shallow?" ) ;
261
+ eprintln ! ( "HELP: consider disabling `download-ci-gcc`" ) ;
262
+ eprintln ! ( "HELP: or fetch enough history to include one upstream commit" ) ;
263
+ panic ! ( ) ;
264
+ }
265
+
266
+ gcc_sha
267
+ }
0 commit comments