Browse Source

cmake: When given multiple source paths use last instead of first

When given two source paths via `-S` or just directory paths prefer
the last one. When the paths are mixed always prefer the last `-S`
entry.

Fixes: #23238
Robert Maynard 3 years ago
parent
commit
7083b19498

+ 36 - 5
Source/cmake.cxx

@@ -818,7 +818,8 @@ void cmake::SetArgs(const std::vector<std::string>& args)
     }
     std::string path = cmSystemTools::CollapseFullPath(value);
     cmSystemTools::ConvertToUnixSlashes(path);
-    state->SetHomeDirectory(path);
+
+    state->SetHomeDirectoryViaCommandLine(path, HomeDirArgStyle::Dash_S);
     return true;
   };
 
@@ -1486,6 +1487,7 @@ bool cmake::SetDirectoriesFromFile(const std::string& arg)
   // CMakeLists.txt file.
   std::string listPath;
   std::string cachePath;
+  bool is_source_dir = false;
   bool is_empty_directory = false;
   if (cmSystemTools::FileIsDirectory(arg)) {
     std::string path = cmSystemTools::CollapseFullPath(arg);
@@ -1501,6 +1503,7 @@ bool cmake::SetDirectoriesFromFile(const std::string& arg)
     if (cmSystemTools::FileExists(listFile)) {
       listPath = path;
       is_empty_directory = false;
+      is_source_dir = true;
     }
   } else if (cmSystemTools::FileExists(arg)) {
     std::string fullPath = cmSystemTools::CollapseFullPath(arg);
@@ -1545,19 +1548,23 @@ bool cmake::SetDirectoriesFromFile(const std::string& arg)
   const bool passed_same_path = (listPath == this->GetHomeDirectory()) ||
     (listPath == this->GetHomeOutputDirectory());
   bool used_provided_path =
-    (passed_same_path || no_source_tree || no_build_tree);
+    (passed_same_path || is_source_dir || no_build_tree);
 
   // If there is a CMakeLists.txt file, use it as the source tree.
   if (!listPath.empty()) {
     // When invoked with a path that points to an existing CMakeCache
     // This function is called multiple times with the same path
-    if (no_source_tree && no_build_tree) {
+    if (is_source_dir) {
+      this->SetHomeDirectoryViaCommandLine(listPath, HomeDirArgStyle::Plain);
+      if (!no_build_tree) {
+        std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+        this->SetHomeOutputDirectory(cwd);
+      }
+    } else if (no_source_tree && no_build_tree) {
       this->SetHomeDirectory(listPath);
 
       std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
       this->SetHomeOutputDirectory(cwd);
-    } else if (no_source_tree) {
-      this->SetHomeDirectory(listPath);
     } else if (no_build_tree) {
       this->SetHomeOutputDirectory(listPath);
     }
@@ -1773,6 +1780,30 @@ void cmake::PrintPresetList(const cmCMakePresetsGraph& graph) const
 }
 #endif
 
+void cmake::SetHomeDirectoryViaCommandLine(std::string const& path,
+                                           HomeDirArgStyle argStyle)
+{
+  bool fromDashS = argStyle == HomeDirArgStyle::Dash_S;
+  static bool homeDirectorySetExplicitly = false;
+  if (path.empty()) {
+    return;
+  }
+
+  auto prev_path = this->GetHomeDirectory();
+  if (prev_path != path && !prev_path.empty()) {
+    const bool ignore_prev_path =
+      (fromDashS || (!fromDashS && !homeDirectorySetExplicitly));
+    const std::string& ignored_path = (ignore_prev_path) ? prev_path : path;
+    this->IssueMessage(MessageType::WARNING,
+                       cmStrCat("Ignoring extra path from command line:\n \"",
+                                ignored_path, "\""));
+  }
+  if (fromDashS || !homeDirectorySetExplicitly) {
+    this->SetHomeDirectory(path);
+  }
+  homeDirectorySetExplicitly = fromDashS;
+}
+
 void cmake::SetHomeDirectory(const std::string& dir)
 {
   this->State->SetSourceDirectory(dir);

+ 23 - 0
Source/cmake.h

@@ -183,6 +183,29 @@ public:
 #endif
   std::string ReportCapabilities() const;
 
+  enum class HomeDirArgStyle
+  {
+    Plain,
+    Dash_S,
+  };
+
+  /**
+   * Set the home directory from `-S` or from a known location
+   * that contains a CMakeLists.txt. Will generate warnings
+   * when overriding an existing source directory.
+   *
+   *  |    args           | src dir| warning        |
+   *  | ----------------- | ------ | -------------- |
+   *  | `dirA dirA`       | dirA   | N/A            |
+   *  | `-S dirA -S dirA` | dirA   | N/A            |
+   *  | `-S dirA -S dirB` | dirB   | Ignoring dirA  |
+   *  | `-S dirA dirB`    | dirA   | Ignoring dirB  |
+   *  | `dirA -S dirB`    | dirB   | Ignoring dirA  |
+   *  | `dirA dirB`       | dirB   | Ignoring dirA  |
+   */
+  void SetHomeDirectoryViaCommandLine(std::string const& path,
+                                      HomeDirArgStyle argStyle);
+
   //@{
   /**
    * Set/Get the home directory (or output directory) in the project. The

+ 12 - 0
Tests/RunCMake/CommandLine/RunCMakeTest.cmake

@@ -168,6 +168,18 @@ endif()
   run_cmake_with_raw_args(S-B-non-path "-S \"${source_dir}\" -B \"${binary_dir}\" \"\"")
   run_cmake_with_raw_args(S-B-non-path2 "-S \"${source_dir}\" \"\" -B \"${binary_dir}\"")
 
+  file(REMOVE_RECURSE "${binary_dir}/other_dir")
+  file(MAKE_DIRECTORY "${binary_dir}/other_dir")
+  file(WRITE "${binary_dir}/other_dir/CMakeLists.txt" [=[ ]=])
+  run_cmake_with_options(S-S-same -S ${source_dir} -S ${source_dir} -B ${binary_dir})
+  run_cmake_with_options(S-S-differs -S ${binary_dir}/other_dir -S ${source_dir} -B ${binary_dir})
+  run_cmake_with_options(S-implicit-same -S ${source_dir} ${source_dir} -B ${binary_dir})
+  run_cmake_with_options(S-implicit-differs -S ${source_dir} ${binary_dir}/other_dir -B ${binary_dir})
+  run_cmake_with_options(S-implicit-differs2 ${binary_dir}/other_dir -S ${source_dir} -B ${binary_dir})
+  run_cmake_with_options(S-implicit-differs3 ${binary_dir}/other_dir ${source_dir} -B ${binary_dir})
+  run_cmake_with_options(S-S-Sdiffers -S ${binary_dir}/other_dir1 -S ${binary_dir}/other_dir2 -S ${source_dir} -B ${binary_dir})
+  run_cmake_with_options(S-S-Simplicit ${binary_dir}/other_dir1 ${binary_dir}/other_dir2 ${source_dir} -B ${binary_dir})
+
   # make sure that -B can explicitly construct build directories
   file(REMOVE_RECURSE "${binary_dir}")
   run_cmake_with_options(B-arg -B ${binary_dir} ${source_dir})

+ 9 - 0
Tests/RunCMake/CommandLine/S-S-Sdiffers-stderr.txt

@@ -0,0 +1,9 @@
+^CMake Warning:
+  Ignoring extra path from command line:
+
+   .*other_dir1"
+.*
+CMake Warning:
+  Ignoring extra path from command line:
+
+   .*other_dir2"$

+ 9 - 0
Tests/RunCMake/CommandLine/S-S-Simplicit-stderr.txt

@@ -0,0 +1,9 @@
+^CMake Warning:
+  Ignoring extra path from command line:
+
+   .*other_dir1"
+.*
+CMake Warning:
+  Ignoring extra path from command line:
+
+   .*other_dir2"$

+ 4 - 0
Tests/RunCMake/CommandLine/S-S-differs-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Warning:
+  Ignoring extra path from command line:
+
+   .*ExplicitDirs-build/other_dir.*

+ 4 - 0
Tests/RunCMake/CommandLine/S-implicit-differs-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Warning:
+  Ignoring extra path from command line:
+
+   .*other_dir"$

+ 4 - 0
Tests/RunCMake/CommandLine/S-implicit-differs2-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Warning:
+  Ignoring extra path from command line:
+
+   .*ExplicitDirs-build/other_dir.*

+ 4 - 0
Tests/RunCMake/CommandLine/S-implicit-differs3-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Warning:
+  Ignoring extra path from command line:
+
+   .*ExplicitDirs-build/other_dir.*