]> git.lizzy.rs Git - rust.git/blobdiff - src/bootstrap/download.rs
Rollup merge of #107740 - oli-obk:lock_tcx, r=petrochenkov
[rust.git] / src / bootstrap / download.rs
index 6ae283f32a5f3a9080edd104a4cf46bc01b3376d..bd67978a7662ee1d61c9d572d6194c8b243276c0 100644 (file)
@@ -18,6 +18,8 @@
     Config,
 };
 
+static SHOULD_FIX_BINS_AND_DYLIBS: OnceCell<bool> = OnceCell::new();
+
 /// Generic helpers that are useful anywhere in bootstrap.
 impl Config {
     pub fn is_verbose(&self) -> bool {
@@ -70,53 +72,61 @@ pub(crate) fn check_run(&self, cmd: &mut Command) -> bool {
         check_run(cmd, self.is_verbose())
     }
 
-    /// Modifies the interpreter section of 'fname' to fix the dynamic linker,
-    /// or the RPATH section, to fix the dynamic library search path
-    ///
-    /// This is only required on NixOS and uses the PatchELF utility to
-    /// change the interpreter/RPATH of ELF executables.
-    ///
-    /// Please see https://nixos.org/patchelf.html for more information
-    fn fix_bin_or_dylib(&self, fname: &Path) {
-        // FIXME: cache NixOS detection?
-        match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() {
-            Err(_) => return,
-            Ok(output) if !output.status.success() => return,
-            Ok(output) => {
-                let mut s = output.stdout;
-                if s.last() == Some(&b'\n') {
-                    s.pop();
-                }
-                if s != b"Linux" {
-                    return;
+    /// Whether or not `fix_bin_or_dylib` needs to be run; can only be true
+    /// on NixOS
+    fn should_fix_bins_and_dylibs(&self) -> bool {
+        let val = *SHOULD_FIX_BINS_AND_DYLIBS.get_or_init(|| {
+            match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() {
+                Err(_) => return false,
+                Ok(output) if !output.status.success() => return false,
+                Ok(output) => {
+                    let mut os_name = output.stdout;
+                    if os_name.last() == Some(&b'\n') {
+                        os_name.pop();
+                    }
+                    if os_name != b"Linux" {
+                        return false;
+                    }
                 }
             }
-        }
 
-        // If the user has asked binaries to be patched for Nix, then
-        // don't check for NixOS or `/lib`, just continue to the patching.
-        // NOTE: this intentionally comes after the Linux check:
-        // - patchelf only works with ELF files, so no need to run it on Mac or Windows
-        // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
-        if !self.patch_binaries_for_nix {
+            // If the user has asked binaries to be patched for Nix, then
+            // don't check for NixOS or `/lib`.
+            // NOTE: this intentionally comes after the Linux check:
+            // - patchelf only works with ELF files, so no need to run it on Mac or Windows
+            // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
+            if self.patch_binaries_for_nix {
+                return true;
+            }
+
             // Use `/etc/os-release` instead of `/etc/NIXOS`.
             // The latter one does not exist on NixOS when using tmpfs as root.
-            const NIX_IDS: &[&str] = &["ID=nixos", "ID='nixos'", "ID=\"nixos\""];
-            let os_release = match File::open("/etc/os-release") {
-                Err(e) if e.kind() == ErrorKind::NotFound => return,
+            let is_nixos = match File::open("/etc/os-release") {
+                Err(e) if e.kind() == ErrorKind::NotFound => false,
                 Err(e) => panic!("failed to access /etc/os-release: {}", e),
-                Ok(f) => f,
+                Ok(os_release) => BufReader::new(os_release).lines().any(|l| {
+                    let l = l.expect("reading /etc/os-release");
+                    matches!(l.trim(), "ID=nixos" | "ID='nixos'" | "ID=\"nixos\"")
+                }),
             };
-            if !BufReader::new(os_release).lines().any(|l| NIX_IDS.contains(&t!(l).trim())) {
-                return;
-            }
-            if Path::new("/lib").exists() {
-                return;
-            }
+            is_nixos && !Path::new("/lib").exists()
+        });
+        if val {
+            println!("info: You seem to be using Nix.");
         }
+        val
+    }
 
-        // At this point we're pretty sure the user is running NixOS or using Nix
-        println!("info: you seem to be using Nix. Attempting to patch {}", fname.display());
+    /// Modifies the interpreter section of 'fname' to fix the dynamic linker,
+    /// or the RPATH section, to fix the dynamic library search path
+    ///
+    /// This is only required on NixOS and uses the PatchELF utility to
+    /// change the interpreter/RPATH of ELF executables.
+    ///
+    /// Please see https://nixos.org/patchelf.html for more information
+    fn fix_bin_or_dylib(&self, fname: &Path) {
+        assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true));
+        println!("attempting to patch {}", fname.display());
 
         // Only build `.nix-deps` once.
         static NIX_DEPS_DIR: OnceCell<PathBuf> = OnceCell::new();
@@ -318,18 +328,32 @@ pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
         let channel = format!("{version}-{date}");
 
         let host = self.build;
-        let rustfmt_path = self.initial_rustc.with_file_name(exe("rustfmt", host));
-        let bin_root = self.out.join(host.triple).join("stage0");
+        let bin_root = self.out.join(host.triple).join("rustfmt");
+        let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
         let rustfmt_stamp = bin_root.join(".rustfmt-stamp");
         if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) {
             return Some(rustfmt_path);
         }
 
-        let filename = format!("rustfmt-{version}-{build}.tar.xz", build = host.triple);
-        self.download_component(DownloadSource::Dist, filename, "rustfmt-preview", &date, "stage0");
-
-        self.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt"));
-        self.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt"));
+        self.download_component(
+            DownloadSource::Dist,
+            format!("rustfmt-{version}-{build}.tar.xz", build = host.triple),
+            "rustfmt-preview",
+            &date,
+            "rustfmt",
+        );
+        self.download_component(
+            DownloadSource::Dist,
+            format!("rustc-{version}-{build}.tar.xz", build = host.triple),
+            "rustc",
+            &date,
+            "rustfmt",
+        );
+
+        if self.should_fix_bins_and_dylibs() {
+            self.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt"));
+            self.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt"));
+        }
 
         self.create(&rustfmt_stamp, &channel);
         Some(rustfmt_path)
@@ -358,16 +382,21 @@ pub(crate) fn download_ci_rustc(&self, commit: &str) {
             let filename = format!("rust-src-{version}.tar.xz");
             self.download_ci_component(filename, "rust-src", commit);
 
-            self.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
-            self.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
-            self.fix_bin_or_dylib(&bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"));
-            let lib_dir = bin_root.join("lib");
-            for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
-                let lib = t!(lib);
-                if lib.path().extension() == Some(OsStr::new("so")) {
-                    self.fix_bin_or_dylib(&lib.path());
+            if self.should_fix_bins_and_dylibs() {
+                self.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
+                self.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
+                self.fix_bin_or_dylib(
+                    &bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"),
+                );
+                let lib_dir = bin_root.join("lib");
+                for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
+                    let lib = t!(lib);
+                    if lib.path().extension() == Some(OsStr::new("so")) {
+                        self.fix_bin_or_dylib(&lib.path());
+                    }
                 }
             }
+
             t!(fs::write(rustc_stamp, commit));
         }
     }
@@ -459,8 +488,10 @@ pub(crate) fn maybe_download_ci_llvm(&self) {
         let key = format!("{}{}", llvm_sha, self.llvm_assertions);
         if program_out_of_date(&llvm_stamp, &key) && !self.dry_run() {
             self.download_ci_llvm(&llvm_sha);
-            for entry in t!(fs::read_dir(llvm_root.join("bin"))) {
-                self.fix_bin_or_dylib(&t!(entry).path());
+            if self.should_fix_bins_and_dylibs() {
+                for entry in t!(fs::read_dir(llvm_root.join("bin"))) {
+                    self.fix_bin_or_dylib(&t!(entry).path());
+                }
             }
 
             // Update the timestamp of llvm-config to force rustc_llvm to be
@@ -475,13 +506,16 @@ pub(crate) fn maybe_download_ci_llvm(&self) {
             let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build));
             t!(filetime::set_file_times(&llvm_config, now, now));
 
-            let llvm_lib = llvm_root.join("lib");
-            for entry in t!(fs::read_dir(&llvm_lib)) {
-                let lib = t!(entry).path();
-                if lib.extension().map_or(false, |ext| ext == "so") {
-                    self.fix_bin_or_dylib(&lib);
+            if self.should_fix_bins_and_dylibs() {
+                let llvm_lib = llvm_root.join("lib");
+                for entry in t!(fs::read_dir(&llvm_lib)) {
+                    let lib = t!(entry).path();
+                    if lib.extension().map_or(false, |ext| ext == "so") {
+                        self.fix_bin_or_dylib(&lib);
+                    }
                 }
             }
+
             t!(fs::write(llvm_stamp, key));
         }
     }