From aa874dc6090cf6b6c9621572419738d105ff4ba3 Mon Sep 17 00:00:00 2001
From: Kyle Edwards <kyle.edwards@kitware.com>
Date: Fri, 16 Jul 2021 10:18:31 -0400
Subject: [PATCH] CMakePresets.json: Fix expansion issue with empty binaryDir

When resolving binaryDir into a full path from a relative path, we
forgot to check if binaryDir is altogether empty, causing empty
binaryDir's to resolve to the source directory. Fix this.

Fixes: #22434
---
 Source/cmCMakePresetsFile.cxx                          | 10 ++++++----
 .../CMakePresets/OptionalBinaryDirFieldNoS.cmake       |  4 ++++
 .../CMakePresets/OptionalBinaryDirFieldNoS.json.in     |  9 +++++++++
 Tests/RunCMake/CMakePresets/RunCMakeTest.cmake         |  5 +++++
 4 files changed, 24 insertions(+), 4 deletions(-)
 create mode 100644 Tests/RunCMake/CMakePresets/OptionalBinaryDirFieldNoS.cmake
 create mode 100644 Tests/RunCMake/CMakePresets/OptionalBinaryDirFieldNoS.json.in

diff --git a/Source/cmCMakePresetsFile.cxx b/Source/cmCMakePresetsFile.cxx
index 2f9972c381c..fd578faef79 100644
--- a/Source/cmCMakePresetsFile.cxx
+++ b/Source/cmCMakePresetsFile.cxx
@@ -197,11 +197,13 @@ bool ExpandMacros(const cmCMakePresetsFile& file,
   std::string binaryDir = preset.BinaryDir;
   CHECK_EXPAND(out, binaryDir, macroExpanders, file.GetVersion(preset))
 
-  if (!cmSystemTools::FileIsFullPath(binaryDir)) {
-    binaryDir = cmStrCat(file.SourceDir, '/', binaryDir);
+  if (!binaryDir.empty()) {
+    if (!cmSystemTools::FileIsFullPath(binaryDir)) {
+      binaryDir = cmStrCat(file.SourceDir, '/', binaryDir);
+    }
+    out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
+    cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
   }
-  out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
-  cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
 
   if (!preset.InstallDir.empty()) {
     std::string installDir = preset.InstallDir;
diff --git a/Tests/RunCMake/CMakePresets/OptionalBinaryDirFieldNoS.cmake b/Tests/RunCMake/CMakePresets/OptionalBinaryDirFieldNoS.cmake
new file mode 100644
index 00000000000..ae8a0def19f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalBinaryDirFieldNoS.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+get_filename_component(_parent_dir "${CMAKE_SOURCE_DIR}" DIRECTORY)
+test_variable(CMAKE_BINARY_DIR "" "${_parent_dir}/OptionalBinaryDirFieldNoS-build")
diff --git a/Tests/RunCMake/CMakePresets/OptionalBinaryDirFieldNoS.json.in b/Tests/RunCMake/CMakePresets/OptionalBinaryDirFieldNoS.json.in
new file mode 100644
index 00000000000..0e3addd560b
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalBinaryDirFieldNoS.json.in
@@ -0,0 +1,9 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "OptionalBinaryDirFieldNoS",
+      "generator": "@RunCMake_GENERATOR@"
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
index 3b9806ab7ef..31bd8a44536 100644
--- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -312,6 +312,11 @@ unset(CMakePresets_FILE)
 # Test optional generator and buildDir fields
 run_cmake_presets(OptionalBinaryDirField -B "${RunCMake_BINARY_DIR}/OptionalBinaryDirField/build")
 run_cmake_presets(OptionalGeneratorField -G "${RunCMake_GENERATOR}")
+set(CMakePresets_NO_S_ARG TRUE)
+set(CMakePresets_SOURCE_ARG "../OptionalBinaryDirFieldNoS")
+run_cmake_presets(OptionalBinaryDirFieldNoS)
+unset(CMakePresets_SOURCE_ARG)
+unset(CMakePresets_NO_S_ARG)
 
 # Test the example from the documentation
 file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _example)
-- 
GitLab