diff --git a/Help/command/file.rst b/Help/command/file.rst index ef49faa0a7..5b9dfac5a0 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst @@ -192,6 +192,10 @@ Writing With ``TOUCH`` and ``TOUCH_NOCREATE``, the contents of an existing file will not be modified. + .. versionchanged:: 3.30 + ```` can be an empty list. CMake 3.29 and earlier required + at least one file to be given. + .. signature:: file(GENERATE [...]) @@ -398,6 +402,10 @@ Filesystem Create the given directories and their parents as needed. + .. versionchanged:: 3.30 + ```` can be an empty list. CMake 3.29 and earlier required + at least one directory to be given. + .. signature:: file(REMOVE ...) file(REMOVE_RECURSE ...) diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 0369051f63..77f740b9ab 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -73,6 +73,11 @@ namespace { bool HandleWriteImpl(std::vector const& args, bool append, cmExecutionStatus& status) { + if (args.size() < 2) { + status.SetError(cmStrCat( + args[0], " must be called with at least one additional argument.")); + return false; + } auto i = args.begin(); i++; // Get rid of subcommand @@ -658,8 +663,11 @@ bool HandleStringsCommand(std::vector const& args, bool HandleGlobImpl(std::vector const& args, bool recurse, cmExecutionStatus& status) { - // File commands has at least one argument - assert(args.size() > 1); + if (args.size() < 2) { + status.SetError(cmStrCat( + args[0], " must be called with at least one additional argument.")); + return false; + } auto i = args.begin(); @@ -869,8 +877,8 @@ bool HandleGlobRecurseCommand(std::vector const& args, bool HandleMakeDirectoryCommand(std::vector const& args, cmExecutionStatus& status) { - // File command has at least one argument - assert(args.size() > 1); + // 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. std::string expr; for (std::string const& arg : @@ -903,8 +911,8 @@ bool HandleMakeDirectoryCommand(std::vector const& args, bool HandleTouchImpl(std::vector const& args, bool create, cmExecutionStatus& status) { - // File command has at least one argument - assert(args.size() > 1); + // Projects might pass a dynamically generated list of files, and it + // could be an empty list. We should not assume there is at least one. for (std::string const& arg : cmMakeRange(args).advance(1)) // Get rid of subcommand @@ -3918,8 +3926,9 @@ bool HandleChmodRecurseCommand(std::vector const& args, bool cmFileCommand(std::vector const& args, cmExecutionStatus& status) { - if (args.size() < 2) { - status.SetError("must be called with at least two arguments."); + if (args.empty()) { + status.SetError( + "given no arguments, but it requires at least a sub-command."); return false; } diff --git a/Tests/CMakeTests/FileTest.cmake.in b/Tests/CMakeTests/FileTest.cmake.in index 71cb3db864..7b76700d46 100644 --- a/Tests/CMakeTests/FileTest.cmake.in +++ b/Tests/CMakeTests/FileTest.cmake.in @@ -13,13 +13,13 @@ set(Copy-NoDest-STDERR "given no DESTINATION") set(Copy-NoFile-RESULT 1) set(Copy-NoFile-STDERR "COPY cannot find.*/does_not_exist\\.txt") set(Glob-NoArg-RESULT 1) -set(Glob-NoArg-STDERR "file must be called with at least two arguments") +set(Glob-NoArg-STDERR "file GLOB must be called with at least one additional argument\\.") set(Make_Directory-NoArg-RESULT 1) set(Make-Directory-NoArg-STDERR "file must be called with at least two arguments") set(MD5-NoFile-RESULT 1) set(MD5-NoFile-STDERR "file MD5 failed to read file") set(MD5-BadArg1-RESULT 1) -set(MD5-BadArg1-STDERR "file must be called with at least two arguments") +set(MD5-BadArg1-STDERR "file MD5 requires a file name and output variable") set(MD5-BadArg2-RESULT 1) set(MD5-BadArg2-STDERR "file MD5 requires a file name and output variable") set(MD5-BadArg4-RESULT 1) diff --git a/Tests/RunCMake/file/LOCK-error-no-path-stderr.txt b/Tests/RunCMake/file/LOCK-error-no-path-stderr.txt index 2247aa68e2..6d7001658b 100644 --- a/Tests/RunCMake/file/LOCK-error-no-path-stderr.txt +++ b/Tests/RunCMake/file/LOCK-error-no-path-stderr.txt @@ -1,4 +1,4 @@ CMake Error at LOCK-error-no-path.cmake:[0-9]+ \(file\): - file must be called with at least two arguments. + sub-command LOCK requires at least two arguments\. Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file/TOUCH-result.txt b/Tests/RunCMake/file/TOUCH-result.txt deleted file mode 100644 index d00491fd7e..0000000000 --- a/Tests/RunCMake/file/TOUCH-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/file/TOUCH-stderr.txt b/Tests/RunCMake/file/TOUCH-stderr.txt deleted file mode 100644 index 9f31676db2..0000000000 --- a/Tests/RunCMake/file/TOUCH-stderr.txt +++ /dev/null @@ -1,9 +0,0 @@ -^CMake Error at TOUCH\.cmake:[0-9]+ \(file\): - file must be called with at least two arguments\. -Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\) -+ -CMake Error at TOUCH\.cmake:[0-9]+ \(file\): - file must be called with at least two arguments\. -Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file/TOUCH.cmake b/Tests/RunCMake/file/TOUCH.cmake index 8931eb53a8..c92a9626e4 100644 --- a/Tests/RunCMake/file/TOUCH.cmake +++ b/Tests/RunCMake/file/TOUCH.cmake @@ -12,5 +12,6 @@ if(NOT EXISTS "${file}") endif() file(REMOVE "${file}") +# Empty arguments used to be an error, but this is valid since CMake 3.30 file(TOUCH) file(TOUCH_NOCREATE)