@@ -14,13 +14,72 @@ use std::sync::OnceLock;
14
14
15
15
use build_helper:: ci:: CiEnv ;
16
16
17
- use crate :: Kind ;
18
- use crate :: core:: builder:: { Builder , RunConfig , ShouldRun , Step } ;
17
+ use crate :: core:: builder:: { Builder , Cargo , Kind , RunConfig , ShouldRun , Step } ;
19
18
use crate :: core:: config:: TargetSelection ;
20
19
use crate :: utils:: build_stamp:: { BuildStamp , generate_smart_stamp_hash} ;
21
20
use crate :: utils:: exec:: command;
22
21
use crate :: utils:: helpers:: { self , t} ;
23
22
23
+ #[ derive( Debug , Clone , Hash , PartialEq , Eq ) ]
24
+ pub struct Gcc {
25
+ pub target : TargetSelection ,
26
+ }
27
+
28
+ #[ derive( Clone ) ]
29
+ pub struct GccOutput {
30
+ pub libgccjit : PathBuf ,
31
+ }
32
+
33
+ impl Step for Gcc {
34
+ type Output = GccOutput ;
35
+
36
+ const ONLY_HOSTS : bool = true ;
37
+
38
+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
39
+ run. path ( "src/gcc" ) . alias ( "gcc" )
40
+ }
41
+
42
+ fn make_run ( run : RunConfig < ' _ > ) {
43
+ run. builder . ensure ( Gcc { target : run. target } ) ;
44
+ }
45
+
46
+ /// Compile GCC (specifically `libgccjit`) for `target`.
47
+ fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
48
+ let target = self . target ;
49
+
50
+ // If GCC has already been built, we avoid building it again.
51
+ let metadata = match get_gcc_build_status ( builder, target) {
52
+ GccBuildStatus :: AlreadyBuilt ( path) => return GccOutput { libgccjit : path } ,
53
+ GccBuildStatus :: ShouldBuild ( m) => m,
54
+ } ;
55
+
56
+ let _guard = builder. msg_unstaged ( Kind :: Build , "GCC" , target) ;
57
+ t ! ( metadata. stamp. remove( ) ) ;
58
+ let _time = helpers:: timeit ( builder) ;
59
+
60
+ let libgccjit_path = libgccjit_built_path ( & metadata. install_dir ) ;
61
+ if builder. config . dry_run ( ) {
62
+ return GccOutput { libgccjit : libgccjit_path } ;
63
+ }
64
+
65
+ build_gcc ( & metadata, builder, target) ;
66
+ create_lib_alias ( builder, & libgccjit_path) ;
67
+
68
+ t ! ( metadata. stamp. write( ) ) ;
69
+
70
+ GccOutput { libgccjit : libgccjit_path }
71
+ }
72
+ }
73
+
74
+ /// Creates a libgccjit.so.0 alias next to libgccjit.so if it does not
75
+ /// already exist
76
+ fn create_lib_alias ( builder : & Builder < ' _ > , libgccjit : & PathBuf ) {
77
+ let lib_alias = libgccjit. parent ( ) . unwrap ( ) . join ( "libgccjit.so.0" ) ;
78
+ if !lib_alias. exists ( ) {
79
+ t ! ( builder. symlink_file( libgccjit, lib_alias) ) ;
80
+ }
81
+ }
82
+
24
83
pub struct Meta {
25
84
stamp : BuildStamp ,
26
85
out_dir : PathBuf ,
@@ -33,7 +92,54 @@ pub enum GccBuildStatus {
33
92
ShouldBuild ( Meta ) ,
34
93
}
35
94
36
- /// This returns whether we've already previously built GCC.
95
+ /// Tries to download GCC from CI if it is enabled and GCC artifacts
96
+ /// are available for the given target.
97
+ /// Returns a path to the libgccjit.so file.
98
+ #[ cfg( not( test) ) ]
99
+ fn try_download_gcc ( builder : & Builder < ' _ > , target : TargetSelection ) -> Option < PathBuf > {
100
+ use build_helper:: git:: PathFreshness ;
101
+
102
+ // Try to download GCC from CI if configured and available
103
+ if !matches ! ( builder. config. gcc_ci_mode, crate :: core:: config:: GccCiMode :: DownloadFromCi ) {
104
+ return None ;
105
+ }
106
+ if target != "x86_64-unknown-linux-gnu" {
107
+ eprintln ! ( "GCC CI download is only available for the `x86_64-unknown-linux-gnu` target" ) ;
108
+ return None ;
109
+ }
110
+ let source = detect_gcc_freshness (
111
+ & builder. config ,
112
+ builder. config . rust_info . is_managed_git_subrepository ( ) ,
113
+ ) ;
114
+ match source {
115
+ PathFreshness :: LastModifiedUpstream { upstream } => {
116
+ // Download from upstream CI
117
+ let root = ci_gcc_root ( & builder. config ) ;
118
+ let gcc_stamp = BuildStamp :: new ( & root) . with_prefix ( "gcc" ) . add_stamp ( & upstream) ;
119
+ if !gcc_stamp. is_up_to_date ( ) && !builder. config . dry_run ( ) {
120
+ builder. config . download_ci_gcc ( & upstream, & root) ;
121
+ t ! ( gcc_stamp. write( ) ) ;
122
+ }
123
+
124
+ let libgccjit = root. join ( "lib" ) . join ( "libgccjit.so" ) ;
125
+ create_lib_alias ( builder, & libgccjit) ;
126
+ Some ( libgccjit)
127
+ }
128
+ PathFreshness :: HasLocalModifications { .. } => {
129
+ // We have local modifications, rebuild GCC.
130
+ eprintln ! ( "Found local GCC modifications, GCC will *not* be downloaded" ) ;
131
+ None
132
+ }
133
+ }
134
+ }
135
+
136
+ #[ cfg( test) ]
137
+ fn try_download_gcc ( _builder : & Builder < ' _ > , _target : TargetSelection ) -> Option < PathBuf > {
138
+ None
139
+ }
140
+
141
+ /// This returns information about whether GCC should be built or if it's already built.
142
+ /// It transparently handles downloading GCC from CI if needed.
37
143
///
38
144
/// It's used to avoid busting caches during x.py check -- if we've already built
39
145
/// GCC, it's fine for us to not try to avoid doing so.
@@ -178,6 +284,34 @@ impl Step for Gcc {
178
284
179
285
t ! ( stamp. write( ) ) ;
180
286
181
- true
182
- }
287
+ /// Detect whether GCC sources have been modified locally or not.
288
+ #[ cfg( not( test) ) ]
289
+ fn detect_gcc_freshness ( config : & crate :: Config , is_git : bool ) -> build_helper:: git:: PathFreshness {
290
+ use build_helper:: git:: { PathFreshness , check_path_modifications} ;
291
+
292
+ let freshness = if is_git {
293
+ Some (
294
+ check_path_modifications (
295
+ Some ( & config. src ) ,
296
+ & config. git_config ( ) ,
297
+ & [ "src/gcc" , "src/bootstrap/download-ci-gcc-stamp" ] ,
298
+ CiEnv :: current ( ) ,
299
+ )
300
+ . unwrap ( ) ,
301
+ )
302
+ } else if let Some ( info) = crate :: utils:: channel:: read_commit_info_file ( & config. src ) {
303
+ Some ( PathFreshness :: LastModifiedUpstream { upstream : info. sha . trim ( ) . to_owned ( ) } )
304
+ } else {
305
+ None
306
+ } ;
307
+
308
+ let Some ( freshness) = freshness else {
309
+ eprintln ! ( "error: could not find commit hash for downloading GCC" ) ;
310
+ eprintln ! ( "HELP: maybe your repository history is too shallow?" ) ;
311
+ eprintln ! ( "HELP: consider disabling `download-ci-gcc`" ) ;
312
+ eprintln ! ( "HELP: or fetch enough history to include one upstream commit" ) ;
313
+ panic ! ( ) ;
314
+ } ;
315
+
316
+ freshness
183
317
}
0 commit comments