@@ -14,13 +14,68 @@ 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 , Cargo , RunConfig , ShouldRun , Step } ;
17
+ use crate :: Config ;
18
+ use crate :: core:: builder:: { Builder , Cargo , Kind , RunConfig , ShouldRun , Step } ;
19
19
use crate :: core:: config:: TargetSelection ;
20
20
use crate :: utils:: build_stamp:: { BuildStamp , generate_smart_stamp_hash} ;
21
21
use crate :: utils:: exec:: command;
22
22
use crate :: utils:: helpers:: { self , t} ;
23
23
24
+ #[ derive( Debug , Clone , Hash , PartialEq , Eq ) ]
25
+ pub struct Gcc {
26
+ pub target : TargetSelection ,
27
+ }
28
+
29
+ #[ derive( Clone ) ]
30
+ pub struct GccOutput {
31
+ pub libgccjit : PathBuf ,
32
+ }
33
+
34
+ impl Step for Gcc {
35
+ type Output = GccOutput ;
36
+
37
+ const ONLY_HOSTS : bool = true ;
38
+
39
+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
40
+ run. path ( "src/gcc" ) . alias ( "gcc" )
41
+ }
42
+
43
+ fn make_run ( run : RunConfig < ' _ > ) {
44
+ run. builder . ensure ( Gcc { target : run. target } ) ;
45
+ }
46
+
47
+ /// Compile GCC (specifically `libgccjit`) for `target`.
48
+ fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
49
+ let target = self . target ;
50
+
51
+ // If GCC has already been built, we avoid building it again.
52
+ let metadata = match get_gcc_build_status ( builder, target) {
53
+ GccBuildStatus :: AlreadyBuilt ( path) => return GccOutput { libgccjit : path } ,
54
+ GccBuildStatus :: ShouldBuild ( m) => m,
55
+ } ;
56
+
57
+ let _guard = builder. msg_unstaged ( Kind :: Build , "GCC" , target) ;
58
+ t ! ( metadata. stamp. remove( ) ) ;
59
+ let _time = helpers:: timeit ( builder) ;
60
+
61
+ let libgccjit_path = libgccjit_built_path ( & metadata. install_dir ) ;
62
+ if builder. config . dry_run ( ) {
63
+ return GccOutput { libgccjit : libgccjit_path } ;
64
+ }
65
+
66
+ build_gcc ( & metadata, builder, target) ;
67
+
68
+ let lib_alias = metadata. install_dir . join ( "lib/libgccjit.so.0" ) ;
69
+ if !lib_alias. exists ( ) {
70
+ t ! ( builder. symlink_file( & libgccjit_path, lib_alias) ) ;
71
+ }
72
+
73
+ t ! ( metadata. stamp. write( ) ) ;
74
+
75
+ GccOutput { libgccjit : libgccjit_path }
76
+ }
77
+ }
78
+
24
79
pub struct Meta {
25
80
stamp : BuildStamp ,
26
81
out_dir : PathBuf ,
@@ -38,7 +93,7 @@ pub enum GccBuildStatus {
38
93
///
39
94
/// It's used to avoid busting caches during x.py check -- if we've already built
40
95
/// GCC, it's fine for us to not try to avoid doing so.
41
- pub fn prebuilt_gcc_config ( builder : & Builder < ' _ > , target : TargetSelection ) -> GccBuildStatus {
96
+ pub fn get_gcc_build_status ( builder : & Builder < ' _ > , target : TargetSelection ) -> GccBuildStatus {
42
97
// Initialize the gcc submodule if not initialized already.
43
98
builder. config . update_submodule ( "src/gcc" ) ;
44
99
@@ -87,104 +142,65 @@ fn libgccjit_built_path(install_dir: &Path) -> PathBuf {
87
142
install_dir. join ( "lib/libgccjit.so" )
88
143
}
89
144
90
- #[ derive( Debug , Clone , Hash , PartialEq , Eq ) ]
91
- pub struct Gcc {
92
- pub target : TargetSelection ,
93
- }
94
-
95
- #[ derive( Clone ) ]
96
- pub struct GccOutput {
97
- pub libgccjit : PathBuf ,
98
- }
99
-
100
- impl Step for Gcc {
101
- type Output = GccOutput ;
102
-
103
- const ONLY_HOSTS : bool = true ;
104
-
105
- fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
106
- run. path ( "src/gcc" ) . alias ( "gcc" )
107
- }
108
-
109
- fn make_run ( run : RunConfig < ' _ > ) {
110
- run. builder . ensure ( Gcc { target : run. target } ) ;
111
- }
112
-
113
- /// Compile GCC (specifically `libgccjit`) for `target`.
114
- fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
115
- let target = self . target ;
116
-
117
- // If GCC has already been built, we avoid building it again.
118
- let Meta { stamp, out_dir, install_dir, root } = match prebuilt_gcc_config ( builder, target)
119
- {
120
- GccBuildStatus :: AlreadyBuilt ( path) => return GccOutput { libgccjit : path } ,
121
- GccBuildStatus :: ShouldBuild ( m) => m,
122
- } ;
123
-
124
- let _guard = builder. msg_unstaged ( Kind :: Build , "GCC" , target) ;
125
- t ! ( stamp. remove( ) ) ;
126
- let _time = helpers:: timeit ( builder) ;
127
- t ! ( fs:: create_dir_all( & out_dir) ) ;
128
- t ! ( fs:: create_dir_all( & install_dir) ) ;
129
-
130
- let libgccjit_path = libgccjit_built_path ( & install_dir) ;
131
- if builder. config . dry_run ( ) {
132
- return GccOutput { libgccjit : libgccjit_path } ;
145
+ fn build_gcc ( metadata : & Meta , builder : & Builder , target : TargetSelection ) {
146
+ let Meta { stamp : _, out_dir, install_dir, root } = metadata;
147
+
148
+ t ! ( fs:: create_dir_all( out_dir) ) ;
149
+ t ! ( fs:: create_dir_all( install_dir) ) ;
150
+
151
+ // GCC creates files (e.g. symlinks to the downloaded dependencies)
152
+ // in the source directory, which does not work with our CI setup, where we mount
153
+ // source directories as read-only on Linux.
154
+ // Therefore, as a part of the build in CI, we first copy the whole source directory
155
+ // to the build directory, and perform the build from there.
156
+ let src_dir = if CiEnv :: is_ci ( ) {
157
+ let src_dir = builder. gcc_out ( target) . join ( "src" ) ;
158
+ if src_dir. exists ( ) {
159
+ builder. remove_dir ( & src_dir) ;
133
160
}
134
-
135
- // GCC creates files (e.g. symlinks to the downloaded dependencies)
136
- // in the source directory, which does not work with our CI setup, where we mount
137
- // source directories as read-only on Linux.
138
- // Therefore, as a part of the build in CI, we first copy the whole source directory
139
- // to the build directory, and perform the build from there.
140
- let src_dir = if CiEnv :: is_ci ( ) {
141
- let src_dir = builder. gcc_out ( target) . join ( "src" ) ;
142
- if src_dir. exists ( ) {
143
- builder. remove_dir ( & src_dir) ;
144
- }
145
- builder. create_dir ( & src_dir) ;
146
- builder. cp_link_r ( & root, & src_dir) ;
147
- src_dir
148
- } else {
149
- root
150
- } ;
151
-
152
- command ( src_dir. join ( "contrib/download_prerequisites" ) ) . current_dir ( & src_dir) . run ( builder) ;
153
- let mut configure_cmd = command ( src_dir. join ( "configure" ) ) ;
154
- configure_cmd
155
- . current_dir ( & out_dir)
156
- // On CI, we compile GCC with Clang.
157
- // The -Wno-everything flag is needed to make GCC compile with Clang 19.
158
- // `-g -O2` are the default flags that are otherwise used by Make.
159
- // FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml.
160
- . env ( "CXXFLAGS" , "-Wno-everything -g -O2" )
161
- . env ( "CFLAGS" , "-Wno-everything -g -O2" )
162
- . arg ( "--enable-host-shared" )
163
- . arg ( "--enable-languages=jit" )
164
- . arg ( "--enable-checking=release" )
165
- . arg ( "--disable-bootstrap" )
166
- . arg ( "--disable-multilib" )
167
- . arg ( format ! ( "--prefix={}" , install_dir. display( ) ) ) ;
168
- let cc = builder. build . cc ( target) . display ( ) . to_string ( ) ;
169
- let cc = builder
161
+ builder. create_dir ( & src_dir) ;
162
+ builder. cp_link_r ( root, & src_dir) ;
163
+ src_dir
164
+ } else {
165
+ root. clone ( )
166
+ } ;
167
+
168
+ command ( src_dir. join ( "contrib/download_prerequisites" ) ) . current_dir ( & src_dir) . run ( builder) ;
169
+ let mut configure_cmd = command ( src_dir. join ( "configure" ) ) ;
170
+ configure_cmd
171
+ . current_dir ( out_dir)
172
+ // On CI, we compile GCC with Clang.
173
+ // The -Wno-everything flag is needed to make GCC compile with Clang 19.
174
+ // `-g -O2` are the default flags that are otherwise used by Make.
175
+ // FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml.
176
+ . env ( "CXXFLAGS" , "-Wno-everything -g -O2" )
177
+ . env ( "CFLAGS" , "-Wno-everything -g -O2" )
178
+ . arg ( "--enable-host-shared" )
179
+ . arg ( "--enable-languages=jit" )
180
+ . arg ( "--enable-checking=release" )
181
+ . arg ( "--disable-bootstrap" )
182
+ . arg ( "--disable-multilib" )
183
+ . arg ( format ! ( "--prefix={}" , install_dir. display( ) ) ) ;
184
+ let cc = builder. build . cc ( target) . display ( ) . to_string ( ) ;
185
+ let cc = builder
186
+ . build
187
+ . config
188
+ . ccache
189
+ . as_ref ( )
190
+ . map_or_else ( || cc. clone ( ) , |ccache| format ! ( "{ccache} {cc}" ) ) ;
191
+ configure_cmd. env ( "CC" , cc) ;
192
+
193
+ if let Ok ( ref cxx) = builder. build . cxx ( target) {
194
+ let cxx = cxx. display ( ) . to_string ( ) ;
195
+ let cxx = builder
170
196
. build
171
197
. config
172
198
. ccache
173
199
. as_ref ( )
174
- . map_or_else ( || cc. clone ( ) , |ccache| format ! ( "{ccache} {cc}" ) ) ;
175
- configure_cmd. env ( "CC" , cc) ;
176
-
177
- if let Ok ( ref cxx) = builder. build . cxx ( target) {
178
- let cxx = cxx. display ( ) . to_string ( ) ;
179
- let cxx = builder
180
- . build
181
- . config
182
- . ccache
183
- . as_ref ( )
184
- . map_or_else ( || cxx. clone ( ) , |ccache| format ! ( "{ccache} {cxx}" ) ) ;
185
- configure_cmd. env ( "CXX" , cxx) ;
186
- }
187
- configure_cmd. run ( builder) ;
200
+ . map_or_else ( || cxx. clone ( ) , |ccache| format ! ( "{ccache} {cxx}" ) ) ;
201
+ configure_cmd. env ( "CXX" , cxx) ;
202
+ }
203
+ configure_cmd. run ( builder) ;
188
204
189
205
command ( "make" )
190
206
. current_dir ( & out_dir)
@@ -196,15 +212,6 @@ impl Step for Gcc {
196
212
. arg ( "--silent" )
197
213
. arg ( "install" )
198
214
. run_capture_stdout ( builder) ;
199
-
200
- let lib_alias = install_dir. join ( "lib/libgccjit.so.0" ) ;
201
- if !lib_alias. exists ( ) {
202
- t ! ( builder. symlink_file( & libgccjit_path, lib_alias) ) ;
203
- }
204
-
205
- t ! ( stamp. write( ) ) ;
206
-
207
- GccOutput { libgccjit : libgccjit_path }
208
215
}
209
216
}
210
217
0 commit comments