1
1
use anyhow:: { anyhow, Context } ;
2
2
use chrono:: { DateTime , Utc } ;
3
3
use collector:: Sha ;
4
- use std:: ffi:: OsStr ;
5
4
use std:: fmt;
6
5
use std:: fs:: { self , File } ;
7
6
use std:: io:: { BufReader , Read } ;
8
- use std:: path:: { Path , PathBuf } ;
7
+ use std:: path:: PathBuf ;
9
8
use tar:: Archive ;
10
9
use xz2:: bufread:: XzDecoder ;
11
10
@@ -40,10 +39,116 @@ impl Sysroot {
40
39
} ;
41
40
42
41
download. get_and_extract ( ModuleVariant :: Rustc ) ?;
43
- download. get_and_extract ( ModuleVariant :: Std ) ?;
42
+ // HACK(eddyb) commented out because we build our own stdlib
43
+ // (see `fn build_std` below).
44
+ // download.get_and_extract(ModuleVariant::Std)?;
44
45
download. get_and_extract ( ModuleVariant :: Cargo ) ?;
46
+ download. get_and_extract ( ModuleVariant :: RustSrc ) ?;
45
47
46
- download. into_sysroot ( )
48
+ let sysroot_dir = download. directory . join ( & download. rust_sha ) ;
49
+ let sysroot = download. into_sysroot ( ) ?;
50
+
51
+ // FIXME(eddyb) remove this once we no longer need to
52
+ // build our own stdlib (see `fn build_std` below).
53
+ sysroot. build_std ( sysroot_dir) ?;
54
+
55
+ Ok ( sysroot)
56
+ }
57
+
58
+ /// Build `std`+`test`+`proc_macro` in a similar way to Cargo's `-Zbuild-std`
59
+ /// feature, but only once, and move the resulting libraries into the sysroot.
60
+ ///
61
+ /// We only need this until https://github.com/rust-lang/cargo/pull/8073
62
+ /// reaches beta, because then `rust-lang/rust` builds will have that
63
+ /// treatment. For now, we only have access to that Cargo change here,
64
+ /// using the newly built Cargo.
65
+ ///
66
+ /// For more background on why we need this, see this comment:
67
+ /// https://github.com/rust-lang/rust/issues/69060#issuecomment-604928032
68
+ /// (in short, Cargo used to include `rustc -vV` output, which contains
69
+ /// the commit hash, into `-Cmetadata`, producing different `std`s,
70
+ /// and making the perf runs incomparable, up to several % of difference).
71
+ fn build_std ( & self , sysroot_dir : PathBuf ) -> anyhow:: Result < ( ) > {
72
+ // Make sure everything below gets absolute directories.
73
+ let sysroot_dir = sysroot_dir. canonicalize ( ) ?;
74
+
75
+ let sysroot_rustlib_dir = sysroot_dir. join ( "lib/rustlib" ) ;
76
+ let rust_src_dir = sysroot_rustlib_dir. join ( "src/rust" ) ;
77
+
78
+ // HACK(eddyb) add a top-level `Cargo.toml` that has the necessary
79
+ // `patch.crates-io` entries for `rustc-std-workspace-{core,alloc,std}`.
80
+ // (maybe `rust-src` should include such a `Cargo.toml`?)
81
+ fs:: write (
82
+ rust_src_dir. join ( "Cargo.toml" ) ,
83
+ "\
84
+ [workspace]
85
+ members = ['src/libtest']
86
+
87
+ [patch.crates-io]
88
+ # See comments in `tools/rustc-std-workspace-core/README.md` for what's going on
89
+ # here
90
+ rustc-std-workspace-core = { path = 'src/tools/rustc-std-workspace-core' }
91
+ rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' }
92
+ rustc-std-workspace-std = { path = 'src/tools/rustc-std-workspace-std' }
93
+ " ,
94
+ ) ?;
95
+
96
+ // HACK(eddyb) we need `std` to run the build scripts to build `std`.
97
+ let vanilla_sysroot_dir = {
98
+ let vanilla_download = SysrootDownload {
99
+ directory : sysroot_dir. join ( "vanilla-sysroot" ) ,
100
+ rust_sha : self . sha . clone ( ) ,
101
+ triple : self . triple . clone ( ) ,
102
+ } ;
103
+ vanilla_download. get_and_extract ( ModuleVariant :: Std ) ?;
104
+ vanilla_download. directory . join ( vanilla_download. rust_sha )
105
+ } ;
106
+
107
+ let rustflags = format ! (
108
+ "--sysroot={sysroot} --remap-path-prefix={remap_from}={remap_to}" ,
109
+ sysroot = vanilla_sysroot_dir. display( ) ,
110
+ remap_from = rust_src_dir. display( ) ,
111
+ remap_to = "/rustc/REDACTED_SHA_HASH/"
112
+ ) ;
113
+
114
+ // Run Cargo to produce `$local_build_target_dir/release/deps/lib*.rlib`.
115
+ let local_build_target_dir = sysroot_dir. join ( "build-std-target" ) ;
116
+ let cargo_status = std:: process:: Command :: new ( & self . cargo )
117
+ . env ( "RUSTC" , & self . rustc )
118
+ . env ( "RUSTFLAGS" , rustflags)
119
+ . env ( "__CARGO_DEFAULT_LIB_METADATA" , "rustc-perf-std" )
120
+ . args ( & [ "build" , "--release" ] )
121
+ . arg ( "--target-dir" )
122
+ . arg ( & local_build_target_dir)
123
+ . args ( & [ "--features" , "panic-unwind" , "--features" , "backtrace" ] )
124
+ . arg ( "--manifest-path" )
125
+ . arg ( rust_src_dir. join ( "src/libtest/Cargo.toml" ) )
126
+ . status ( ) ?;
127
+ if !cargo_status. success ( ) {
128
+ return Err ( anyhow ! (
129
+ "unable to build stdlib for {} triple {}" ,
130
+ self . sha,
131
+ self . triple
132
+ ) ) ;
133
+ }
134
+
135
+ // Move all of the `rlib` files into the main sysroot.
136
+ let sysroot_target_lib_dir = sysroot_rustlib_dir. join ( & self . triple ) . join ( "lib" ) ;
137
+ for entry in fs:: read_dir ( local_build_target_dir. join ( "release/deps" ) ) ? {
138
+ let entry = entry?;
139
+ let path = entry. path ( ) ;
140
+ if let ( Some ( name) , Some ( ext) ) = ( path. file_name ( ) , path. extension ( ) ) {
141
+ if ext == "rlib" {
142
+ fs:: rename ( & path, sysroot_target_lib_dir. join ( name) ) ?;
143
+ }
144
+ }
145
+ }
146
+
147
+ // Clean up, to avoid accidental usage of these directories.
148
+ fs:: remove_dir_all ( vanilla_sysroot_dir) ?;
149
+ fs:: remove_dir_all ( local_build_target_dir) ?;
150
+
151
+ Ok ( ( ) )
47
152
}
48
153
}
49
154
@@ -66,14 +171,15 @@ struct SysrootDownload {
66
171
triple : String ,
67
172
}
68
173
69
- const MODULE_URL : & str =
70
- "https://rust-lang-ci2.s3.amazonaws.com/rustc-builds/@SHA@/@MODULE@-nightly-@[email protected] " ;
174
+ const BASE_URL : & str = "https://rust-lang-ci2.s3.amazonaws.com/rustc-builds" ;
71
175
176
+ // FIXME(eddyb) rename to just `Component`.
72
177
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
73
178
enum ModuleVariant {
74
179
Cargo ,
75
180
Rustc ,
76
181
Std ,
182
+ RustSrc ,
77
183
}
78
184
79
185
impl fmt:: Display for ModuleVariant {
@@ -82,47 +188,45 @@ impl fmt::Display for ModuleVariant {
82
188
ModuleVariant :: Cargo => write ! ( f, "cargo" ) ,
83
189
ModuleVariant :: Rustc => write ! ( f, "rustc" ) ,
84
190
ModuleVariant :: Std => write ! ( f, "rust-std" ) ,
191
+ ModuleVariant :: RustSrc => write ! ( f, "rust-src" ) ,
85
192
}
86
193
}
87
194
}
88
195
89
196
impl ModuleVariant {
90
197
fn url ( & self , sysroot : & SysrootDownload , triple : & str ) -> String {
91
- MODULE_URL
92
- . replace ( "@MODULE@" , & self . to_string ( ) )
93
- . replace ( "@SHA@" , & sysroot. rust_sha )
94
- . replace ( "@TRIPLE@" , triple)
198
+ let suffix = if * self == ModuleVariant :: RustSrc {
199
+ String :: new ( )
200
+ } else {
201
+ format ! ( "-{}" , triple)
202
+ } ;
203
+ format ! (
204
+ "{base}/{sha}/{module}-nightly{suffix}.tar.xz" ,
205
+ base = BASE_URL ,
206
+ module = self ,
207
+ sha = sysroot. rust_sha,
208
+ suffix = suffix,
209
+ )
95
210
}
96
211
}
97
212
98
213
impl SysrootDownload {
99
214
fn into_sysroot ( self ) -> anyhow:: Result < Sysroot > {
215
+ let sysroot_bin_dir = self . directory . join ( & self . rust_sha ) . join ( "bin" ) ;
216
+ let sysroot_bin = |name| {
217
+ let path = sysroot_bin_dir. join ( name) ;
218
+ path. canonicalize ( ) . with_context ( || {
219
+ format ! (
220
+ "failed to canonicalize {} path for {}: {:?}" ,
221
+ name, self . rust_sha, path
222
+ )
223
+ } )
224
+ } ;
225
+
100
226
Ok ( Sysroot {
101
- rustc : self
102
- . directory
103
- . join ( & self . rust_sha )
104
- . join ( "rustc/bin/rustc" )
105
- . canonicalize ( )
106
- . with_context ( || {
107
- format ! ( "failed to canonicalize rustc path for {}" , self . rust_sha)
108
- } ) ?,
109
- rustdoc : self
110
- . directory
111
- . join ( & self . rust_sha )
112
- . join ( "rustc/bin/rustdoc" )
113
- . canonicalize ( )
114
- . with_context ( || {
115
- format ! ( "failed to canonicalize rustdoc path for {}" , self . rust_sha)
116
- } ) ?,
117
- cargo : {
118
- let path = self . directory . join ( & self . rust_sha ) . join ( "cargo/bin/cargo" ) ;
119
- path. canonicalize ( ) . with_context ( || {
120
- format ! (
121
- "failed to canonicalize cargo path for {}: {:?}" ,
122
- self . rust_sha, path
123
- )
124
- } ) ?
125
- } ,
227
+ rustc : sysroot_bin ( "rustc" ) ?,
228
+ rustdoc : sysroot_bin ( "rustdoc" ) ?,
229
+ cargo : sysroot_bin ( "cargo" ) ?,
126
230
sha : self . rust_sha ,
127
231
triple : self . triple ,
128
232
} )
@@ -161,19 +265,21 @@ impl SysrootDownload {
161
265
}
162
266
163
267
return Err ( anyhow ! (
164
- "unable to download sha {} triple {} module {}" ,
268
+ "unable to download sha {} triple {} module {} from {} " ,
165
269
self . rust_sha,
166
270
self . triple,
167
- variant
271
+ variant,
272
+ url
168
273
) ) ;
169
274
}
170
275
171
276
fn extract < T : Read > ( & self , variant : ModuleVariant , reader : T ) -> anyhow:: Result < ( ) > {
172
- let is_std = variant == ModuleVariant :: Std ;
173
277
let mut archive = Archive :: new ( reader) ;
174
- let std_prefix = format ! ( "rust-std-{}/lib/rustlib" , self . triple) ;
175
-
176
- let mut to_link = Vec :: new ( ) ;
278
+ let prefix = if variant == ModuleVariant :: Std {
279
+ format ! ( "rust-std-{}" , self . triple)
280
+ } else {
281
+ variant. to_string ( )
282
+ } ;
177
283
178
284
let unpack_into = self . directory . join ( & self . rust_sha ) ;
179
285
@@ -184,21 +290,11 @@ impl SysrootDownload {
184
290
assert ! ( components. next( ) . is_some( ) , "strip container directory" ) ;
185
291
let path = components. as_path ( ) ;
186
292
187
- let path = if is_std {
188
- if let Ok ( path) = path. strip_prefix ( & std_prefix) {
189
- if path. extension ( ) == Some ( OsStr :: new ( "dylib" ) ) {
190
- to_link. push ( path. to_owned ( ) ) ;
191
- continue ;
192
- } else {
193
- Path :: new ( "rustc/lib/rustlib" ) . join ( path)
194
- }
195
- } else {
196
- continue ;
197
- }
293
+ let path = if let Ok ( path) = path. strip_prefix ( & prefix) {
294
+ unpack_into. join ( path)
198
295
} else {
199
- path . into ( )
296
+ continue ;
200
297
} ;
201
- let path = unpack_into. join ( path) ;
202
298
fs:: create_dir_all ( & path. parent ( ) . unwrap ( ) ) . with_context ( || {
203
299
format ! (
204
300
"could not create intermediate directories for {}" ,
@@ -208,24 +304,6 @@ impl SysrootDownload {
208
304
entry. unpack ( path) ?;
209
305
}
210
306
211
- let link_dst_prefix = unpack_into. join ( format ! ( "rustc/lib/rustlib/{}/lib" , self . triple) ) ;
212
- let link_src_prefix = format ! ( "{}/lib" , self . triple) ;
213
- for path in to_link {
214
- let src = unpack_into. join ( "rustc/lib" ) . join (
215
- path. strip_prefix ( & link_src_prefix)
216
- . with_context ( || format ! ( "stripping prefix from: {:?}" , path) ) ?,
217
- ) ;
218
- let dst = link_dst_prefix. join ( & path) ;
219
- fs:: create_dir_all ( & dst. parent ( ) . unwrap ( ) ) . with_context ( || {
220
- format ! (
221
- "could not create intermediate directories for {}" ,
222
- dst. display( )
223
- )
224
- } ) ?;
225
- log:: trace!( "linking {} to {}" , src. display( ) , dst. display( ) ) ;
226
- fs:: hard_link ( src, dst) ?;
227
- }
228
-
229
307
Ok ( ( ) )
230
308
}
231
309
}
0 commit comments