From 7610aa55590575671d203aa5afa8c27ab73fcf3a Mon Sep 17 00:00:00 2001
From: Jieyou Xu <jieyouxu@outlook.com>
Date: Thu, 7 Nov 2024 20:02:09 +0800
Subject: [PATCH] Unify `sysroot_target_{bin,lib}dir` handling

---
 src/bootstrap/src/core/builder/mod.rs   | 95 +++++++++++++------------
 src/bootstrap/src/core/builder/tests.rs | 46 ++++++++++++
 2 files changed, 96 insertions(+), 45 deletions(-)

diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 73bc7195ac24c..026c26479d355 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -765,6 +765,54 @@ impl Kind {
     }
 }
 
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+struct Libdir {
+    compiler: Compiler,
+    target: TargetSelection,
+}
+
+impl Step for Libdir {
+    type Output = PathBuf;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.never()
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        let relative_sysroot_libdir = builder.sysroot_libdir_relative(self.compiler);
+        let sysroot = builder.sysroot(self.compiler).join(relative_sysroot_libdir).join("rustlib");
+
+        if !builder.config.dry_run() {
+            // Avoid deleting the `rustlib/` directory we just copied (in `impl Step for
+            // Sysroot`).
+            if !builder.download_rustc() {
+                let sysroot_target_libdir = sysroot.join(self.target).join("lib");
+                builder.verbose(|| {
+                    eprintln!(
+                        "Removing sysroot {} to avoid caching bugs",
+                        sysroot_target_libdir.display()
+                    )
+                });
+                let _ = fs::remove_dir_all(&sysroot_target_libdir);
+                t!(fs::create_dir_all(&sysroot_target_libdir));
+            }
+
+            if self.compiler.stage == 0 {
+                // The stage 0 compiler for the build triple is always pre-built. Ensure that
+                // `libLLVM.so` ends up in the target libdir, so that ui-fulldeps tests can use
+                // it when run.
+                dist::maybe_install_llvm_target(
+                    builder,
+                    self.compiler.host,
+                    &builder.sysroot(self.compiler),
+                );
+            }
+        }
+
+        sysroot
+    }
+}
+
 impl<'a> Builder<'a> {
     fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
         macro_rules! describe {
@@ -1165,56 +1213,13 @@ impl<'a> Builder<'a> {
 
     /// Returns the bindir for a compiler's sysroot.
     pub fn sysroot_target_bindir(&self, compiler: Compiler, target: TargetSelection) -> PathBuf {
-        self.sysroot_target_libdir(compiler, target).parent().unwrap().join("bin")
+        self.ensure(Libdir { compiler, target }).join(target).join("bin")
     }
 
     /// Returns the libdir where the standard library and other artifacts are
     /// found for a compiler's sysroot.
     pub fn sysroot_target_libdir(&self, compiler: Compiler, target: TargetSelection) -> PathBuf {
-        #[derive(Debug, Clone, Hash, PartialEq, Eq)]
-        struct Libdir {
-            compiler: Compiler,
-            target: TargetSelection,
-        }
-        impl Step for Libdir {
-            type Output = PathBuf;
-
-            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-                run.never()
-            }
-
-            fn run(self, builder: &Builder<'_>) -> PathBuf {
-                let lib = builder.sysroot_libdir_relative(self.compiler);
-                let sysroot = builder
-                    .sysroot(self.compiler)
-                    .join(lib)
-                    .join("rustlib")
-                    .join(self.target)
-                    .join("lib");
-                // Avoid deleting the rustlib/ directory we just copied
-                // (in `impl Step for Sysroot`).
-                if !builder.download_rustc() {
-                    builder.verbose(|| {
-                        println!("Removing sysroot {} to avoid caching bugs", sysroot.display())
-                    });
-                    let _ = fs::remove_dir_all(&sysroot);
-                    t!(fs::create_dir_all(&sysroot));
-                }
-
-                if self.compiler.stage == 0 {
-                    // The stage 0 compiler for the build triple is always pre-built.
-                    // Ensure that `libLLVM.so` ends up in the target libdir, so that ui-fulldeps tests can use it when run.
-                    dist::maybe_install_llvm_target(
-                        builder,
-                        self.compiler.host,
-                        &builder.sysroot(self.compiler),
-                    );
-                }
-
-                sysroot
-            }
-        }
-        self.ensure(Libdir { compiler, target })
+        self.ensure(Libdir { compiler, target }).join(target).join("lib")
     }
 
     pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index a1c8bff0db97e..b2ffbd9c70f6a 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -738,3 +738,49 @@ mod dist {
         ]);
     }
 }
+
+mod sysroot_target_dirs {
+    use super::{
+        Build, Builder, Compiler, TEST_TRIPLE_1, TEST_TRIPLE_2, TargetSelection, configure,
+    };
+
+    #[test]
+    fn test_sysroot_target_libdir() {
+        let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]));
+        let builder = Builder::new(&build);
+        let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1);
+        let compiler = Compiler { stage: 1, host: target_triple_1 };
+        let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2);
+        let actual = builder.sysroot_target_libdir(compiler, target_triple_2);
+
+        assert_eq!(
+            builder
+                .sysroot(compiler)
+                .join(builder.sysroot_libdir_relative(compiler))
+                .join("rustlib")
+                .join(TEST_TRIPLE_2)
+                .join("lib"),
+            actual
+        );
+    }
+
+    #[test]
+    fn test_sysroot_target_bindir() {
+        let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]));
+        let builder = Builder::new(&build);
+        let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1);
+        let compiler = Compiler { stage: 1, host: target_triple_1 };
+        let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2);
+        let actual = builder.sysroot_target_bindir(compiler, target_triple_2);
+
+        assert_eq!(
+            builder
+                .sysroot(compiler)
+                .join(builder.sysroot_libdir_relative(compiler))
+                .join("rustlib")
+                .join(TEST_TRIPLE_2)
+                .join("bin"),
+            actual
+        );
+    }
+}