mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 05:40:54 -06:00
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
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
40
Help/policy/CMP0175.rst
Normal file
40
Help/policy/CMP0175.rst
Normal file
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
1
Tests/RunCMake/add_custom_command/CMP0175-NEW-result.txt
Normal file
1
Tests/RunCMake/add_custom_command/CMP0175-NEW-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
29
Tests/RunCMake/add_custom_command/CMP0175-NEW-stderr.txt
Normal file
29
Tests/RunCMake/add_custom_command/CMP0175-NEW-stderr.txt
Normal file
@@ -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\)
|
||||
2
Tests/RunCMake/add_custom_command/CMP0175-NEW.cmake
Normal file
2
Tests/RunCMake/add_custom_command/CMP0175-NEW.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
cmake_policy(SET CMP0175 NEW)
|
||||
include(CMP0175.cmake)
|
||||
2
Tests/RunCMake/add_custom_command/CMP0175-OLD.cmake
Normal file
2
Tests/RunCMake/add_custom_command/CMP0175-OLD.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
cmake_policy(SET CMP0175 OLD)
|
||||
include(CMP0175.cmake)
|
||||
72
Tests/RunCMake/add_custom_command/CMP0175-WARN-stderr.txt
Normal file
72
Tests/RunCMake/add_custom_command/CMP0175-WARN-stderr.txt
Normal file
@@ -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\.
|
||||
1
Tests/RunCMake/add_custom_command/CMP0175-WARN.cmake
Normal file
1
Tests/RunCMake/add_custom_command/CMP0175-WARN.cmake
Normal file
@@ -0,0 +1 @@
|
||||
include(CMP0175.cmake)
|
||||
65
Tests/RunCMake/add_custom_command/CMP0175.cmake
Normal file
65
Tests/RunCMake/add_custom_command/CMP0175.cmake
Normal file
@@ -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
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user