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

add_custom_{command,target}: Add genex support to OUTPUT and BYPRODUCTS

Move rejection of `#`, `<`, and `>` characters in outputs and byproducts
to a generate-time check.  This removes the front-end check that
disallowed generator expressions.  The generators have already been
updated to handle them.

Fixes: #12877
This commit is contained in:
Brad King
2020-10-19 15:20:53 -04:00
parent f36af9228b
commit c257c25419
27 changed files with 367 additions and 107 deletions

View File

@@ -46,6 +46,12 @@ The options are:
Append the ``COMMAND`` and ``DEPENDS`` option values to the custom
command for the first output specified. There must have already
been a previous call to this command with the same output.
If the previous call specified the output via a generator expression,
the output specified by the current call must match in at least one
configuration after evaluating generator expressions. In this case,
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
used in the future.
@@ -73,6 +79,9 @@ The options are:
The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
:prop_sf:`GENERATED` files during ``make clean``.
Since CMake 3.20, arguments to ``BYPRODUCTS`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.
``COMMAND``
Specify the command-line(s) to execute at build time.
If more than one ``COMMAND`` is specified they will be executed in order,
@@ -220,6 +229,9 @@ The options are:
as a file on disk it should be marked with the :prop_sf:`SYMBOLIC`
source file property.
Since CMake 3.20, arguments to ``OUTPUT`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.
``USES_TERMINAL``
.. versionadded:: 3.2
@@ -279,6 +291,24 @@ adds a custom command to run ``someTool`` to generate ``out.c`` and then
compile the generated source as part of a library. The generation rule
will re-run whenever ``in.txt`` changes.
Since CMake 3.20, one may use generator expressions to specify
per-configuration outputs. For example, the code:
.. code-block:: cmake
add_custom_command(
OUTPUT "out-$<CONFIG>.c"
COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
-o "out-$<CONFIG>.c"
-c "$<CONFIG>"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
VERBATIM)
add_library(myLib "out-$<CONFIG>.c")
adds a custom command to run ``someTool`` to generate ``out-<config>.c``,
where ``<config>`` is the build configuration, and then compile the generated
source as part of a library.
Build Events
^^^^^^^^^^^^
@@ -346,3 +376,21 @@ For example, the code:
will run ``someHasher`` to produce a ``.hash`` file next to the executable
after linking.
Since CMake 3.20, one may use generator expressions to specify
per-configuration byproducts. For example, the code:
.. code-block:: cmake
add_library(myPlugin MODULE myPlugin.c)
add_custom_command(
TARGET myPlugin POST_BUILD
COMMAND someHasher -i "$<TARGET_FILE:myPlugin>"
--as-code "myPlugin-hash-$<CONFIG>.c"
BYPRODUCTS "myPlugin-hash-$<CONFIG>.c"
VERBATIM)
add_executable(myExe myExe.c "myPlugin-hash-$<CONFIG>.c")
will run ``someHasher`` after linking ``myPlugin``, e.g. to produce a ``.c``
file containing code to check the hash of ``myPlugin`` that the ``myExe``
executable can use to verify it before loading.

View File

@@ -54,6 +54,9 @@ The options are:
The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
:prop_sf:`GENERATED` files during ``make clean``.
Since CMake 3.20, arguments to ``BYPRODUCTS`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.
``COMMAND``
Specify the command-line(s) to execute at build time.
If more than one ``COMMAND`` is specified they will be executed in order,

View File

@@ -0,0 +1,6 @@
custom-command-output-genex
---------------------------
* :command:`add_custom_command` and :command:`add_custom_target` now
support :manual:`generator expressions <cmake-generator-expressions(7)>`
in their ``OUTPUT`` and ``BYPRODUCTS`` options.

View File

@@ -181,8 +181,6 @@ set(SRCS
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
cmCacheManager.cxx
cmCacheManager.h
cmCheckCustomOutputs.h
cmCheckCustomOutputs.cxx
cmCLocaleEnvironmentScope.h
cmCLocaleEnvironmentScope.cxx
cmCMakePath.h

View File

@@ -5,7 +5,6 @@
#include <sstream>
#include <unordered_set>
#include "cmCheckCustomOutputs.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmCustomCommandTypes.h"
@@ -298,13 +297,6 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
return false;
}
// Make sure the output names and locations are safe.
if (!cmCheckCustomOutputs(output, "OUTPUT", status) ||
!cmCheckCustomOutputs(outputs, "OUTPUTS", status) ||
!cmCheckCustomOutputs(byproducts, "BYPRODUCTS", status)) {
return false;
}
// Check for an append request.
if (append) {
mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,

View File

@@ -4,7 +4,6 @@
#include <utility>
#include "cmCheckCustomOutputs.h"
#include "cmCustomCommandLines.h"
#include "cmExecutionStatus.h"
#include "cmGeneratorExpression.h"
@@ -210,11 +209,6 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args,
return false;
}
// Make sure the byproduct names and locations are safe.
if (!cmCheckCustomOutputs(byproducts, "BYPRODUCTS", status)) {
return false;
}
// Add the utility target to the makefile.
bool escapeOldStyle = !verbatim;
cmTarget* target = mf.AddUtilityCommand(

View File

@@ -1,36 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCheckCustomOutputs.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
bool cmCheckCustomOutputs(const std::vector<std::string>& outputs,
cm::string_view keyword, cmExecutionStatus& status)
{
cmMakefile& mf = status.GetMakefile();
for (std::string const& o : outputs) {
// Make sure the file will not be generated into the source
// directory during an out of source build.
if (!mf.CanIWriteThisFile(o)) {
status.SetError(
cmStrCat("attempted to have a file\n ", o,
"\nin a source directory as an output of custom command."));
cmSystemTools::SetFatalErrorOccured();
return false;
}
// Make sure the output file name has no invalid characters.
std::string::size_type pos = o.find_first_of("#<>");
if (pos != std::string::npos) {
status.SetError(cmStrCat("called with ", keyword, " containing a \"",
o[pos], "\". This character is not allowed."));
return false;
}
}
return true;
}

View File

@@ -1,15 +0,0 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <string>
#include <vector>
#include <cm/string_view>
class cmExecutionStatus;
bool cmCheckCustomOutputs(const std::vector<std::string>& outputs,
cm::string_view keyword, cmExecutionStatus& status);

View File

@@ -17,6 +17,7 @@
#include <cm/memory>
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -3813,7 +3814,14 @@ void cmLocalGenerator::GenerateFrameworkInfoPList(
}
namespace {
cm::string_view CustomOutputRoleKeyword(cmLocalGenerator::OutputRole role)
{
return (role == cmLocalGenerator::OutputRole::Primary ? "OUTPUT"_s
: "BYPRODUCTS"_s);
}
void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output,
cmLocalGenerator::OutputRole role,
cmCommandOrigin origin,
const cmListFileBacktrace& lfbt)
{
@@ -3825,6 +3833,28 @@ void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output,
return;
}
// Make sure the file will not be generated into the source
// directory during an out of source build.
if (!lg.GetMakefile()->CanIWriteThisFile(output)) {
lg.GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(CustomOutputRoleKeyword(role), " path\n ", output,
"\nin a source directory as an output of custom command."),
lfbt);
return;
}
// Make sure the output file name has no invalid characters.
std::string::size_type pos = output.find_first_of("#<>");
if (pos != std::string::npos) {
lg.GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(CustomOutputRoleKeyword(role), " containing a \"", output[pos],
"\" is not allowed."),
lfbt);
return;
}
// Outputs without generator expressions from the project are already
// created and marked as generated. Do not mark them again, because
// other commands might have overwritten the property.
@@ -4283,7 +4313,7 @@ void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct,
auto pr = this->OutputToSource.emplace(byproduct, entry);
if (pr.second) {
CreateGeneratedSource(*this, byproduct, origin, bt);
CreateGeneratedSource(*this, byproduct, OutputRole::Byproduct, origin, bt);
} else {
SourceEntry& current = pr.first->second;
// Has the target already been set?
@@ -4311,7 +4341,7 @@ void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output,
auto pr = this->OutputToSource.emplace(output, entry);
if (pr.second) {
CreateGeneratedSource(*this, output, origin, bt);
CreateGeneratedSource(*this, output, role, origin, bt);
} else {
SourceEntry& current = pr.first->second;
// Outputs take precedence over byproducts

View File

@@ -16,6 +16,72 @@ void config_$<CONFIG>() {}
]]
)
# Custom command outputs named with the configuration(s).
add_custom_command(
OUTPUT "custom1_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom1.cpp.in" "custom1_$<CONFIG>.cpp"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom1.cpp.in
VERBATIM
)
# Output path starts in a generator expression.
add_custom_command(
OUTPUT "$<1:custom2_$<CONFIG>.cpp>"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom2.cpp.in" "custom2_$<CONFIG>.cpp"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom2.cpp.in
VERBATIM
)
# Source file generated as a custom command's byproduct.
add_custom_command(
OUTPUT custom3.txt
BYPRODUCTS "$<1:custom3_$<CONFIG>.cpp>"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom3.cpp.in" "custom3_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E touch custom3.txt
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom3.cpp.in
VERBATIM
)
# Source file generated as a custom target's byproduct.
add_custom_target(custom4
BYPRODUCTS "custom4_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/custom4.cpp.in" "custom4_$<CONFIG>.cpp"
VERBATIM
)
# Source file generated by appended custom command.
add_custom_command(
OUTPUT "custom5_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E echo custom5_$<CONFIG>.cpp
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom5.cpp.in
VERBATIM
)
add_custom_command(APPEND
OUTPUT "custom5_$<CONFIG>.cpp"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom5.cpp.in" "custom5_$<CONFIG>.cpp.in"
VERBATIM
)
# Appending through any configuration's output affects all configurations.
if(CMAKE_CONFIGURATION_TYPES MATCHES ";([^;]+)$")
set(last_config "${CMAKE_MATCH_1}")
else()
set(last_config ${CMAKE_BUILD_TYPE})
endif()
add_custom_command(APPEND
OUTPUT "custom5_${last_config}.cpp"
COMMAND ${CMAKE_COMMAND} -E copy "custom5_$<CONFIG>.cpp.in" "custom5_$<CONFIG>.cpp"
VERBATIM
)
foreach(n RANGE 1 5)
set_property(SOURCE custom${n}_Debug.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_DEBUG)
foreach(other Release RelWithDebInfo MinSizeRel)
set_property(SOURCE custom${n}_${other}.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_OTHER)
endforeach()
endforeach()
add_library(Custom STATIC
custom1_$<CONFIG>.cpp
custom2_$<CONFIG>.cpp
custom3_$<CONFIG>.cpp custom3.txt
custom4_$<CONFIG>.cpp
custom5_$<CONFIG>.cpp
)
# Per-config sources via INTERFACE_SOURCES.
add_library(iface INTERFACE)
target_sources(iface INTERFACE
@@ -34,7 +100,7 @@ add_executable(ConfigSources
$<$<CONFIG:NotAConfig>:does_not_exist.cpp>
${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp
)
target_link_libraries(ConfigSources iface)
target_link_libraries(ConfigSources Custom iface)
# Per-config sources via LINK_LIBRARIES.
add_library(iface_debug INTERFACE)
@@ -53,6 +119,7 @@ target_compile_definitions(ConfigSourcesLink PRIVATE
"$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
)
target_link_libraries(ConfigSourcesLink PRIVATE
Custom
"$<$<CONFIG:Debug>:iface_debug>"
"$<$<NOT:$<CONFIG:Debug>>:iface_other>"
"$<$<CONFIG:NotAConfig>:iface_does_not_exist>"
@@ -70,7 +137,7 @@ target_compile_definitions(ConfigSourcesLinkIface PRIVATE
"$<$<CONFIG:Debug>:CFG_DEBUG>"
"$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
)
target_link_libraries(ConfigSourcesLinkIface ConfigSourcesIface)
target_link_libraries(ConfigSourcesLinkIface Custom ConfigSourcesIface)
# A target with sources in only one configuration that is not the
# first in CMAKE_CONFIGURATION_TYPES.

View File

@@ -0,0 +1,13 @@
#ifdef CUSTOM_CFG_DEBUG
int custom1_debug()
{
return 0;
}
#endif
#ifdef CUSTOM_CFG_OTHER
int custom1_other()
{
return 0;
}
#endif

View File

@@ -0,0 +1,13 @@
#ifdef CUSTOM_CFG_DEBUG
int custom2_debug()
{
return 0;
}
#endif
#ifdef CUSTOM_CFG_OTHER
int custom2_other()
{
return 0;
}
#endif

View File

@@ -0,0 +1,13 @@
#ifdef CUSTOM_CFG_DEBUG
int custom3_debug()
{
return 0;
}
#endif
#ifdef CUSTOM_CFG_OTHER
int custom3_other()
{
return 0;
}
#endif

View File

@@ -0,0 +1,13 @@
#ifdef CUSTOM_CFG_DEBUG
int custom4_debug()
{
return 0;
}
#endif
#ifdef CUSTOM_CFG_OTHER
int custom4_other()
{
return 0;
}
#endif

View File

@@ -0,0 +1,13 @@
#ifdef CUSTOM_CFG_DEBUG
int custom5_debug()
{
return 0;
}
#endif
#ifdef CUSTOM_CFG_OTHER
int custom5_other()
{
return 0;
}
#endif

View File

@@ -7,7 +7,14 @@
#include "iface.h"
extern int custom1_debug();
extern int custom2_debug();
extern int custom3_debug();
extern int custom4_debug();
extern int custom5_debug();
int main(int argc, char** argv)
{
return iface_src() + iface_debug();
return iface_src() + iface_debug() + custom1_debug() + custom2_debug() +
custom3_debug() + custom4_debug() + custom5_debug();
}

View File

@@ -7,7 +7,14 @@
#include "iface.h"
extern int custom1_other();
extern int custom2_other();
extern int custom3_other();
extern int custom4_other();
extern int custom5_other();
int main(int argc, char** argv)
{
return iface_src() + iface_other();
return iface_src() + iface_other() + custom1_other() + custom2_other() +
custom3_other() + custom4_other() + custom5_other();
}

View File

@@ -0,0 +1,37 @@
set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
if(NOT EXISTS "${vcProjectFile}")
set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
return()
endif()
set(found_CustomBuild_out 0)
set(found_CustomBuild_out_CONFIG 0)
set(found_CustomBuild_out_CONFIG_CONFIG 0)
set(found_CustomBuild_out_HASH 0)
file(STRINGS "${vcProjectFile}" lines)
foreach(line IN LISTS lines)
if(line MATCHES [[<CustomBuild Include=".*\\out\.txt\.rule">]])
set(found_CustomBuild_out 1)
endif()
if(line MATCHES [[<CustomBuild Include=".*\\out-\(CONFIG\)\.txt\.rule">]])
set(found_CustomBuild_out_CONFIG 1)
endif()
if(line MATCHES [[<CustomBuild Include=".*\\out-\(CONFIG\)-\(CONFIG\)\.txt\.rule">]])
set(found_CustomBuild_out_CONFIG_CONFIG 1)
endif()
if(line MATCHES [[<CustomBuild Include=".*\\[0-9A-Fa-f]+\.rule">]])
set(found_CustomBuild_out_HASH 1)
endif()
endforeach()
if(NOT found_CustomBuild_out)
string(APPEND RunCMake_TEST_FAILED "CustomBuild for out.txt.rule not found in\n ${vcProjectFile}\n")
endif()
if(NOT found_CustomBuild_out_CONFIG)
string(APPEND RunCMake_TEST_FAILED "CustomBuild for out-(CONFIG).txt.rule not found in\n ${vcProjectFile}\n")
endif()
if(NOT found_CustomBuild_out_CONFIG_CONFIG)
string(APPEND RunCMake_TEST_FAILED "CustomBuild for out-(CONFIG)-(CONFIG).txt.rule not found in\n ${vcProjectFile}\n")
endif()
if(NOT found_CustomBuild_out_HASH)
string(APPEND RunCMake_TEST_FAILED "CustomBuild for <hash>.rule not found in\n ${vcProjectFile}\n")
endif()

View File

@@ -0,0 +1,21 @@
add_custom_command(
OUTPUT "$<1:out.txt>"
COMMAND ${CMAKE_COMMAND} -E touch "out.txt"
VERBATIM
)
add_custom_command(
OUTPUT "out-$<CONFIG>.txt"
COMMAND ${CMAKE_COMMAND} -E touch "out-$<CONFIG>.txt"
VERBATIM
)
add_custom_command(
OUTPUT "out-$<CONFIG>-$<CONFIG>.txt"
COMMAND ${CMAKE_COMMAND} -E touch "out-$<CONFIG>-$<CONFIG>.txt"
VERBATIM
)
add_custom_command(
OUTPUT "out-$<CONFIG>-$<CONFIG:Debug>.txt"
COMMAND ${CMAKE_COMMAND} -E touch "out-$<CONFIG>-$<CONFIG:Debug>.txt"
VERBATIM
)
add_custom_target(foo DEPENDS "out.txt" "out-$<CONFIG>.txt" "out-$<CONFIG>-$<CONFIG>.txt" "out-$<CONFIG>-$<CONFIG:Debug>.txt")

View File

@@ -7,6 +7,7 @@ if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREA
run_cmake(LanguageStandard)
endif()
run_cmake(CustomCommandGenex)
run_cmake(VsCsharpSourceGroup)
run_cmake(VsCSharpCompilerOpts)
run_cmake(ExplicitCMakeLists)

View File

@@ -1,36 +1,47 @@
CMake Error at BadByproduct.cmake:2 \(add_custom_command\):
add_custom_command called with BYPRODUCTS containing a "#". This character
is not allowed.
BYPRODUCTS containing a "#" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at BadByproduct.cmake:3 \(add_custom_command\):
add_custom_command called with BYPRODUCTS containing a "<". This character
is not allowed.
BYPRODUCTS containing a "<" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at BadByproduct.cmake:4 \(add_custom_command\):
add_custom_command called with BYPRODUCTS containing a ">". This character
is not allowed.
BYPRODUCTS containing a ">" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
(
CMake Error at BadByproduct.cmake:5 \(add_custom_command\):
add_custom_command called with BYPRODUCTS containing a "<". This character
is not allowed.
BYPRODUCTS containing a "#" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
)+
CMake Error at BadByproduct.cmake:6 \(add_custom_command\):
add_custom_command attempted to have a file
BYPRODUCTS path
.*RunCMake/add_custom_command/f
in a source directory as an output of custom command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
(
CMake Error at BadByproduct.cmake:7 \(add_custom_command\):
Error evaluating generator expression:
\$<TARGET_PROPERTY:prop>
\$<TARGET_PROPERTY:prop> may only be used with binary targets. It may not
be used with add_custom_command or add_custom_target. Specify the target
to read a property from using the \$<TARGET_PROPERTY:tgt,prop> signature
instead.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
)+

View File

@@ -4,3 +4,4 @@ add_custom_command(OUTPUT b BYPRODUCTS "a<")
add_custom_command(OUTPUT c BYPRODUCTS "a>")
add_custom_command(OUTPUT d BYPRODUCTS "$<CONFIG>/#")
add_custom_command(OUTPUT e BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/f)
add_custom_command(OUTPUT f BYPRODUCTS "$<TARGET_PROPERTY:prop>")

View File

@@ -1,36 +1,47 @@
CMake Error at BadOutput.cmake:2 \(add_custom_command\):
add_custom_command called with OUTPUT containing a "#". This character is
not allowed.
OUTPUT containing a "#" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at BadOutput.cmake:3 \(add_custom_command\):
add_custom_command called with OUTPUT containing a "<". This character is
not allowed.
OUTPUT containing a "<" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at BadOutput.cmake:4 \(add_custom_command\):
add_custom_command called with OUTPUT containing a ">". This character is
not allowed.
OUTPUT containing a ">" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
(
CMake Error at BadOutput.cmake:5 \(add_custom_command\):
add_custom_command called with OUTPUT containing a "<". This character is
not allowed.
OUTPUT containing a "#" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
)+
CMake Error at BadOutput.cmake:6 \(add_custom_command\):
add_custom_command attempted to have a file
OUTPUT path
.*RunCMake/add_custom_command/e
in a source directory as an output of custom command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
(
CMake Error at BadOutput.cmake:7 \(add_custom_command\):
Error evaluating generator expression:
\$<TARGET_PROPERTY:prop>
\$<TARGET_PROPERTY:prop> may only be used with binary targets. It may not
be used with add_custom_command or add_custom_target. Specify the target
to read a property from using the \$<TARGET_PROPERTY:tgt,prop> signature
instead.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
)+

View File

@@ -4,3 +4,4 @@ add_custom_command(OUTPUT "a<" COMMAND b)
add_custom_command(OUTPUT "a>" COMMAND c)
add_custom_command(OUTPUT "$<CONFIG>/#" COMMAND d)
add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/e COMMAND f)
add_custom_command(OUTPUT "$<TARGET_PROPERTY:prop>" COMMAND g)

View File

@@ -1,36 +1,47 @@
CMake Error at BadByproduct.cmake:2 \(add_custom_target\):
add_custom_target called with BYPRODUCTS containing a "#". This character
is not allowed.
BYPRODUCTS containing a "#" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at BadByproduct.cmake:3 \(add_custom_target\):
add_custom_target called with BYPRODUCTS containing a "<". This character
is not allowed.
BYPRODUCTS containing a "<" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
CMake Error at BadByproduct.cmake:4 \(add_custom_target\):
add_custom_target called with BYPRODUCTS containing a ">". This character
is not allowed.
BYPRODUCTS containing a ">" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
(
CMake Error at BadByproduct.cmake:5 \(add_custom_target\):
add_custom_target called with BYPRODUCTS containing a "<". This character
is not allowed.
BYPRODUCTS containing a "#" is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
)+
CMake Error at BadByproduct.cmake:6 \(add_custom_target\):
add_custom_target attempted to have a file
BYPRODUCTS path
.*RunCMake/add_custom_target/j
in a source directory as an output of custom command.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
(
CMake Error at BadByproduct.cmake:7 \(add_custom_target\):
Error evaluating generator expression:
\$<TARGET_PROPERTY:prop>
\$<TARGET_PROPERTY:prop> may only be used with binary targets. It may not
be used with add_custom_command or add_custom_target. Specify the target
to read a property from using the \$<TARGET_PROPERTY:tgt,prop> signature
instead.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
)+

View File

@@ -4,3 +4,4 @@ add_custom_target(c BYPRODUCTS "a<" COMMAND d)
add_custom_target(e BYPRODUCTS "a>" COMMAND f)
add_custom_target(g BYPRODUCTS "$<CONFIG>/#" COMMAND h)
add_custom_target(i BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/j COMMAND k)
add_custom_target(l BYPRODUCTS "$<TARGET_PROPERTY:prop>" COMMAND m)

View File

@@ -293,7 +293,6 @@ CMAKE_CXX_SOURCES="\
cmCMakePolicyCommand \
cmCPackPropertiesGenerator \
cmCacheManager \
cmCheckCustomOutputs \
cmCommand \
cmCommandArgumentParserHelper \
cmCommands \