Commit c6129272 authored by Brad King's avatar Brad King

file(RENAME): Add option to capture error message on failure

parent 0c2dc345
......@@ -38,7 +38,7 @@ Synopsis
file({`GLOB`_ | `GLOB_RECURSE`_} <out-var> [...] [<globbing-expr>...])
file(`RENAME`_ <oldname> <newname>)
file(`RENAME`_ <oldname> <newname> [...])
file({`REMOVE`_ | `REMOVE_RECURSE`_ } [<files>...])
file(`MAKE_DIRECTORY`_ [<dir>...])
file({`COPY`_ | `INSTALL`_} <file>... DESTINATION <dir> [...])
......@@ -665,11 +665,18 @@ Examples of recursive globbing include::
.. code-block:: cmake
file(RENAME <oldname> <newname>)
file(RENAME <oldname> <newname>
[RESULT <result>])
Move a file or directory within a filesystem from ``<oldname>`` to
``<newname>``, replacing the destination atomically.
The options are:
``RESULT <result>``
Set ``<result>`` variable to ``0`` on success or an error message otherwise.
If ``RESULT`` is not specified and the operation fails, an error is emitted.
* The :command:`file(RENAME)` command learned to optionally capture
failure in a result variable.
......@@ -1313,8 +1313,9 @@ bool HandleRelativePathCommand(std::vector<std::string> const& args,
bool HandleRename(std::vector<std::string> const& args,
cmExecutionStatus& status)
if (args.size() != 3) {
status.SetError("RENAME given incorrect number of arguments.");
if (args.size() < 3) {
status.SetError("RENAME must be called with at least two additional "
return false;
......@@ -1330,13 +1331,39 @@ bool HandleRename(std::vector<std::string> const& args,
cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[2]);
if (!cmSystemTools::RenameFile(oldname, newname)) {
std::string err = cmSystemTools::GetLastSystemError();
status.SetError(cmStrCat("RENAME failed to rename\n ", oldname,
"\nto\n ", newname, "\nbecause: ", err, "\n"));
struct Arguments
std::string Result;
static auto const parser =
cmArgumentParser<Arguments>{}.Bind("RESULT"_s, &Arguments::Result);
std::vector<std::string> unconsumedArgs;
Arguments const arguments =
parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
if (!unconsumedArgs.empty()) {
status.SetError("RENAME unknown argument:\n " + unconsumedArgs.front());
return false;
return true;
std::string err;
switch (cmSystemTools::RenameFile(oldname, newname, &err)) {
case cmSystemTools::RenameResult::Success:
if (!arguments.Result.empty()) {
status.GetMakefile().AddDefinition(arguments.Result, "0");
return true;
case cmSystemTools::RenameResult::Failure:
if (!arguments.Result.empty()) {
status.GetMakefile().AddDefinition(arguments.Result, err);
return true;
status.SetError(cmStrCat("RENAME failed to rename\n ", oldname, "\nto\n ",
newname, "\nbecause: ", err, "\n"));
return false;
bool HandleRemoveImpl(std::vector<std::string> const& args, bool recurse,
^CMake Error at [^
]*/Tests/RunCMake/file/RENAME-arg-missing.cmake:1 \(file\):
file RENAME must be called with at least two additional arguments$
^CMake Error at [^
]*/Tests/RunCMake/file/RENAME-arg-unknown.cmake:1 \(file\):
file RENAME unknown argument:
file(RENAME "old" "new" unknown)
^-- file\(RENAME\) failed with result: [A-Za-z]
set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
file(WRITE "${oldname}" "")
file(MAKE_DIRECTORY "${newname}")
file(RENAME "${oldname}" "${newname}" RESULT result)
message(STATUS "file(RENAME) failed with result: ${result}")
if(NOT EXISTS "${oldname}")
message(FATAL_ERROR "The old name does not still exist:\n ${oldname}")
^CMake Error at [^
]*/Tests/RunCMake/file/RENAME-file-to-dir-fail.cmake:[0-9] \(file\):
file RENAME failed to rename
because: [A-Za-z]
set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
file(WRITE "${oldname}" "")
file(MAKE_DIRECTORY "${newname}")
file(RENAME "${oldname}" "${newname}")
set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
file(WRITE "${oldname}" "")
file(RENAME "${oldname}" "${newname}")
if(EXISTS "${oldname}")
message(FATAL_ERROR "The old name still exists:\n ${oldname}")
if(NOT EXISTS "${newname}")
message(FATAL_ERROR "The new name does not exist:\n ${newname}")
......@@ -50,6 +50,12 @@ run_cmake(SIZE-error-does-not-exist)
# tests are valid both for GLOB and GLOB_RECURSE
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment