@@ -14,6 +14,8 @@ use std::path::Path;
1414use std:: path:: PathBuf ;
1515use std:: process:: Command ;
1616
17+ const NIGHTLY_TOOLCHAIN : & str = "nightly" ;
18+
1719struct Wasm32Check {
1820 rustc_path : PathBuf ,
1921 sysroot : PathBuf ,
@@ -168,6 +170,136 @@ fn rustup_add_wasm_target() -> Result<()> {
168170 Ok ( ( ) )
169171}
170172
173+ /// Ensure that the nightly toolchain is installed and has the `rust-src` component
174+ /// and `wasm32-unknown-unknown` target, which are required for `-Z build-std`.
175+ pub fn check_nightly_prerequisites ( ) -> Result < ( ) > {
176+ let msg = format ! (
177+ "{}Checking nightly toolchain prerequisites for panic=unwind..." ,
178+ emoji:: TARGET
179+ ) ;
180+ PBAR . info ( & msg) ;
181+
182+ let nightly_sysroot = get_nightly_sysroot ( ) ?;
183+
184+ if !nightly_sysroot. exists ( ) {
185+ install_nightly_toolchain ( ) ?;
186+ }
187+
188+ if !has_rust_src_component ( ) ? {
189+ install_rust_src_component ( ) ?;
190+ }
191+
192+ if !does_nightly_wasm32_target_exist ( ) {
193+ rustup_add_wasm_target_nightly ( ) ?;
194+ }
195+
196+ Ok ( ( ) )
197+ }
198+
199+ fn get_nightly_sysroot ( ) -> Result < PathBuf > {
200+ let command = Command :: new ( "rustc" )
201+ . args ( [ "+nightly" , "--print" , "sysroot" ] )
202+ . output ( ) ?;
203+
204+ if command. status . success ( ) {
205+ Ok ( String :: from_utf8 ( command. stdout ) ?. trim ( ) . into ( ) )
206+ } else {
207+ Err ( anyhow ! (
208+ "Getting nightly rustc's sysroot wasn't successful. Got {}" ,
209+ command. status
210+ ) )
211+ }
212+ }
213+
214+ fn install_nightly_toolchain ( ) -> Result < ( ) > {
215+ let msg = format ! (
216+ "{}Installing nightly toolchain via rustup..." ,
217+ emoji:: TARGET
218+ ) ;
219+ PBAR . info ( & msg) ;
220+
221+ let mut cmd = Command :: new ( "rustup" ) ;
222+ cmd. arg ( "toolchain" ) . arg ( "install" ) . arg ( NIGHTLY_TOOLCHAIN ) ;
223+ utils:: run ( cmd, "rustup" ) . context ( "Installing the nightly toolchain with rustup" ) ?;
224+
225+ Ok ( ( ) )
226+ }
227+
228+ fn has_rust_src_component ( ) -> Result < bool > {
229+ let command = Command :: new ( "rustup" )
230+ . args ( [ "component" , "list" , "--toolchain" , NIGHTLY_TOOLCHAIN ] )
231+ . output ( ) ?;
232+
233+ if !command. status . success ( ) {
234+ return Ok ( false ) ;
235+ }
236+
237+ let stdout = String :: from_utf8 ( command. stdout ) ?;
238+ Ok ( stdout
239+ . lines ( )
240+ . any ( |line| line. starts_with ( "rust-src" ) && line. contains ( "(installed)" ) ) )
241+ }
242+
243+ fn install_rust_src_component ( ) -> Result < ( ) > {
244+ let msg = format ! (
245+ "{}Installing rust-src component for nightly toolchain..." ,
246+ emoji:: TARGET
247+ ) ;
248+ PBAR . info ( & msg) ;
249+
250+ let mut cmd = Command :: new ( "rustup" ) ;
251+ cmd. arg ( "component" )
252+ . arg ( "add" )
253+ . arg ( "rust-src" )
254+ . arg ( "--toolchain" )
255+ . arg ( NIGHTLY_TOOLCHAIN ) ;
256+ utils:: run ( cmd, "rustup" ) . context ( "Adding the rust-src component with rustup" ) ?;
257+
258+ Ok ( ( ) )
259+ }
260+
261+ fn does_nightly_wasm32_target_exist ( ) -> bool {
262+ let command = Command :: new ( "rustc" )
263+ . args ( [
264+ "+nightly" ,
265+ "--target" ,
266+ "wasm32-unknown-unknown" ,
267+ "--print" ,
268+ "target-libdir" ,
269+ ] )
270+ . output ( ) ;
271+
272+ match command {
273+ Ok ( output) if output. status . success ( ) => {
274+ let path: PathBuf = String :: from_utf8 ( output. stdout )
275+ . ok ( )
276+ . map ( |s| s. trim ( ) . into ( ) )
277+ . unwrap_or_default ( ) ;
278+ path. exists ( )
279+ }
280+ _ => false ,
281+ }
282+ }
283+
284+ fn rustup_add_wasm_target_nightly ( ) -> Result < ( ) > {
285+ let msg = format ! (
286+ "{}Adding wasm32-unknown-unknown target for nightly toolchain..." ,
287+ emoji:: TARGET
288+ ) ;
289+ PBAR . info ( & msg) ;
290+
291+ let mut cmd = Command :: new ( "rustup" ) ;
292+ cmd. arg ( "target" )
293+ . arg ( "add" )
294+ . arg ( "wasm32-unknown-unknown" )
295+ . arg ( "--toolchain" )
296+ . arg ( NIGHTLY_TOOLCHAIN ) ;
297+ utils:: run ( cmd, "rustup" )
298+ . context ( "Adding the wasm32-unknown-unknown target for nightly with rustup" ) ?;
299+
300+ Ok ( ( ) )
301+ }
302+
171303/// Ensure that `rustc` is present and that it is >= 1.30.0
172304pub fn check_rustc_version ( ) -> Result < String > {
173305 let local_minor_version = rustc_minor_version ( ) ;
0 commit comments