about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Beránek <berykubik@gmail.com>2025-06-12 15:41:02 +0200
committerJakub Beránek <berykubik@gmail.com>2025-06-12 15:48:50 +0200
commita71b463d2b3ae896db91b6e5ba116c77f1ce7d48 (patch)
tree948bec1dd9ace7b5ed597e145f3c6d4fbccb0c25
parentdbe15e3e94ac206d212a5f3370edb6f9ac2c4463 (diff)
downloadrust-a71b463d2b3ae896db91b6e5ba116c77f1ce7d48.tar.gz
rust-a71b463d2b3ae896db91b6e5ba116c77f1ce7d48.zip
Move submodule path cache from `parse_gitmodules` to `Builder`
It would not be correct if multiple values of `target_dir` were ever passed to the function in the same process.
-rw-r--r--src/bootstrap/src/core/builder/mod.rs21
-rw-r--r--src/bootstrap/src/lib.rs8
-rw-r--r--src/bootstrap/src/utils/helpers.rs2
-rw-r--r--src/build_helper/src/util.rs26
4 files changed, 30 insertions, 27 deletions
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 887db683f78..7433f0b0f3b 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -5,7 +5,7 @@ use std::fmt::{self, Debug, Write};
 use std::hash::Hash;
 use std::ops::Deref;
 use std::path::{Path, PathBuf};
-use std::sync::LazyLock;
+use std::sync::{LazyLock, OnceLock};
 use std::time::{Duration, Instant};
 use std::{env, fs};
 
@@ -60,6 +60,9 @@ pub struct Builder<'a> {
     /// to do. For example: with `./x check foo bar` we get `paths=["foo",
     /// "bar"]`.
     pub paths: Vec<PathBuf>,
+
+    /// Cached list of submodules from self.build.src.
+    submodule_paths_cache: OnceLock<Vec<String>>,
 }
 
 impl Deref for Builder<'_> {
@@ -687,7 +690,7 @@ impl<'a> ShouldRun<'a> {
     ///
     /// [`path`]: ShouldRun::path
     pub fn paths(mut self, paths: &[&str]) -> Self {
-        let submodules_paths = build_helper::util::parse_gitmodules(&self.builder.src);
+        let submodules_paths = self.builder.submodule_paths();
 
         self.paths.insert(PathSet::Set(
             paths
@@ -1180,6 +1183,7 @@ impl<'a> Builder<'a> {
             stack: RefCell::new(Vec::new()),
             time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
             paths,
+            submodule_paths_cache: Default::default(),
         }
     }
 
@@ -1510,6 +1514,19 @@ impl<'a> Builder<'a> {
         None
     }
 
+    /// Updates all submodules, and exits with an error if submodule
+    /// management is disabled and the submodule does not exist.
+    pub fn require_and_update_all_submodules(&self) {
+        for submodule in self.submodule_paths() {
+            self.require_submodule(submodule, None);
+        }
+    }
+
+    /// Get all submodules from the src directory.
+    pub fn submodule_paths(&self) -> &[String] {
+        self.submodule_paths_cache.get_or_init(|| build_helper::util::parse_gitmodules(&self.src))
+    }
+
     /// Ensure that a given step is built, returning its output. This will
     /// cache the step, so it is safe (and good!) to call this as often as
     /// needed to ensure that all dependencies are built.
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 215586b32f0..fd874604bbe 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -591,14 +591,6 @@ impl Build {
         }
     }
 
-    /// Updates all submodules, and exits with an error if submodule
-    /// management is disabled and the submodule does not exist.
-    pub fn require_and_update_all_submodules(&self) {
-        for submodule in build_helper::util::parse_gitmodules(&self.src) {
-            self.require_submodule(submodule, None);
-        }
-    }
-
     /// If any submodule has been initialized already, sync it unconditionally.
     /// This avoids contributors checking in a submodule change by accident.
     fn update_existing_submodules(&self) {
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index f2c3e8c0df4..4f361af4bf7 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -98,7 +98,7 @@ pub fn is_dylib(path: &Path) -> bool {
 
 /// Return the path to the containing submodule if available.
 pub fn submodule_path_of(builder: &Builder<'_>, path: &str) -> Option<String> {
-    let submodule_paths = build_helper::util::parse_gitmodules(&builder.src);
+    let submodule_paths = builder.submodule_paths();
     submodule_paths.iter().find_map(|submodule_path| {
         if path.starts_with(submodule_path) { Some(submodule_path.to_string()) } else { None }
     })
diff --git a/src/build_helper/src/util.rs b/src/build_helper/src/util.rs
index 72c05c4c48a..80dd6813d13 100644
--- a/src/build_helper/src/util.rs
+++ b/src/build_helper/src/util.rs
@@ -2,7 +2,6 @@ use std::fs::File;
 use std::io::{BufRead, BufReader};
 use std::path::Path;
 use std::process::Command;
-use std::sync::OnceLock;
 
 /// Invokes `build_helper::util::detail_exit` with `cfg!(test)`
 ///
@@ -51,25 +50,20 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> {
 }
 
 /// Returns the submodule paths from the `.gitmodules` file in the given directory.
-pub fn parse_gitmodules(target_dir: &Path) -> &[String] {
-    static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new();
+pub fn parse_gitmodules(target_dir: &Path) -> Vec<String> {
     let gitmodules = target_dir.join(".gitmodules");
     assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display());
 
-    let init_submodules_paths = || {
-        let file = File::open(gitmodules).unwrap();
+    let file = File::open(gitmodules).unwrap();
 
-        let mut submodules_paths = vec![];
-        for line in BufReader::new(file).lines().map_while(Result::ok) {
-            let line = line.trim();
-            if line.starts_with("path") {
-                let actual_path = line.split(' ').last().expect("Couldn't get value of path");
-                submodules_paths.push(actual_path.to_owned());
-            }
+    let mut submodules_paths = vec![];
+    for line in BufReader::new(file).lines().map_while(Result::ok) {
+        let line = line.trim();
+        if line.starts_with("path") {
+            let actual_path = line.split(' ').last().expect("Couldn't get value of path");
+            submodules_paths.push(actual_path.to_owned());
         }
+    }
 
-        submodules_paths
-    };
-
-    SUBMODULES_PATHS.get_or_init(|| init_submodules_paths())
+    submodules_paths
 }