diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 4ce3f7ed21..eef6f6dc39 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -778,8 +778,8 @@ project binary tree: .. code-block:: shell - cmake --build [] [-- ] - cmake --build --preset [] [-- ] + cmake --build [] [-- ] + cmake --build [] --preset [] [-- ] This abstracts a native build tool's command-line interface with the following options: @@ -795,17 +795,23 @@ following options: Use a build preset to specify build options. The project binary directory is inferred from the ``configurePreset`` key unless a directory is specified - after ``--build``. The current working directory must contain CMake preset - files. See :manual:`preset ` for more details. + after ``--build``. See :manual:`preset ` for more details. .. versionadded:: 4.3 ``cmake --build`` now supports specifying a build directory and preset together. + .. versionchanged:: 4.4 + ``cmake --build --preset`` no longer needs to be called from the + directory containing the CMake presets files. + .. option:: --list-presets - Lists the available build presets. The current working directory must - contain CMake preset files. + Lists the available build presets. + + .. versionchanged:: 4.4 + ``cmake --build --list-presets`` no longer needs to be called from + the directory containing the CMake presets files. .. option:: -j [], --parallel [] diff --git a/Help/release/dev/cmake-build-preset-dir.rst b/Help/release/dev/cmake-build-preset-dir.rst new file mode 100644 index 0000000000..4422487c9b --- /dev/null +++ b/Help/release/dev/cmake-build-preset-dir.rst @@ -0,0 +1,5 @@ +cmake-build-preset-dir +---------------------- + +* :manual:`cmake(1)` now supports ``--build --preset
``
+  regardless of the current working directory.
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 3598518cd0..d7d7bc1ac3 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -3909,9 +3909,17 @@ int cmake::Build(cmBuildArgs buildArgs, std::vector targets,
 
 #if !defined(CMAKE_BOOTSTRAP)
   if (!presetName.empty() || listPresets) {
-    this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
-    this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
-
+    // If the binary directory was specified, use it to find
+    // the source directory so we can locate the presets file.
+    if (!buildArgs.binaryDir.empty() &&
+        this->SetDirectoriesFromFile(buildArgs.binaryDir)) {
+      // HomeDirectory is now the source directory (found in CMakeCache.txt)
+    } else {
+      // Otherwise we assume this command was called from the source directory.
+      this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
+      this->SetHomeOutputDirectory(
+        cmSystemTools::GetLogicalWorkingDirectory());
+    }
     cmCMakePresetsGraph settingsFile;
     auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
     if (result != true) {
diff --git a/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-stderr.txt
index fbd9416468..86204c2a50 100644
--- a/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-stderr.txt
+++ b/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-stderr.txt
@@ -1,2 +1,4 @@
-^Error: [^
-]*/Tests/RunCMake/build2 is not a directory$
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/build2:
+File not found: [^
+]*/Tests/RunCMake/build2/CMakePresets.json$
diff --git a/Tests/RunCMake/CMakePresetsBuild/BuildPresetFromBinaryDir.cmake b/Tests/RunCMake/CMakePresetsBuild/BuildPresetFromBinaryDir.cmake
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
index 5479343721..92378d35e9 100644
--- a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
@@ -90,3 +90,34 @@ set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
 
 run_cmake_build_presets(ConfigurePresetUnreachable "x" "x" "")
 set(CMakePresetsBuild_BUILD_ONLY 0)
+
+# Verify that `cmake --build  --preset 
` works when
+# the current working directory is not the source directory.
+block()
+  set(name "BuildPresetFromBinaryDir")
+  set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_SOURCE_DIR}/build/default")
+  set(RunCMake_TEST_NO_CLEAN TRUE)
+
+  file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  set(CASE_NAME "${name}")
+  set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
+  configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt.in"
+                 "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" @ONLY)
+  configure_file("${RunCMake_SOURCE_DIR}/ListPresets.json.in"
+                 "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" @ONLY)
+
+  # Configure using the "default" preset.
+  set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+  run_cmake_command("${name}-configure"
+    "${CMAKE_COMMAND}" "--preset" "default")
+
+  # Verify calling `cmake --build  --preset 
` from the
+  # binary directory.
+  set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  run_cmake_command("${name}-build"
+    "${CMAKE_COMMAND}" "--build" "${RunCMake_TEST_BINARY_DIR}"
+    "--preset" "build-default")
+endblock()