cmake -E copy_if_*: Add -t argument support

Issue: #24568
This commit is contained in:
Alex Reinking
2026-02-24 13:38:07 -05:00
committed by Brad King
parent 0807adfafe
commit 29dcbe4169
8 changed files with 71 additions and 70 deletions
+15 -7
View File
@@ -1222,7 +1222,7 @@ Available commands are:
Copy files to ``<destination>`` (either file or directory).
If multiple files are specified, or if ``-t`` is specified, the
``<destination>`` must be directory and it must exist. If ``-t`` is not
``<destination>`` must be a directory and it must exist. If ``-t`` is not
specified, the last argument is assumed to be the ``<destination>``.
Wildcards are not supported. ``copy`` does follow symlinks. That means it
does not copy symlinks, but the files or directories it point to.
@@ -1269,29 +1269,37 @@ Available commands are:
This is faster than ``copy_directory_if_different`` as it only compares
file timestamps instead of file contents.
.. option:: copy_if_different <file>... <destination>
.. option:: copy_if_different <file>... <destination>,
copy_if_different -t <destination> <file>...
Copy files to ``<destination>`` (either file or directory) if
they have changed.
If multiple files are specified, the ``<destination>`` must be
directory and it must exist.
If multiple files are specified, or if ``-t`` is specified,
the ``<destination>`` must be a directory and it must exist.
``copy_if_different`` does follow symlinks.
.. versionadded:: 3.5
Support for multiple input files.
.. option:: copy_if_newer <file>... <destination>
.. versionadded:: 4.4
Support for the ``-t`` argument.
.. option:: copy_if_newer <file>... <destination>,
copy_if_newer -t <destination> <file>...
.. versionadded:: 4.2
Copy files to ``<destination>`` (either file or directory) if
source files are newer than destination files (based on file timestamps).
If multiple files are specified, the ``<destination>`` must be
directory and it must exist.
If multiple files are specified, or if ``-t`` is specified,
the ``<destination>`` must be a directory and it must exist.
``copy_if_newer`` does follow symlinks.
This is faster than ``copy_if_different`` as it only compares
file timestamps instead of file contents.
.. versionadded:: 4.4
Support for the ``-t`` argument.
.. option:: create_symlink <old> <new>
Create a symbolic link ``<new>`` naming ``<old>``.
+7
View File
@@ -0,0 +1,7 @@
cmake-E-copy-t-flag
-------------------
* The :option:`cmake -E` commands
:option:`copy_if_different <cmake-E copy_if_different>` and
:option:`copy_if_newer <cmake-E copy_if_newer>`
gained support for the ``-t`` argument.
+33 -63
View File
@@ -105,13 +105,16 @@ char const* const HELP_AVAILABLE_COMMANDS = R"(Available commands:
cat [--] <files>... - concat the files and print them to the standard output
chdir dir cmd [args...] - run command in a given directory
compare_files [--ignore-eol] file1 file2
- check if file1 is same as file2
copy <file>... destination - copy files to destination (either file or directory)
- check if file1 is same as file2
copy <file>... destination | -t <destination> <file>...
- copy files to destination (either file or directory)
copy_directory <dir>... destination - copy content of <dir>... directories to 'destination' directory
copy_directory_if_different <dir>... destination - copy changed content of <dir>... directories to 'destination' directory
copy_directory_if_newer <dir>... destination - copy newer content of <dir>... directories to 'destination' directory
copy_if_different <file>... destination - copy files if it has changed
copy_if_newer <file>... destination - copy files if source is newer than destination
copy_if_different <file>... destination | -t <destination> <file>...
- copy files if source has changed
copy_if_newer <file>... destination | -t <destination> <file>...
- copy files if source is newer than destination
echo [<string>...] - displays arguments as text
echo_append [<string>...] - displays arguments as text but no new line
env [--unset=NAME ...] [NAME=VALUE ...] [--] <command> [<arg>...]
@@ -1002,8 +1005,26 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
{
// IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
if (args.size() > 1) {
// Copy file
if (args[1] == "copy" && args.size() > 3) {
// Copy file, copy file if different, copy file if newer.
if ((args[1] == "copy" || args[1] == "copy_if_different" ||
args[1] == "copy_if_newer") &&
args.size() > 3) {
using CopyFn = cmsys::SystemTools::CopyStatus (*)(std::string const&,
std::string const&);
CopyFn copyFn;
std::string copyErrPrefix;
if (args[1] == "copy") {
copyFn = cmSystemTools::CopyFileAlways;
copyErrPrefix = "Error copying file";
} else if (args[1] == "copy_if_different") {
copyFn = cmSystemTools::CopyFileIfDifferent;
copyErrPrefix = "Error copying file (if different) from";
} else {
copyFn = cmSystemTools::CopyFileIfNewer;
copyErrPrefix = "Error copying file (if newer) from";
}
std::string const& cmdName = args[1];
using CommandArgument =
cmCommandLineArgument<bool(std::string const& value)>;
@@ -1038,14 +1059,14 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
files.pop_back();
}
if (targetArg && (!cmSystemTools::FileIsDirectory(*targetArg))) {
std::cerr << "Error: Target (for copy command) \"" << *targetArg
<< "\" is not a directory.\n";
std::cerr << "Error: Target (for " << cmdName << " command) \""
<< *targetArg << "\" is not a directory.\n";
return 1;
}
if (!targetArg) {
if (files.size() < 2) {
std::cerr
<< "Error: No files or target specified (for copy command).\n";
std::cerr << "Error: No files or target specified (for " << cmdName
<< " command).\n";
return 1;
}
targetArg = files.back();
@@ -1054,10 +1075,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
// If error occurs we want to continue copying next files.
bool return_value = false;
for (auto const& file : files) {
cmsys::SystemTools::CopyStatus const status =
cmSystemTools::CopyFileAlways(file, *targetArg);
cmsys::SystemTools::CopyStatus const status = copyFn(file, *targetArg);
if (!status) {
std::cerr << "Error copying file \"" << file << "\" to \""
std::cerr << copyErrPrefix << " \"" << file << "\" to \""
<< *targetArg << "\": " << status.GetString() << '\n';
return_value = true;
}
@@ -1065,56 +1085,6 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
return return_value;
}
// Copy file if different.
if (args[1] == "copy_if_different" && args.size() > 3) {
// If multiple source files specified,
// then destination must be directory
if ((args.size() > 4) &&
(!cmSystemTools::FileIsDirectory(args.back()))) {
std::cerr << "Error: Target (for copy_if_different command) \""
<< args.back() << "\" is not a directory.\n";
return 1;
}
// If error occurs we want to continue copying next files.
bool return_value = false;
for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
cmsys::SystemTools::CopyStatus const status =
cmSystemTools::CopyFileIfDifferent(arg, args.back());
if (!status) {
std::cerr << "Error copying file (if different) from \"" << arg
<< "\" to \"" << args.back()
<< "\": " << status.GetString() << '\n';
return_value = true;
}
}
return return_value;
}
// Copy file if newer.
if (args[1] == "copy_if_newer" && args.size() > 3) {
// If multiple source files specified,
// then destination must be directory
if ((args.size() > 4) &&
(!cmSystemTools::FileIsDirectory(args.back()))) {
std::cerr << "Error: Target (for copy_if_newer command) \""
<< args.back() << "\" is not a directory.\n";
return 1;
}
// If error occurs we want to continue copying next files.
bool return_value = false;
for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
cmsys::SystemTools::CopyStatus const status =
cmSystemTools::CopyFileIfNewer(arg, args.back());
if (!status) {
std::cerr << "Error copying file (if newer) from \"" << arg
<< "\" to \"" << args.back()
<< "\": " << status.GetString() << '\n';
return_value = true;
}
}
return return_value;
}
// Copy directory contents
if ((args[1] == "copy_directory" ||
args[1] == "copy_directory_if_different" ||
@@ -0,0 +1 @@
^Error: Target \(for copy_if_different command\).* is not a directory\.$
@@ -0,0 +1 @@
^Error: Target \(for copy_if_newer command\).* is not a directory\.$
@@ -653,6 +653,12 @@ run_cmake_command(E_copy-t-argument-target-is-file
${CMAKE_COMMAND} -E copy ${in}/f1.txt -t ${out}/f1.txt ${in}/f3.txt)
run_cmake_command(E_copy-t-argument-no-source-files
${CMAKE_COMMAND} -E copy -t ${out})
run_cmake_command(E_copy_if_different-t-argument
${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt -t ${out} ${in}/f3.txt)
run_cmake_command(E_copy_if_different-t-argument-target-is-file
${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt -t ${out}/f1.txt ${in}/f3.txt)
run_cmake_command(E_copy_if_different-t-argument-no-source-files
${CMAKE_COMMAND} -E copy_if_different -t ${out})
run_cmake_command(E_copy_if_different-one-source-directory-target-is-directory
${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${out})
run_cmake_command(E_copy_if_different-three-source-files-target-is-directory
@@ -661,6 +667,12 @@ run_cmake_command(E_copy_if_different-three-source-files-target-is-file
${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${in}/f2.txt ${in}/f3.txt ${out}/f1.txt)
run_cmake_command(E_copy_if_different-nonexistent-source
${CMAKE_COMMAND} -E copy_if_different ${in}/nonexistent.txt ${out})
run_cmake_command(E_copy_if_newer-t-argument
${CMAKE_COMMAND} -E copy_if_newer ${in}/f1.txt -t ${out} ${in}/f3.txt)
run_cmake_command(E_copy_if_newer-t-argument-target-is-file
${CMAKE_COMMAND} -E copy_if_newer ${in}/f1.txt -t ${out}/f1.txt ${in}/f3.txt)
run_cmake_command(E_copy_if_newer-t-argument-no-source-files
${CMAKE_COMMAND} -E copy_if_newer -t ${out})
run_cmake_command(E_copy_if_newer-one-source-directory-target-is-directory
${CMAKE_COMMAND} -E copy_if_newer ${in}/f1.txt ${out})
run_cmake_command(E_copy_if_newer-three-source-files-target-is-directory