@@ -2,14 +2,13 @@ use std::any::{type_name, Any};
22use std:: cell:: { Cell , RefCell } ;
33use std:: collections:: BTreeSet ;
44use std:: env;
5- use std:: ffi:: { OsStr , OsString } ;
5+ use std:: ffi:: OsStr ;
66use std:: fmt:: { Debug , Write } ;
7- use std:: fs:: { self , File } ;
7+ use std:: fs:: { self } ;
88use std:: hash:: Hash ;
9- use std:: io:: { BufRead , BufReader , ErrorKind } ;
109use std:: ops:: Deref ;
1110use std:: path:: { Component , Path , PathBuf } ;
12- use std:: process:: { Command , Stdio } ;
11+ use std:: process:: Command ;
1312use std:: time:: { Duration , Instant } ;
1413
1514use crate :: cache:: { Cache , Interned , INTERNER } ;
@@ -24,14 +23,12 @@ use crate::test;
2423use crate :: tool:: { self , SourceType } ;
2524use crate :: util:: { self , add_dylib_path, add_link_lib_path, exe, libdir, output, t} ;
2625use crate :: EXTRA_CHECK_CFGS ;
27- use crate :: { check, Config } ;
28- use crate :: { compile, Crate } ;
26+ use crate :: { check, compile, Crate } ;
2927use crate :: { Build , CLang , DocTests , GitRepo , Mode } ;
3028
3129pub use crate :: Compiler ;
3230// FIXME: replace with std::lazy after it gets stabilized and reaches beta
33- use once_cell:: sync:: { Lazy , OnceCell } ;
34- use xz2:: bufread:: XzDecoder ;
31+ use once_cell:: sync:: Lazy ;
3532
3633pub struct Builder < ' a > {
3734 pub build : & ' a Build ,
@@ -853,241 +850,6 @@ impl<'a> Builder<'a> {
853850 StepDescription :: run ( v, self , paths) ;
854851 }
855852
856- /// Modifies the interpreter section of 'fname' to fix the dynamic linker,
857- /// or the RPATH section, to fix the dynamic library search path
858- ///
859- /// This is only required on NixOS and uses the PatchELF utility to
860- /// change the interpreter/RPATH of ELF executables.
861- ///
862- /// Please see https://nixos.org/patchelf.html for more information
863- pub ( crate ) fn fix_bin_or_dylib ( & self , fname : & Path ) {
864- // FIXME: cache NixOS detection?
865- match Command :: new ( "uname" ) . arg ( "-s" ) . stderr ( Stdio :: inherit ( ) ) . output ( ) {
866- Err ( _) => return ,
867- Ok ( output) if !output. status . success ( ) => return ,
868- Ok ( output) => {
869- let mut s = output. stdout ;
870- if s. last ( ) == Some ( & b'\n' ) {
871- s. pop ( ) ;
872- }
873- if s != b"Linux" {
874- return ;
875- }
876- }
877- }
878-
879- // If the user has asked binaries to be patched for Nix, then
880- // don't check for NixOS or `/lib`, just continue to the patching.
881- // NOTE: this intentionally comes after the Linux check:
882- // - patchelf only works with ELF files, so no need to run it on Mac or Windows
883- // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
884- if !self . config . patch_binaries_for_nix {
885- // Use `/etc/os-release` instead of `/etc/NIXOS`.
886- // The latter one does not exist on NixOS when using tmpfs as root.
887- const NIX_IDS : & [ & str ] = & [ "ID=nixos" , "ID='nixos'" , "ID=\" nixos\" " ] ;
888- let os_release = match File :: open ( "/etc/os-release" ) {
889- Err ( e) if e. kind ( ) == ErrorKind :: NotFound => return ,
890- Err ( e) => panic ! ( "failed to access /etc/os-release: {}" , e) ,
891- Ok ( f) => f,
892- } ;
893- if !BufReader :: new ( os_release) . lines ( ) . any ( |l| NIX_IDS . contains ( & t ! ( l) . trim ( ) ) ) {
894- return ;
895- }
896- if Path :: new ( "/lib" ) . exists ( ) {
897- return ;
898- }
899- }
900-
901- // At this point we're pretty sure the user is running NixOS or using Nix
902- println ! ( "info: you seem to be using Nix. Attempting to patch {}" , fname. display( ) ) ;
903-
904- // Only build `.nix-deps` once.
905- static NIX_DEPS_DIR : OnceCell < PathBuf > = OnceCell :: new ( ) ;
906- let mut nix_build_succeeded = true ;
907- let nix_deps_dir = NIX_DEPS_DIR . get_or_init ( || {
908- // Run `nix-build` to "build" each dependency (which will likely reuse
909- // the existing `/nix/store` copy, or at most download a pre-built copy).
910- //
911- // Importantly, we create a gc-root called `.nix-deps` in the `build/`
912- // directory, but still reference the actual `/nix/store` path in the rpath
913- // as it makes it significantly more robust against changes to the location of
914- // the `.nix-deps` location.
915- //
916- // bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
917- // zlib: Needed as a system dependency of `libLLVM-*.so`.
918- // patchelf: Needed for patching ELF binaries (see doc comment above).
919- let nix_deps_dir = self . out . join ( ".nix-deps" ) ;
920- const NIX_EXPR : & str = "
921- with (import <nixpkgs> {});
922- symlinkJoin {
923- name = \" rust-stage0-dependencies\" ;
924- paths = [
925- zlib
926- patchelf
927- stdenv.cc.bintools
928- ];
929- }
930- " ;
931- nix_build_succeeded = self . try_run ( Command :: new ( "nix-build" ) . args ( & [
932- Path :: new ( "-E" ) ,
933- Path :: new ( NIX_EXPR ) ,
934- Path :: new ( "-o" ) ,
935- & nix_deps_dir,
936- ] ) ) ;
937- nix_deps_dir
938- } ) ;
939- if !nix_build_succeeded {
940- return ;
941- }
942-
943- let mut patchelf = Command :: new ( nix_deps_dir. join ( "bin/patchelf" ) ) ;
944- let rpath_entries = {
945- // ORIGIN is a relative default, all binary and dynamic libraries we ship
946- // appear to have this (even when `../lib` is redundant).
947- // NOTE: there are only two paths here, delimited by a `:`
948- let mut entries = OsString :: from ( "$ORIGIN/../lib:" ) ;
949- entries. push ( t ! ( fs:: canonicalize( nix_deps_dir) ) ) ;
950- entries. push ( "/lib" ) ;
951- entries
952- } ;
953- patchelf. args ( & [ OsString :: from ( "--set-rpath" ) , rpath_entries] ) ;
954- if !fname. extension ( ) . map_or ( false , |ext| ext == "so" ) {
955- // Finally, set the correct .interp for binaries
956- let dynamic_linker_path = nix_deps_dir. join ( "nix-support/dynamic-linker" ) ;
957- // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ...
958- let dynamic_linker = t ! ( String :: from_utf8( t!( fs:: read( dynamic_linker_path) ) ) ) ;
959- patchelf. args ( & [ "--set-interpreter" , dynamic_linker. trim_end ( ) ] ) ;
960- }
961-
962- self . try_run ( patchelf. arg ( fname) ) ;
963- }
964-
965- pub ( crate ) fn download_component ( & self , url : & str , dest_path : & Path , help_on_error : & str ) {
966- self . verbose ( & format ! ( "download {url}" ) ) ;
967- // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
968- let tempfile = self . tempdir ( ) . join ( dest_path. file_name ( ) . unwrap ( ) ) ;
969- // While bootstrap itself only supports http and https downloads, downstream forks might
970- // need to download components from other protocols. The match allows them adding more
971- // protocols without worrying about merge conflicts if we change the HTTP implementation.
972- match url. split_once ( "://" ) . map ( |( proto, _) | proto) {
973- Some ( "http" ) | Some ( "https" ) => {
974- self . download_http_with_retries ( & tempfile, url, help_on_error)
975- }
976- Some ( other) => panic ! ( "unsupported protocol {other} in {url}" ) ,
977- None => panic ! ( "no protocol in {url}" ) ,
978- }
979- t ! ( std:: fs:: rename( & tempfile, dest_path) ) ;
980- }
981-
982- fn download_http_with_retries ( & self , tempfile : & Path , url : & str , help_on_error : & str ) {
983- println ! ( "downloading {}" , url) ;
984- // Try curl. If that fails and we are on windows, fallback to PowerShell.
985- let mut curl = Command :: new ( "curl" ) ;
986- curl. args ( & [
987- "-#" ,
988- "-y" ,
989- "30" ,
990- "-Y" ,
991- "10" , // timeout if speed is < 10 bytes/sec for > 30 seconds
992- "--connect-timeout" ,
993- "30" , // timeout if cannot connect within 30 seconds
994- "--retry" ,
995- "3" ,
996- "-Sf" ,
997- "-o" ,
998- ] ) ;
999- curl. arg ( tempfile) ;
1000- curl. arg ( url) ;
1001- if !self . check_run ( & mut curl) {
1002- if self . build . build . contains ( "windows-msvc" ) {
1003- println ! ( "Fallback to PowerShell" ) ;
1004- for _ in 0 ..3 {
1005- if self . try_run ( Command :: new ( "PowerShell.exe" ) . args ( & [
1006- "/nologo" ,
1007- "-Command" ,
1008- "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;" ,
1009- & format ! (
1010- "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')" ,
1011- url, tempfile. to_str( ) . expect( "invalid UTF-8 not supported with powershell downloads" ) ,
1012- ) ,
1013- ] ) ) {
1014- return ;
1015- }
1016- println ! ( "\n spurious failure, trying again" ) ;
1017- }
1018- }
1019- if !help_on_error. is_empty ( ) {
1020- eprintln ! ( "{}" , help_on_error) ;
1021- }
1022- crate :: detail_exit ( 1 ) ;
1023- }
1024- }
1025-
1026- pub ( crate ) fn unpack ( & self , tarball : & Path , dst : & Path , pattern : & str ) {
1027- println ! ( "extracting {} to {}" , tarball. display( ) , dst. display( ) ) ;
1028- if !dst. exists ( ) {
1029- t ! ( fs:: create_dir_all( dst) ) ;
1030- }
1031-
1032- // `tarball` ends with `.tar.xz`; strip that suffix
1033- // example: `rust-dev-nightly-x86_64-unknown-linux-gnu`
1034- let uncompressed_filename =
1035- Path :: new ( tarball. file_name ( ) . expect ( "missing tarball filename" ) ) . file_stem ( ) . unwrap ( ) ;
1036- let directory_prefix = Path :: new ( Path :: new ( uncompressed_filename) . file_stem ( ) . unwrap ( ) ) ;
1037-
1038- // decompress the file
1039- let data = t ! ( File :: open( tarball) ) ;
1040- let decompressor = XzDecoder :: new ( BufReader :: new ( data) ) ;
1041-
1042- let mut tar = tar:: Archive :: new ( decompressor) ;
1043- for member in t ! ( tar. entries( ) ) {
1044- let mut member = t ! ( member) ;
1045- let original_path = t ! ( member. path( ) ) . into_owned ( ) ;
1046- // skip the top-level directory
1047- if original_path == directory_prefix {
1048- continue ;
1049- }
1050- let mut short_path = t ! ( original_path. strip_prefix( directory_prefix) ) ;
1051- if !short_path. starts_with ( pattern) {
1052- continue ;
1053- }
1054- short_path = t ! ( short_path. strip_prefix( pattern) ) ;
1055- let dst_path = dst. join ( short_path) ;
1056- self . verbose ( & format ! ( "extracting {} to {}" , original_path. display( ) , dst. display( ) ) ) ;
1057- if !t ! ( member. unpack_in( dst) ) {
1058- panic ! ( "path traversal attack ??" ) ;
1059- }
1060- let src_path = dst. join ( original_path) ;
1061- if src_path. is_dir ( ) && dst_path. exists ( ) {
1062- continue ;
1063- }
1064- t ! ( fs:: rename( src_path, dst_path) ) ;
1065- }
1066- t ! ( fs:: remove_dir_all( dst. join( directory_prefix) ) ) ;
1067- }
1068-
1069- /// Returns whether the SHA256 checksum of `path` matches `expected`.
1070- pub ( crate ) fn verify ( & self , path : & Path , expected : & str ) -> bool {
1071- use sha2:: Digest ;
1072-
1073- self . verbose ( & format ! ( "verifying {}" , path. display( ) ) ) ;
1074- let mut hasher = sha2:: Sha256 :: new ( ) ;
1075- // FIXME: this is ok for rustfmt (4.1 MB large at time of writing), but it seems memory-intensive for rustc and larger components.
1076- // Consider using streaming IO instead?
1077- let contents = if self . config . dry_run ( ) { vec ! [ ] } else { t ! ( fs:: read( path) ) } ;
1078- hasher. update ( & contents) ;
1079- let found = hex:: encode ( hasher. finalize ( ) . as_slice ( ) ) ;
1080- let verified = found == expected;
1081- if !verified && !self . config . dry_run ( ) {
1082- println ! (
1083- "invalid checksum: \n \
1084- found: {found}\n \
1085- expected: {expected}",
1086- ) ;
1087- }
1088- return verified;
1089- }
1090-
1091853 /// Obtain a compiler at a given stage and for a given host. Explicitly does
1092854 /// not take `Compiler` since all `Compiler` instances are meant to be
1093855 /// obtained through this function, since it ensures that they are valid
@@ -1301,19 +1063,6 @@ impl<'a> Builder<'a> {
13011063 None
13021064 }
13031065
1304- /// Convenience wrapper to allow `builder.llvm_link_shared()` instead of `builder.config.llvm_link_shared(&builder)`.
1305- pub ( crate ) fn llvm_link_shared ( & self ) -> bool {
1306- Config :: llvm_link_shared ( self )
1307- }
1308-
1309- pub ( crate ) fn download_rustc ( & self ) -> bool {
1310- Config :: download_rustc ( self )
1311- }
1312-
1313- pub ( crate ) fn initial_rustfmt ( & self ) -> Option < PathBuf > {
1314- Config :: initial_rustfmt ( self )
1315- }
1316-
13171066 /// Prepares an invocation of `cargo` to be run.
13181067 ///
13191068 /// This will create a `Command` that represents a pending execution of
0 commit comments