summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/add_custom_command.rst48
-rw-r--r--Help/command/add_custom_target.rst3
-rw-r--r--Help/release/dev/custom-command-output-genex.rst6
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/cmAddCustomCommandCommand.cxx8
-rw-r--r--Source/cmAddCustomTargetCommand.cxx6
-rw-r--r--Source/cmCheckCustomOutputs.cxx36
-rw-r--r--Source/cmCheckCustomOutputs.h15
-rw-r--r--Source/cmLocalGenerator.cxx34
-rw-r--r--Tests/ConfigSources/CMakeLists.txt71
-rw-r--r--Tests/ConfigSources/custom1.cpp.in13
-rw-r--r--Tests/ConfigSources/custom2.cpp.in13
-rw-r--r--Tests/ConfigSources/custom3.cpp.in13
-rw-r--r--Tests/ConfigSources/custom4.cpp.in13
-rw-r--r--Tests/ConfigSources/custom5.cpp.in13
-rw-r--r--Tests/ConfigSources/main_debug.cpp9
-rw-r--r--Tests/ConfigSources/main_other.cpp9
-rw-r--r--Tests/RunCMake/VS10Project/CustomCommandGenex-check.cmake37
-rw-r--r--Tests/RunCMake/VS10Project/CustomCommandGenex.cmake21
-rw-r--r--Tests/RunCMake/VS10Project/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt33
-rw-r--r--Tests/RunCMake/add_custom_command/BadByproduct.cmake1
-rw-r--r--Tests/RunCMake/add_custom_command/BadOutput-stderr.txt33
-rw-r--r--Tests/RunCMake/add_custom_command/BadOutput.cmake1
-rw-r--r--Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt33
-rw-r--r--Tests/RunCMake/add_custom_target/BadByproduct.cmake1
-rwxr-xr-xbootstrap1
27 files changed, 367 insertions, 107 deletions
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 85d56a3..4464ad6 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -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.
diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst
index 7c29dda..85e1e16 100644
--- a/Help/command/add_custom_target.rst
+++ b/Help/command/add_custom_target.rst
@@ -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,
diff --git a/Help/release/dev/custom-command-output-genex.rst b/Help/release/dev/custom-command-output-genex.rst
new file mode 100644
index 0000000..215349f
--- /dev/null
+++ b/Help/release/dev/custom-command-output-genex.rst
@@ -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.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index c3b7e50..c5b67c0 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -181,8 +181,6 @@ set(SRCS
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
cmCacheManager.cxx
cmCacheManager.h
- cmCheckCustomOutputs.h
- cmCheckCustomOutputs.cxx
cmCLocaleEnvironmentScope.h
cmCLocaleEnvironmentScope.cxx
cmCMakePath.h
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 8194226..ccd7255 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -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,
diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx
index fd509bd..104065f 100644
--- a/Source/cmAddCustomTargetCommand.cxx
+++ b/Source/cmAddCustomTargetCommand.cxx
@@ -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(
diff --git a/Source/cmCheckCustomOutputs.cxx b/Source/cmCheckCustomOutputs.cxx
deleted file mode 100644
index 7645c88..0000000
--- a/Source/cmCheckCustomOutputs.cxx
+++ /dev/null
@@ -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;
-}
diff --git a/Source/cmCheckCustomOutputs.h b/Source/cmCheckCustomOutputs.h
deleted file mode 100644
index 2752ed4..0000000
--- a/Source/cmCheckCustomOutputs.h
+++ /dev/null
@@ -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);
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index dd1779b..9f9d725 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -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
diff --git a/Tests/ConfigSources/CMakeLists.txt b/Tests/ConfigSources/CMakeLists.txt
index 1db00cc..5513af8 100644
--- a/Tests/ConfigSources/CMakeLists.txt
+++ b/Tests/ConfigSources/CMakeLists.txt
@@ -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.
diff --git a/Tests/ConfigSources/custom1.cpp.in b/Tests/ConfigSources/custom1.cpp.in
new file mode 100644
index 0000000..e5f21c7
--- /dev/null
+++ b/Tests/ConfigSources/custom1.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom1_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom1_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom2.cpp.in b/Tests/ConfigSources/custom2.cpp.in
new file mode 100644
index 0000000..438c1fd
--- /dev/null
+++ b/Tests/ConfigSources/custom2.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom2_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom2_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom3.cpp.in b/Tests/ConfigSources/custom3.cpp.in
new file mode 100644
index 0000000..4545b69
--- /dev/null
+++ b/Tests/ConfigSources/custom3.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom3_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom3_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom4.cpp.in b/Tests/ConfigSources/custom4.cpp.in
new file mode 100644
index 0000000..8a8b2a8
--- /dev/null
+++ b/Tests/ConfigSources/custom4.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom4_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom4_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom5.cpp.in b/Tests/ConfigSources/custom5.cpp.in
new file mode 100644
index 0000000..51f40ae
--- /dev/null
+++ b/Tests/ConfigSources/custom5.cpp.in
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom5_debug()
+{
+ return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom5_other()
+{
+ return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/main_debug.cpp b/Tests/ConfigSources/main_debug.cpp
index 9b1e68a..ef776f8 100644
--- a/Tests/ConfigSources/main_debug.cpp
+++ b/Tests/ConfigSources/main_debug.cpp
@@ -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();
}
diff --git a/Tests/ConfigSources/main_other.cpp b/Tests/ConfigSources/main_other.cpp
index 3184a19..74f2156 100644
--- a/Tests/ConfigSources/main_other.cpp
+++ b/Tests/ConfigSources/main_other.cpp
@@ -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();
}
diff --git a/Tests/RunCMake/VS10Project/CustomCommandGenex-check.cmake b/Tests/RunCMake/VS10Project/CustomCommandGenex-check.cmake
new file mode 100644
index 0000000..a7047bc
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/CustomCommandGenex-check.cmake
@@ -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()
diff --git a/Tests/RunCMake/VS10Project/CustomCommandGenex.cmake b/Tests/RunCMake/VS10Project/CustomCommandGenex.cmake
new file mode 100644
index 0000000..5b69dc2
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/CustomCommandGenex.cmake
@@ -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")
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 133dacc..d5ed136 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -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)
diff --git a/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt b/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt
index 086e397..6d51575 100644
--- a/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt
+++ b/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt
@@ -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\)
+
+)+
diff --git a/Tests/RunCMake/add_custom_command/BadByproduct.cmake b/Tests/RunCMake/add_custom_command/BadByproduct.cmake
index 91bca52..7c786a4 100644
--- a/Tests/RunCMake/add_custom_command/BadByproduct.cmake
+++ b/Tests/RunCMake/add_custom_command/BadByproduct.cmake
@@ -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>")
diff --git a/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt b/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt
index 731e58d..506bec9 100644
--- a/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt
+++ b/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt
@@ -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\)
+
+)+
diff --git a/Tests/RunCMake/add_custom_command/BadOutput.cmake b/Tests/RunCMake/add_custom_command/BadOutput.cmake
index 6875fe9..77acb7f 100644
--- a/Tests/RunCMake/add_custom_command/BadOutput.cmake
+++ b/Tests/RunCMake/add_custom_command/BadOutput.cmake
@@ -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)
diff --git a/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt b/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt
index 0f58550..4f0f005 100644
--- a/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt
+++ b/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt
@@ -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\)
+
+)+
diff --git a/Tests/RunCMake/add_custom_target/BadByproduct.cmake b/Tests/RunCMake/add_custom_target/BadByproduct.cmake
index 963d641..e97f9fd 100644
--- a/Tests/RunCMake/add_custom_target/BadByproduct.cmake
+++ b/Tests/RunCMake/add_custom_target/BadByproduct.cmake
@@ -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)
diff --git a/bootstrap b/bootstrap
index c342f10..aae4f22 100755
--- a/bootstrap
+++ b/bootstrap
@@ -293,7 +293,6 @@ CMAKE_CXX_SOURCES="\
cmCMakePolicyCommand \
cmCPackPropertiesGenerator \
cmCacheManager \
- cmCheckCustomOutputs \
cmCommand \
cmCommandArgumentParserHelper \
cmCommands \