summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCraig Scott <craig.scott@crascit.com>2024-08-25 04:41:41 (GMT)
committerCraig Scott <craig.scott@crascit.com>2024-09-09 22:19:09 (GMT)
commitec519f3e975467443a8286b4ddc1904d964f851f (patch)
tree064d01a870e69a69f19c3fe2b5f7b33e3e69d9ca
parent8dc8be08849acb75446a53fe763eee5b3296d739 (diff)
downloadCMake-ec519f3e975467443a8286b4ddc1904d964f851f.zip
CMake-ec519f3e975467443a8286b4ddc1904d964f851f.tar.gz
CMake-ec519f3e975467443a8286b4ddc1904d964f851f.tar.bz2
add_custom_command: Validate arguments more rigorously
Add a new CMP0175 policy to preserve backward compatibility for projects that were using unsupported keywords or arguments. Fixes: #26096, #21089, #18976
-rw-r--r--Help/command/add_custom_command.rst69
-rw-r--r--Help/manual/cmake-policies.7.rst1
-rw-r--r--Help/policy/CMP0175.rst40
-rw-r--r--Source/cmAddCustomCommandCommand.cxx203
-rw-r--r--Source/cmPolicies.h2
-rw-r--r--Tests/RunCMake/add_custom_command/CMP0175-NEW-result.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/CMP0175-NEW-stderr.txt29
-rw-r--r--Tests/RunCMake/add_custom_command/CMP0175-NEW.cmake2
-rw-r--r--Tests/RunCMake/add_custom_command/CMP0175-OLD.cmake2
-rw-r--r--Tests/RunCMake/add_custom_command/CMP0175-WARN-stderr.txt72
-rw-r--r--Tests/RunCMake/add_custom_command/CMP0175-WARN.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/CMP0175.cmake65
-rw-r--r--Tests/RunCMake/add_custom_command/RunCMakeTest.cmake3
13 files changed, 481 insertions, 9 deletions
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index a69c8dc..122bb4e 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -5,6 +5,8 @@ Add a custom build rule to the generated build system.
There are two main signatures for ``add_custom_command``.
+.. _`add_custom_command(OUTPUT)`:
+
Generating Files
^^^^^^^^^^^^^^^^
@@ -54,7 +56,7 @@ The options are:
the appended commands and dependencies apply to all configurations.
The ``COMMENT``, ``MAIN_DEPENDENCY``, and ``WORKING_DIRECTORY``
- options are currently ignored when APPEND is given, but may be
+ options are currently ignored when ``APPEND`` is given, but may be
used in the future.
``BYPRODUCTS``
@@ -82,6 +84,10 @@ The options are:
The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
:prop_sf:`GENERATED` files during ``make clean``.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ All byproducts must be set in the first call to
+ ``add_custom_command(OUTPUT...)`` for the output files.
+
.. versionadded:: 3.20
Arguments to ``BYPRODUCTS`` may use a restricted set of
:manual:`generator expressions <cmake-generator-expressions(7)>`.
@@ -95,11 +101,15 @@ The options are:
``COMMAND``
Specify the command-line(s) to execute at build time.
- If more than one ``COMMAND`` is specified they will be executed in order,
+ At least one ``COMMAND`` would normally be given, but certain patterns
+ may omit it, such as adding commands in separate calls using `APPEND`.
+
+ If more than one ``COMMAND`` is specified, they will be executed in order,
but *not* necessarily composed into a stateful shell or batch script.
- (To run a full script, use the :command:`configure_file` command or the
+ To run a full script, use the :command:`configure_file` command or the
:command:`file(GENERATE)` command to create it, and then specify
- a ``COMMAND`` to launch it.)
+ a ``COMMAND`` to launch it.
+
The optional ``ARGS`` argument is for backward compatibility and
will be ignored.
@@ -144,7 +154,8 @@ The options are:
``COMMENT``
Display the given message before the commands are executed at
- build time.
+ build time. This will be ignored if ``APPEND`` is given, although a future
+ version may use it.
.. versionadded:: 3.26
Arguments to ``COMMENT`` may use
@@ -204,6 +215,10 @@ The options are:
``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc``
to be properly expanded.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ If the appended commands need this option to be set, it must be set on the
+ first call to ``add_custom_command(OUTPUT...)`` for the output files.
+
``CODEGEN``
.. versionadded:: 3.31
@@ -216,6 +231,10 @@ The options are:
Furthermore, this option is allowed only if policy :policy:`CMP0171`
is set to ``NEW``.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ It can only be set on the first call to ``add_custom_command(OUTPUT...)``
+ for the output files.
+
``IMPLICIT_DEPENDS``
Request scanning of implicit dependencies of an input file.
The language given specifies the programming language whose
@@ -240,6 +259,10 @@ The options are:
Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
an error by ninja at build time.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ Job pools can only be specified in the first call to
+ ``add_custom_command(OUTPUT...)`` for the output files.
+
``JOB_SERVER_AWARE``
.. versionadded:: 3.28
@@ -251,6 +274,10 @@ The options are:
This option is silently ignored by other generators.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ Job server awareness can only be specified in the first call to
+ ``add_custom_command(OUTPUT...)`` for the output files.
+
.. _`GNU Make Documentation`: https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html
``MAIN_DEPENDENCY``
@@ -262,6 +289,9 @@ The options are:
library or an executable) counts as an implicit main dependency which
gets silently overwritten by a custom command specification.
+ This option is currently ignored if ``APPEND`` is given, but a future
+ version may use it.
+
``OUTPUT``
Specify the output files the command is expected to produce.
Each output file will be marked with the :prop_sf:`GENERATED`
@@ -306,6 +336,10 @@ The options are:
With the :generator:`Ninja` generator, this places the command in
the ``console`` :prop_gbl:`pool <JOB_POOLS>`.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ If the appended commands need access to the terminal, it must be set on
+ the first call to ``add_custom_command(OUTPUT...)`` for the output files.
+
``VERBATIM``
All arguments to the commands will be escaped properly for the
build tool so that the invoked command receives each argument
@@ -316,11 +350,18 @@ The options are:
is platform specific because there is no protection of
tool-specific special characters.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ If the appended commands need to be treated as ``VERBATIM``, it must be set
+ on the first call to ``add_custom_command(OUTPUT...)`` for the output files.
+
``WORKING_DIRECTORY``
Execute the command with the given current working directory.
- If it is a relative path it will be interpreted relative to the
+ If it is a relative path, it will be interpreted relative to the
build tree directory corresponding to the current source directory.
+ This option is currently ignored if ``APPEND`` is given, but a future
+ version may use it.
+
.. versionadded:: 3.13
Arguments to ``WORKING_DIRECTORY`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.
@@ -406,6 +447,10 @@ The options are:
:ref:`Makefile Generators`, :ref:`Visual Studio Generators`,
and the :generator:`Xcode` generator.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ Depfiles can only be set on the first call to
+ ``add_custom_command(OUTPUT...)`` for the output files.
+
``DEPENDS_EXPLICIT_ONLY``
.. versionadded:: 3.27
@@ -421,6 +466,10 @@ The options are:
This option can be enabled on all custom commands by setting
:variable:`CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY` to ``ON``.
+ This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+ It can only be set on the first call to ``add_custom_command(OUTPUT...)``
+ for the output files.
+
Only the :ref:`Ninja Generators` actually use this information to remove
unnecessary implicit dependencies.
@@ -575,9 +624,11 @@ of the following is specified:
Run after all other rules within the target have been executed.
Projects should always specify one of the above three keywords when using
-the ``TARGET`` form. For backward compatibility reasons, ``POST_BUILD`` is
-assumed if no such keyword is given, but projects should explicitly provide
-one of the keywords to make clear the behavior they expect.
+the ``TARGET`` form. See policy :policy:`CMP0175`.
+
+All other keywords shown in the signature above have the same meaning as they
+do for the :command:`add_custom_command(OUTPUT)` form of the command.
+At least one ``COMMAND`` must be given, see policy :policy:`CMP0175`.
.. note::
Because generator expressions can be used in custom commands,
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index e257c36..e5284e9 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.31
.. toctree::
:maxdepth: 1
+ CMP0175: add_custom_command() rejects invalid arguments. </policy/CMP0175>
CMP0174: cmake_parse_arguments(PARSE_ARGV) defines a variable for an empty string after a single-value keyword. </policy/CMP0174>
CMP0173: The CMakeFindFrameworks module is removed. </policy/CMP0173>
CMP0172: The CPack module enables per-machine installation by default in the CPack WIX Generator. </policy/CMP0172>
diff --git a/Help/policy/CMP0175.rst b/Help/policy/CMP0175.rst
new file mode 100644
index 0000000..f2c372d
--- /dev/null
+++ b/Help/policy/CMP0175.rst
@@ -0,0 +1,40 @@
+CMP0175
+-------
+
+.. versionadded:: 3.31
+
+:command:`add_custom_command` rejects invalid arguments.
+
+CMake 3.30 and earlier silently ignored unsupported keywords and missing or
+invalid arguments for the different forms of the :command:`add_custom_command`
+command. CMake 3.31 implements more rigorous argument checking and will flag
+invalid or missing arguments as errors.
+
+The ``OLD`` behavior of this policy will accept the same invalid keywords or
+arguments as CMake 3.30 and earlier. The ``NEW`` behavior will flag the
+following as errors that previously went unreported:
+
+* The ``OUTPUT`` form does not accept ``PRE_BUILD``, ``PRE_LINK``, or
+ ``POST_BUILD`` keywords.
+* When the ``APPEND`` keyword is given, the ``OUTPUT`` form also does not
+ accept ``BYPRODUCTS``, ``COMMAND_EXPAND_LISTS``, ``DEPENDS_EXPLICIT_ONLY``,
+ ``DEPFILE``, ``JOB_POOL``, ``JOB_SERVER_AWARE``, ``USES_TERMINAL``, or
+ ``VERBATIM`` keywords.
+* The ``TARGET`` form requires exactly one of ``PRE_BUILD``, ``PRE_LINK``, or
+ ``POST_BUILD`` to be given. Previously, if none were given, ``POST_BUILD``
+ was assumed, or if multiple keywords were given, the last one was used.
+* The ``TARGET`` form does not accept ``DEPENDS``, ``DEPENDS_EXPLICIT_ONLY``,
+ ``DEPFILE``, ``IMPLICIT_DEPENDS``, ``MAIN_DEPENDENCY``, ``JOB_POOL``,
+ ``JOB_SERVER_AWARE``, or ``USES_TERMINAL`` keywords.
+* The ``TARGET`` form now requires at least one ``COMMAND`` to be given.
+* If a keyword expects a value to be given after it, but no value is provided,
+ that was previously treated as though the keyword was not given at all.
+* The ``COMMENT`` keyword expects exactly one value after it. If multiple
+ values are given, or if the ``COMMENT`` keyword is given more than once,
+ this is an error.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.31
+.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
+.. include:: STANDARD_ADVICE.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index d5adba7..885094d 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -2,11 +2,15 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmAddCustomCommandCommand.h"
+#include <algorithm>
+#include <iterator>
+#include <set>
#include <sstream>
#include <unordered_set>
#include <utility>
#include <cm/memory>
+#include <cmext/string_view>
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
@@ -140,11 +144,82 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
keyDEPENDS_EXPLICIT_ONLY,
keyCODEGEN
};
+ /* clang-format off */
+ static std::set<std::string> const supportedTargetKeywords{
+ keyARGS,
+ keyBYPRODUCTS,
+ keyCOMMAND,
+ keyCOMMAND_EXPAND_LISTS,
+ keyCOMMENT,
+ keyPOST_BUILD,
+ keyPRE_BUILD,
+ keyPRE_LINK,
+ keyTARGET,
+ keyVERBATIM,
+ keyWORKING_DIRECTORY
+ };
+ /* clang-format on */
+ static std::set<std::string> const supportedOutputKeywords{
+ keyAPPEND,
+ keyARGS,
+ keyBYPRODUCTS,
+ keyCODEGEN,
+ keyCOMMAND,
+ keyCOMMAND_EXPAND_LISTS,
+ keyCOMMENT,
+ keyDEPENDS,
+ keyDEPENDS_EXPLICIT_ONLY,
+ keyDEPFILE,
+ keyIMPLICIT_DEPENDS,
+ keyJOB_POOL,
+ keyJOB_SERVER_AWARE,
+ keyMAIN_DEPENDENCY,
+ keyOUTPUT,
+ keyUSES_TERMINAL,
+ keyVERBATIM,
+ keyWORKING_DIRECTORY
+ };
+ /* clang-format off */
+ static std::set<std::string> const supportedAppendKeywords{
+ keyAPPEND,
+ keyARGS,
+ keyCOMMAND,
+ keyCOMMENT, // Allowed but ignored
+ keyDEPENDS,
+ keyIMPLICIT_DEPENDS,
+ keyMAIN_DEPENDENCY, // Allowed but ignored
+ keyOUTPUT,
+ keyWORKING_DIRECTORY // Allowed but ignored
+ };
+ /* clang-format on */
+ std::set<std::string> keywordsSeen;
+ std::string const* keywordExpectingValue = nullptr;
+ auto const cmp0175 = mf.GetPolicyStatus(cmPolicies::CMP0175);
for (std::string const& copy : args) {
if (keywords.count(copy)) {
+ // Check if a preceding keyword expected a value but there wasn't one
+ if (keywordExpectingValue) {
+ std::string const msg =
+ cmStrCat("Keyword ", *keywordExpectingValue,
+ " requires a value, but none was given.");
+ if (cmp0175 == cmPolicies::NEW) {
+ mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+ if (cmp0175 == cmPolicies::WARN) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(msg, '\n',
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
+ }
+ }
+ keywordExpectingValue = nullptr;
+ keywordsSeen.insert(copy);
+
if (copy == keySOURCE) {
doing = doing_source;
+ keywordExpectingValue = &keySOURCE;
} else if (copy == keyCOMMAND) {
doing = doing_command;
@@ -173,6 +248,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
codegen = true;
} else if (copy == keyTARGET) {
doing = doing_target;
+ keywordExpectingValue = &keyTARGET;
} else if (copy == keyARGS) {
// Ignore this old keyword.
} else if (copy == keyDEPENDS) {
@@ -181,16 +257,20 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
doing = doing_outputs;
} else if (copy == keyOUTPUT) {
doing = doing_output;
+ keywordExpectingValue = &keyOUTPUT;
} else if (copy == keyBYPRODUCTS) {
doing = doing_byproducts;
} else if (copy == keyWORKING_DIRECTORY) {
doing = doing_working_directory;
+ keywordExpectingValue = &keyWORKING_DIRECTORY;
} else if (copy == keyMAIN_DEPENDENCY) {
doing = doing_main_dependency;
+ keywordExpectingValue = &keyMAIN_DEPENDENCY;
} else if (copy == keyIMPLICIT_DEPENDS) {
doing = doing_implicit_depends_lang;
} else if (copy == keyCOMMENT) {
doing = doing_comment;
+ keywordExpectingValue = &keyCOMMENT;
} else if (copy == keyDEPFILE) {
doing = doing_depfile;
if (!mf.GetGlobalGenerator()->SupportsCustomCommandDepfile()) {
@@ -198,12 +278,16 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
mf.GetGlobalGenerator()->GetName()));
return false;
}
+ keywordExpectingValue = &keyDEPFILE;
} else if (copy == keyJOB_POOL) {
doing = doing_job_pool;
+ keywordExpectingValue = &keyJOB_POOL;
} else if (copy == keyJOB_SERVER_AWARE) {
doing = doing_job_server_aware;
+ keywordExpectingValue = &keyJOB_SERVER_AWARE;
}
} else {
+ keywordExpectingValue = nullptr; // Value is being processed now
std::string filename;
switch (doing) {
case doing_output:
@@ -288,6 +372,21 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
byproducts.push_back(filename);
break;
case doing_comment:
+ if (!comment_buffer.empty()) {
+ std::string const msg =
+ "COMMENT requires exactly one argument, but multiple values "
+ "or COMMENT keywords have been given.";
+ if (cmp0175 == cmPolicies::NEW) {
+ mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+ if (cmp0175 == cmPolicies::WARN) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(msg, '\n',
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
+ }
+ }
comment_buffer = copy;
comment = comment_buffer.c_str();
break;
@@ -351,6 +450,27 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
// Check for an append request.
if (append) {
+ std::vector<std::string> unsupportedKeywordsUsed;
+ std::set_difference(keywordsSeen.begin(), keywordsSeen.end(),
+ supportedAppendKeywords.begin(),
+ supportedAppendKeywords.end(),
+ std::back_inserter(unsupportedKeywordsUsed));
+ if (!unsupportedKeywordsUsed.empty()) {
+ std::string const msg =
+ cmJoin(unsupportedKeywordsUsed, ", "_s,
+ "The following keywords are not supported when using "
+ "APPEND with add_custom_command(OUTPUT): "_s);
+ if (cmp0175 == cmPolicies::NEW) {
+ mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+ if (cmp0175 == cmPolicies::WARN) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(msg, ".\n",
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
+ }
+ }
mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,
commandLines);
return true;
@@ -376,9 +496,92 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
cc->SetDependsExplicitOnly(depends_explicit_only);
if (source.empty() && output.empty()) {
// Source is empty, use the target.
+ if (commandLines.empty()) {
+ std::string const msg = "At least one COMMAND must be given.";
+ if (cmp0175 == cmPolicies::NEW) {
+ mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+ if (cmp0175 == cmPolicies::WARN) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(msg, '\n',
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
+ }
+ }
+
+ std::vector<std::string> unsupportedKeywordsUsed;
+ std::set_difference(keywordsSeen.begin(), keywordsSeen.end(),
+ supportedTargetKeywords.begin(),
+ supportedTargetKeywords.end(),
+ std::back_inserter(unsupportedKeywordsUsed));
+ if (!unsupportedKeywordsUsed.empty()) {
+ std::string const msg =
+ cmJoin(unsupportedKeywordsUsed, ", "_s,
+ "The following keywords are not supported when using "
+ "add_custom_command(TARGET): "_s);
+ if (cmp0175 == cmPolicies::NEW) {
+ mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+ if (cmp0175 == cmPolicies::WARN) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(msg, ".\n",
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
+ }
+ }
+ auto const prePostCount = keywordsSeen.count(keyPRE_BUILD) +
+ keywordsSeen.count(keyPRE_LINK) + keywordsSeen.count(keyPOST_BUILD);
+ if (prePostCount != 1) {
+ std::string msg =
+ "Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given.";
+ if (cmp0175 == cmPolicies::NEW) {
+ mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+ if (cmp0175 == cmPolicies::WARN) {
+ msg += " Assuming ";
+ switch (cctype) {
+ case cmCustomCommandType::PRE_BUILD:
+ msg += "PRE_BUILD";
+ break;
+ case cmCustomCommandType::PRE_LINK:
+ msg += "PRE_LINK";
+ break;
+ case cmCustomCommandType::POST_BUILD:
+ msg += "POST_BUILD";
+ }
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(msg, " to preserve backward compatibility.\n",
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
+ }
+ }
mf.AddCustomCommandToTarget(target, cctype, std::move(cc));
} else if (target.empty()) {
// Target is empty, use the output.
+ std::vector<std::string> unsupportedKeywordsUsed;
+ std::set_difference(keywordsSeen.begin(), keywordsSeen.end(),
+ supportedOutputKeywords.begin(),
+ supportedOutputKeywords.end(),
+ std::back_inserter(unsupportedKeywordsUsed));
+ if (!unsupportedKeywordsUsed.empty()) {
+ std::string const msg =
+ cmJoin(unsupportedKeywordsUsed, ", "_s,
+ "The following keywords are not supported when using "
+ "add_custom_command(OUTPUT): "_s);
+ if (cmp0175 == cmPolicies::NEW) {
+ mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+ if (cmp0175 == cmPolicies::WARN) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(msg, ".\n",
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0175)));
+ }
+ }
cc->SetOutputs(output);
cc->SetMainDependency(main_dependency);
cc->SetDepends(depends);
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 7b056ae..644cb9e 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -537,6 +537,8 @@ class cmMakefile;
SELECT(POLICY, CMP0174, \
"cmake_parse_arguments(PARSE_ARGV) defines a variable for an empty " \
"string after a single-value keyword.", \
+ 3, 31, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0175, "add_custom_command() rejects invalid arguments.", \
3, 31, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
diff --git a/Tests/RunCMake/add_custom_command/CMP0175-NEW-result.txt b/Tests/RunCMake/add_custom_command/CMP0175-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CMP0175-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/add_custom_command/CMP0175-NEW-stderr.txt b/Tests/RunCMake/add_custom_command/CMP0175-NEW-stderr.txt
new file mode 100644
index 0000000..c356971
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CMP0175-NEW-stderr.txt
@@ -0,0 +1,29 @@
+CMake Error at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ The following keywords are not supported when using
+ add_custom_command\(TARGET\): DEPENDS, DEPENDS_EXPLICIT_ONLY, DEPFILE,
+ JOB_POOL, MAIN_DEPENDENCY
+Call Stack \(most recent call first\):
+ CMP0175-NEW\.cmake:2 \(include\)
+ CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ The following keywords are not supported when using
+ add_custom_command\(TARGET\): IMPLICIT_DEPENDS, USES_TERMINAL
+Call Stack \(most recent call first\):
+ CMP0175-NEW\.cmake:2 \(include\)
+ CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given\.
+Call Stack \(most recent call first\):
+ CMP0175-NEW\.cmake:2 \(include\)
+ CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given\.
+Call Stack \(most recent call first\):
+ CMP0175-NEW\.cmake:2 \(include\)
+ CMakeLists\.txt:3 \(include\)
diff --git a/Tests/RunCMake/add_custom_command/CMP0175-NEW.cmake b/Tests/RunCMake/add_custom_command/CMP0175-NEW.cmake
new file mode 100644
index 0000000..d8cb4fb
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CMP0175-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0175 NEW)
+include(CMP0175.cmake)
diff --git a/Tests/RunCMake/add_custom_command/CMP0175-OLD.cmake b/Tests/RunCMake/add_custom_command/CMP0175-OLD.cmake
new file mode 100644
index 0000000..a66c02d
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CMP0175-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0175 OLD)
+include(CMP0175.cmake)
diff --git a/Tests/RunCMake/add_custom_command/CMP0175-WARN-stderr.txt b/Tests/RunCMake/add_custom_command/CMP0175-WARN-stderr.txt
new file mode 100644
index 0000000..f49dd73
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CMP0175-WARN-stderr.txt
@@ -0,0 +1,72 @@
+CMake Warning \(dev\) at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ The following keywords are not supported when using
+ add_custom_command\(TARGET\): DEPENDS, DEPENDS_EXPLICIT_ONLY, DEPFILE,
+ JOB_POOL, MAIN_DEPENDENCY\.
+
+ Policy CMP0175 is not set: add_custom_command\(\) rejects invalid arguments\.
+ Run "cmake --help-policy CMP0175" for policy details\. Use the cmake_policy
+ command to set the policy and suppress this warning\.
+Call Stack \(most recent call first\):
+ CMP0175-WARN\.cmake:1 \(include\)
+ CMakeLists.txt:3 \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Warning \(dev\) at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ The following keywords are not supported when using
+ add_custom_command\(TARGET\): IMPLICIT_DEPENDS, USES_TERMINAL\.
+
+ Policy CMP0175 is not set: add_custom_command\(\) rejects invalid arguments\.
+ Run "cmake --help-policy CMP0175" for policy details\. Use the cmake_policy
+ command to set the policy and suppress this warning\.
+Call Stack \(most recent call first\):
+ CMP0175-WARN\.cmake:1 \(include\)
+ CMakeLists\.txt:3 \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Warning \(dev\) at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given\. Assuming
+ POST_BUILD to preserve backward compatibility\.
+
+ Policy CMP0175 is not set: add_custom_command\(\) rejects invalid arguments\.
+ Run "cmake --help-policy CMP0175" for policy details\. Use the cmake_policy
+ command to set the policy and suppress this warning\.
+Call Stack \(most recent call first\):
+ CMP0175-WARN\.cmake:1 \(include\)
+ CMakeLists\.txt:3 \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Warning \(dev\) at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given\. Assuming
+ POST_BUILD to preserve backward compatibility\.
+
+ Policy CMP0175 is not set: add_custom_command\(\) rejects invalid arguments\.
+ Run "cmake --help-policy CMP0175" for policy details\. Use the cmake_policy
+ command to set the policy and suppress this warning\.
+Call Stack \(most recent call first\):
+ CMP0175-WARN\.cmake:1 \(include\)
+ CMakeLists\.txt:3 \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Warning \(dev\) at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ At least one COMMAND must be given\.
+
+ Policy CMP0175 is not set: add_custom_command\(\) rejects invalid arguments\.
+ Run "cmake --help-policy CMP0175" for policy details\. Use the cmake_policy
+ command to set the policy and suppress this warning\.
+Call Stack \(most recent call first\):
+ CMP0175-WARN\.cmake:1 \(include\)
+ CMakeLists\.txt:3 \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Warning \(dev\) at CMP0175\.cmake:[0-9]+ \(add_custom_command\):
+ The following keywords are not supported when using
+ add_custom_command\(OUTPUT\): OUTPUTS, POST_BUILD, PRE_BUILD, PRE_LINK,
+ SOURCE\.
+
+ Policy CMP0175 is not set: add_custom_command\(\) rejects invalid arguments\.
+ Run "cmake --help-policy CMP0175" for policy details\. Use the cmake_policy
+ command to set the policy and suppress this warning\.
+Call Stack \(most recent call first\):
+ CMP0175-WARN\.cmake:1 \(include\)
+ CMakeLists\.txt:3 \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/add_custom_command/CMP0175-WARN.cmake b/Tests/RunCMake/add_custom_command/CMP0175-WARN.cmake
new file mode 100644
index 0000000..cd89b53
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CMP0175-WARN.cmake
@@ -0,0 +1 @@
+include(CMP0175.cmake)
diff --git a/Tests/RunCMake/add_custom_command/CMP0175.cmake b/Tests/RunCMake/add_custom_command/CMP0175.cmake
new file mode 100644
index 0000000..0c20f4e
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CMP0175.cmake
@@ -0,0 +1,65 @@
+enable_language(CXX)
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp "int main() {}")
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)
+
+#============================================================================
+# add_custom_command(TARGET)
+#============================================================================
+
+# Unsupported keywords. Need to test them in batches to avoid other checks.
+add_custom_command(TARGET main
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E true
+
+ # None of the following are allowed for the TARGET form
+
+ #APPEND # Has its own check requiring OUTPUT to be set
+ #CODEGEN # Other checks will fail before the CMP0175 check
+ DEPENDS valueDoesNotMatterHere
+ DEPENDS_EXPLICIT_ONLY YES
+ DEPFILE valueDoesNotMatterHere
+ #IMPLICIT_DEPENDS # Earlier check fails when DEPFILE is present
+ JOB_POOL valueDoesNotMatterHere
+ MAIN_DEPENDENCY valueDoesNotMatterHere
+ #OUTPUT # Other checks will fail before the CMP0175 check
+ #OUTPUTS # Special case, not a documented keyword (used for deprecated form)
+ #SOURCE # Old signature, special handling makes it hard to check
+ #USES_TERMINAL
+)
+add_custom_command(TARGET main
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E true
+ # Has to be tested separately due to separate check for clash with DEPFILE
+ IMPLICIT_DEPENDS valueDoesNotMatterHere
+ # Has to be tested separately due to separate check for clash with JOB_POOL
+ USES_TERMINAL NO
+)
+
+# Missing any PRE_BUILD, PRE_LINK, or POST_BUILD
+add_custom_command(TARGET main
+ COMMAND ${CMAKE_COMMAND} -E true
+)
+
+# More than one of PRE_BUILD, PRE_LINK, or POST_BUILD
+add_custom_command(TARGET main
+ PRE_BUILD PRE_LINK POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E true
+)
+
+# Missing COMMAND
+add_custom_command(TARGET main
+ POST_BUILD
+ COMMENT "Need at least 4 arguments, so added this comment"
+)
+
+#============================================================================
+# add_custom_command(OUTPUT)
+#============================================================================
+
+add_custom_command(OUTPUT blah.txt
+ OUTPUTS
+ POST_BUILD
+ PRE_BUILD
+ PRE_LINK
+ SOURCE
+)
diff --git a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake
index 46e7bae..820591c 100644
--- a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake
+++ b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake
@@ -1,5 +1,8 @@
include(RunCMake)
+run_cmake(CMP0175-OLD)
+run_cmake(CMP0175-WARN)
+run_cmake(CMP0175-NEW)
run_cmake(AppendLiteralQuotes)
run_cmake(AppendNoOutput)
run_cmake(AppendNotOutput)