cmake --build --preset: Relax CWD constraint

Prior to this commit, cmake --build <dir> --preset <pre> needed to be called
from the source directory. We now look up the source directory in
CMakeCache.txt when a build directory is specified on the command line.

Issue: #27075
This commit is contained in:
Zack Galbreath
2026-04-23 09:23:01 -04:00
parent c6f896526a
commit 021cf4f4f7
6 changed files with 63 additions and 11 deletions
+12 -6
View File
@@ -778,8 +778,8 @@ project binary tree:
.. code-block:: shell
cmake --build <dir> [<options>] [-- <build-tool-options>]
cmake --build --preset <preset> [<options>] [-- <build-tool-options>]
cmake --build <dir> [<options>] [-- <build-tool-options>]
cmake --build [<dir>] --preset <preset> [<options>] [-- <build-tool-options>]
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 <cmake-presets(7)>` for more details.
after ``--build``. See :manual:`preset <cmake-presets(7)>` for more details.
.. versionadded:: 4.3
``cmake --build`` now supports specifying a build directory and
preset together.
.. versionchanged:: 4.4
``cmake --build <dir> --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 <dir> --list-presets`` no longer needs to be called from
the directory containing the CMake presets files.
.. option:: -j [<jobs>], --parallel [<jobs>]
@@ -0,0 +1,5 @@
cmake-build-preset-dir
----------------------
* :manual:`cmake(1)` now supports ``--build <dir> --preset <pre>``
regardless of the current working directory.
+11 -3
View File
@@ -3909,9 +3909,17 @@ int cmake::Build(cmBuildArgs buildArgs, std::vector<std::string> 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) {
@@ -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$
@@ -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 <dir> --preset <pre>` 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 <dir> --preset <pre>` 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()