1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-14 19:08:07 +08:00

file(MAKE_DIRECTORY): Add optional RESULT keyword to capture failure.

Fixes: #26041
This commit is contained in:
Asit Dhal
2024-06-16 19:44:03 +02:00
parent eea58be537
commit 95323c90a1
19 changed files with 124 additions and 21 deletions

View File

@@ -398,10 +398,19 @@ Filesystem
============== ======================================================
.. signature::
file(MAKE_DIRECTORY <directories>...)
file(MAKE_DIRECTORY <directories>... [RESULT <result>])
Create the given directories and their parents as needed.
The options are:
``RESULT <result>``
.. versionadded:: 3.31
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.
.. versionchanged:: 3.30
``<directories>`` can be an empty list. CMake 3.29 and earlier required
at least one directory to be given.

View File

@@ -0,0 +1,5 @@
make_directory-optional-result
------------------------------
* The :command:`file(MAKE_DIRECTORY)` learned to
optionally capture failure in a result variable.

View File

@@ -8,6 +8,7 @@
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iterator>
#include <map>
#include <set>
#include <sstream>
@@ -881,6 +882,42 @@ bool HandleMakeDirectoryCommand(std::vector<std::string> const& args,
// Projects might pass a dynamically generated list of directories, and it
// could be an empty list. We should not assume there is at least one.
cmRange<std::vector<std::string>::const_iterator> argsRange =
cmMakeRange(args).advance(1); // Get rid of subcommand
struct Arguments : public ArgumentParser::ParseResult
{
std::string Result;
};
Arguments arguments;
auto resultPosItr =
std::find(cm::begin(argsRange), cm::end(argsRange), "RESULT");
if (resultPosItr != cm::end(argsRange)) {
static auto const parser =
cmArgumentParser<Arguments>{}.Bind("RESULT"_s, &Arguments::Result);
std::vector<std::string> unparsedArguments;
auto resultDistanceFromBegin =
std::distance(cm::begin(argsRange), resultPosItr);
arguments =
parser.Parse(cmMakeRange(argsRange).advance(resultDistanceFromBegin),
&unparsedArguments);
if (!unparsedArguments.empty()) {
std::string unexpectedArgsStr = cmJoin(
cmMakeRange(cm::begin(unparsedArguments), cm::end(unparsedArguments)),
"\n");
status.SetError("MAKE_DIRECTORY called with unexpected\n"
"arguments:\n" +
unexpectedArgsStr);
return false;
}
auto resultDistanceFromEnd =
std::distance(cm::end(argsRange), resultPosItr);
argsRange = argsRange.retreat(-resultDistanceFromEnd);
}
std::string expr;
for (std::string const& arg :
cmMakeRange(args).advance(1)) // Get rid of subcommand
@@ -892,20 +929,34 @@ bool HandleMakeDirectoryCommand(std::vector<std::string> const& args,
cdir = &expr;
}
if (!status.GetMakefile().CanIWriteThisFile(*cdir)) {
std::string e = "attempted to create a directory: " + *cdir +
" into a source directory.";
status.SetError(e);
cmSystemTools::SetFatalErrorOccurred();
return false;
std::string e = cmStrCat("attempted to create a directory: ", *cdir,
" into a source directory.");
if (arguments.Result.empty()) {
status.SetError(e);
cmSystemTools::SetFatalErrorOccurred();
return false;
}
status.GetMakefile().AddDefinition(arguments.Result, e);
return true;
}
cmsys::Status mkdirStatus = cmSystemTools::MakeDirectory(*cdir);
if (!mkdirStatus) {
std::string error = cmStrCat("failed to create directory:\n ", *cdir,
"\nbecause: ", mkdirStatus.GetString());
status.SetError(error);
return false;
if (arguments.Result.empty()) {
std::string errorOutput =
cmStrCat("failed to create directory:\n ", *cdir,
"\nbecause: ", mkdirStatus.GetString());
status.SetError(errorOutput);
return false;
}
std::string errorResult = cmStrCat("Failed to create directory: ", *cdir,
" Error: ", mkdirStatus.GetString());
status.GetMakefile().AddDefinition(arguments.Result, errorResult);
return true;
}
}
if (!arguments.Result.empty()) {
status.GetMakefile().AddDefinition(arguments.Result, "0");
}
return true;
}

View File

@@ -588,6 +588,7 @@ foreach(var
endif()
endforeach()
add_RunCMake_test(file-DOWNLOAD)
add_RunCMake_test(file-MAKE_DIRECTORY)
add_RunCMake_test(file-RPATH
-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
-DCMake_TEST_ELF_LARGE=${CMake_TEST_ELF_LARGE}

View File

@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.5)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@@ -0,0 +1,3 @@
^-- Result=Failed to create directory: [^
]*/Tests/RunCMake/file-MAKE_DIRECTORY/MAKE_DIRECTORY-Result-many-dirs-FAIL-build/file/directory0 Error: [^
]*$

View File

@@ -0,0 +1,9 @@
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/file" "")
file(MAKE_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/file/directory0"
"${CMAKE_CURRENT_BINARY_DIR}/file/directory1"
"${CMAKE_CURRENT_BINARY_DIR}/file/directory2"
RESULT resultVal
)
message(STATUS "Result=${resultVal}")

View File

@@ -0,0 +1,7 @@
file(MAKE_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/file/directory0"
"${CMAKE_CURRENT_BINARY_DIR}/file/directory1"
"${CMAKE_CURRENT_BINARY_DIR}/file/directory2"
RESULT resultVal
)
message(STATUS "Result=${resultVal}")

View File

@@ -0,0 +1,3 @@
^-- Result=Failed to create directory: [^
]*/Tests/RunCMake/file-MAKE_DIRECTORY/MAKE_DIRECTORY-Result-one-dir-FAIL-build/file/directory Error: [^
]*$

View File

@@ -0,0 +1,3 @@
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/file" "")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/file/directory" RESULT resultVal)
message(STATUS "Result=${resultVal}")

View File

@@ -0,0 +1,2 @@
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/file/directory" RESULT resultVal)
message(STATUS "Result=${resultVal}")

View File

@@ -0,0 +1,9 @@
^CMake Error at [^
]*/MAKE_DIRECTORY-one-dir-FAIL.cmake:[0-9]+ \(file\):
file failed to create directory:
[^
]*/Tests/RunCMake/file-MAKE_DIRECTORY/MAKE_DIRECTORY-one-dir-FAIL-build/file/directory
because: [^
]+$

View File

@@ -0,0 +1,7 @@
include(RunCMake)
run_cmake_script(MAKE_DIRECTORY-one-dir-FAIL)
run_cmake_script(MAKE_DIRECTORY-Result-one-dir-FAIL)
run_cmake_script(MAKE_DIRECTORY-Result-one-dir-SUCCESS)
run_cmake_script(MAKE_DIRECTORY-Result-many-dirs-FAIL)
run_cmake_script(MAKE_DIRECTORY-Result-many-dirs-SUCCESS)

View File

@@ -1,9 +0,0 @@
^CMake Error at [^
]*/MAKE_DIRECTORY-fail.cmake:[0-9]+ \(file\):
file failed to create directory:
[^
]*/Tests/RunCMake/file/MAKE_DIRECTORY-fail-build/file/directory
because: [^
]+$

View File

@@ -62,8 +62,6 @@ run_cmake_script(COPY_FILE-arg-unknown)
run_cmake_script(COPY_FILE-input-missing)
run_cmake_script(COPY_FILE-output-missing)
run_cmake_script(MAKE_DIRECTORY-fail)
run_cmake_script(RENAME-file-replace)
run_cmake_script(RENAME-file-to-file)
run_cmake_script(RENAME-file-to-dir-capture)