summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2020-09-10 14:09:44 (GMT)
committerKitware Robot <kwrobot@kitware.com>2020-09-10 14:12:30 (GMT)
commit487c71123006e6ea79b5734d60cd0731164ecaaa (patch)
tree2cebe89b98d5c5596b2bf23bf199bd2b249996bc
parentdb3efb75686265ec23ad593b59b388c262e7cfc8 (diff)
parent45fedf0e176d354b8cb4d3eed4a1ef9bf3943094 (diff)
downloadCMake-487c71123006e6ea79b5734d60cd0731164ecaaa.zip
CMake-487c71123006e6ea79b5734d60cd0731164ecaaa.tar.gz
CMake-487c71123006e6ea79b5734d60cd0731164ecaaa.tar.bz2
Merge topic 'custom-command-dedup'
45fedf0e17 Makefile: Add policy CMP0113 to avoid duplication of custom commands 844779bdc1 cmMakefileTargetGenerator: Simplify custom command output collection Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !5204
-rw-r--r--Help/manual/cmake-policies.7.rst1
-rw-r--r--Help/policy/CMP0113.rst43
-rw-r--r--Help/release/dev/custom-command-dedup.rst5
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx10
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.h10
-rw-r--r--Source/cmMakefileTargetGenerator.cxx48
-rw-r--r--Source/cmMakefileTargetGenerator.h5
-rw-r--r--Source/cmPolicies.h7
-rw-r--r--Tests/RunCMake/Make/CMP0113-Common.cmake17
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW-build-gnu-stderr.txt5
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW-build-result.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW-build-stderr.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-NEW.cmake2
-rw-r--r--Tests/RunCMake/Make/CMP0113-OLD-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-OLD.cmake2
-rw-r--r--Tests/RunCMake/Make/CMP0113-WARN-build-stdout.txt1
-rw-r--r--Tests/RunCMake/Make/CMP0113-WARN.cmake2
-rw-r--r--Tests/RunCMake/Make/RunCMakeTest.cmake22
-rw-r--r--Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt1
20 files changed, 174 insertions, 11 deletions
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index cd1d4d3..3821dc3 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.19
.. toctree::
:maxdepth: 1
+ CMP0113: Makefile generators do not repeat custom commands from target dependencies. </policy/CMP0113>
CMP0112: Target file component generator expressions do not add target dependencies. </policy/CMP0112>
CMP0111: An imported target with a missing location fails during generation. </policy/CMP0111>
CMP0110: add_test() supports arbitrary characters in test names. </policy/CMP0110>
diff --git a/Help/policy/CMP0113.rst b/Help/policy/CMP0113.rst
new file mode 100644
index 0000000..6f56902
--- /dev/null
+++ b/Help/policy/CMP0113.rst
@@ -0,0 +1,43 @@
+CMP0113
+-------
+
+.. versionadded:: 3.19
+
+:ref:`Makefile Generators` do not repeat custom commands from target
+dependencies.
+
+Consider a chain of custom commands split across two dependent targets:
+
+.. code-block:: cmake
+
+ add_custom_command(OUTPUT output-not-created
+ COMMAND ... DEPENDS ...)
+ set_property(SOURCE output-not-created PROPERTY SYMBOLIC 1)
+ add_custom_command(OUTPUT output-created
+ COMMAND ... DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/output-not-created)
+ add_custom_target(first DEPENDS output-not-created)
+ add_custom_target(second DEPENDS output-created)
+ add_dependencies(second first)
+
+In CMake 3.18 and lower, the Makefile generators put a copy of both custom
+commands in the Makefile for target ``second`` even though its dependency on
+target ``first`` ensures that the first custom command runs before the second.
+Running ``make second`` would cause the first custom command to run once in
+the ``first`` target and then again in the ``second`` target.
+
+CMake 3.19 and above prefer to not duplicate custom commands in a target that
+are already generated in other targets on which the target depends (directly or
+indirectly). This policy provides compatibility for projects that have not
+been updated to expect the new behavior. In particular, projects that relied
+on the duplicate execution or that did not properly set the :prop_sf:`SYMBOLIC`
+source file property may be affected.
+
+The ``OLD`` behavior for this policy is to duplicate custom commands in
+dependent targets. The ``NEW`` behavior of this policy is to not duplicate
+custom commands in dependent targets.
+
+This policy was introduced in CMake version 3.19. Unlike many policies,
+CMake version |release| does *not* warn when this policy is not set and
+simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/release/dev/custom-command-dedup.rst b/Help/release/dev/custom-command-dedup.rst
new file mode 100644
index 0000000..65fa303
--- /dev/null
+++ b/Help/release/dev/custom-command-dedup.rst
@@ -0,0 +1,5 @@
+custom-command-dedup
+--------------------
+
+* :ref:`Makefile Generators` no longer repeat custom commands from target
+ dependencies. See policy :policy:`CMP0113`.
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index c449450..c877cf8 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -38,6 +38,7 @@
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmTargetDepend.h"
#include "cmVersion.h"
#include "cmake.h"
@@ -105,6 +106,15 @@ void cmLocalUnixMakefileGenerator3::Generate()
if (!gt->IsInBuildSystem()) {
continue;
}
+
+ auto& gtVisited = this->GetCommandsVisited(gt);
+ auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt);
+ for (auto& d : deps) {
+ // Take the union of visited source files of custom commands
+ auto depVisited = this->GetCommandsVisited(d);
+ gtVisited.insert(depVisited.begin(), depVisited.end());
+ }
+
std::unique_ptr<cmMakefileTargetGenerator> tg(
cmMakefileTargetGenerator::New(gt));
if (tg) {
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index 095836e..8286d67 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -19,6 +19,7 @@ class cmCustomCommandGenerator;
class cmGeneratorTarget;
class cmGlobalGenerator;
class cmMakefile;
+class cmSourceFile;
/** \class cmLocalUnixMakefileGenerator3
* \brief Write a LocalUnix makefiles.
@@ -294,4 +295,13 @@ private:
bool ColorMakefile;
bool SkipPreprocessedSourceRules;
bool SkipAssemblySourceRules;
+
+ std::set<cmSourceFile const*>& GetCommandsVisited(
+ cmGeneratorTarget const* target)
+ {
+ return this->CommandsVisited[target];
+ };
+
+ std::map<cmGeneratorTarget const*, std::set<cmSourceFile const*>>
+ CommandsVisited;
};
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index ebfddb9..e1fe0e5 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -26,10 +26,12 @@
#include "cmMakefileLibraryTargetGenerator.h"
#include "cmMakefileUtilityTargetGenerator.h"
#include "cmOutputConverter.h"
+#include "cmPolicies.h"
#include "cmProperty.h"
#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocationKind.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
@@ -51,6 +53,17 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
if (cmProp ruleStatus = cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) {
this->NoRuleMessages = cmIsOff(*ruleStatus);
}
+ switch (this->GeneratorTarget->GetPolicyStatusCMP0113()) {
+ case cmPolicies::WARN:
+ case cmPolicies::OLD:
+ this->CMP0113New = false;
+ break;
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->CMP0113New = true;
+ break;
+ }
MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this);
}
@@ -217,6 +230,12 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
this->GeneratorTarget->GetCustomCommands(customCommands,
this->GetConfigName());
for (cmSourceFile const* sf : customCommands) {
+ if (this->CMP0113New &&
+ !this->LocalGenerator->GetCommandsVisited(this->GeneratorTarget)
+ .insert(sf)
+ .second) {
+ continue;
+ }
cmCustomCommandGenerator ccg(*sf->GetCustomCommand(),
this->GetConfigName(), this->LocalGenerator);
this->GenerateCustomRuleFile(ccg);
@@ -1290,16 +1309,7 @@ void cmMakefileTargetGenerator::DriveCustomCommands(
std::vector<std::string>& depends)
{
// Depend on all custom command outputs.
- std::vector<cmSourceFile*> sources;
- this->GeneratorTarget->GetSourceFiles(
- sources, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
- for (cmSourceFile* source : sources) {
- if (cmCustomCommand* cc = source->GetCustomCommand()) {
- cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
- this->LocalGenerator);
- cm::append(depends, ccg.GetOutputs());
- }
- }
+ cm::append(depends, this->CustomCommandOutputs);
}
void cmMakefileTargetGenerator::WriteObjectDependRules(
@@ -1346,6 +1356,22 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile(
bool symbolic = this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs,
depends, commands);
+ // Symbolic inputs are not expected to exist, so add dummy rules.
+ if (this->CMP0113New && !depends.empty()) {
+ std::vector<std::string> no_depends;
+ std::vector<std::string> no_commands;
+ for (std::string const& dep : depends) {
+ if (cmSourceFile* dsf =
+ this->Makefile->GetSource(dep, cmSourceFileLocationKind::Known)) {
+ if (dsf->GetPropertyAsBool("SYMBOLIC")) {
+ this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
+ dep, no_depends, no_commands,
+ true);
+ }
+ }
+ }
+ }
+
// If the rule has changed make sure the output is rebuilt.
if (!symbolic) {
this->GlobalGenerator->AddRuleHash(ccg.GetOutputs(), content.str());
@@ -1360,6 +1386,8 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile(
this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi.first,
objFullPath, srcFullPath);
}
+
+ this->CustomCommandOutputs.insert(outputs.begin(), outputs.end());
}
void cmMakefileTargetGenerator::MakeEchoProgress(
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index fd6dac8..1740d54 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -196,6 +196,8 @@ protected:
unsigned long NumberOfProgressActions;
bool NoRuleMessages;
+ bool CMP0113New = false;
+
// the path to the directory the build file is in
std::string TargetBuildDirectory;
std::string TargetBuildDirectoryFull;
@@ -228,6 +230,9 @@ protected:
// Set of extra output files to be driven by the build.
std::set<std::string> ExtraFiles;
+ // Set of custom command output files to be driven by the build.
+ std::set<std::string> CustomCommandOutputs;
+
using MultipleOutputPairsType = std::map<std::string, std::string>;
MultipleOutputPairsType MultipleOutputPairs;
bool WriteMakeRule(std::ostream& os, const char* comment,
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 5b286d4..f9ec0d6 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -333,6 +333,10 @@ class cmMakefile;
SELECT(POLICY, CMP0112, \
"Target file component generator expressions do not add target " \
"dependencies.", \
+ 3, 19, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0113, \
+ "Makefile generators do not repeat custom commands from target " \
+ "dependencies.", \
3, 19, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
@@ -367,7 +371,8 @@ class cmMakefile;
F(CMP0104) \
F(CMP0105) \
F(CMP0108) \
- F(CMP0112)
+ F(CMP0112) \
+ F(CMP0113)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies
diff --git a/Tests/RunCMake/Make/CMP0113-Common.cmake b/Tests/RunCMake/Make/CMP0113-Common.cmake
new file mode 100644
index 0000000..8ce26c4
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-Common.cmake
@@ -0,0 +1,17 @@
+add_custom_command(
+ OUTPUT output-not-created
+ COMMAND ${CMAKE_COMMAND} -E echo output-not-created
+ DEPENDS ${CMAKE_CURRENT_LIST_FILE}
+ VERBATIM
+ )
+
+add_custom_command(
+ OUTPUT output-created
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_FILE} output-created
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/output-not-created
+ VERBATIM
+ )
+
+add_custom_target(drive1 ALL DEPENDS output-not-created)
+add_custom_target(drive2 ALL DEPENDS output-created)
+add_dependencies(drive2 drive1)
diff --git a/Tests/RunCMake/Make/CMP0113-NEW-build-gnu-stderr.txt b/Tests/RunCMake/Make/CMP0113-NEW-build-gnu-stderr.txt
new file mode 100644
index 0000000..0af354a
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-NEW-build-gnu-stderr.txt
@@ -0,0 +1,5 @@
+No rule to make target [^
+]*output-not-created[^
+]*, needed by [^
+]*output-created[^
+]*
diff --git a/Tests/RunCMake/Make/CMP0113-NEW-build-result.txt b/Tests/RunCMake/Make/CMP0113-NEW-build-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-NEW-build-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/Make/CMP0113-NEW-build-stderr.txt b/Tests/RunCMake/Make/CMP0113-NEW-build-stderr.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-NEW-build-stderr.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/Make/CMP0113-NEW-build-stdout.txt b/Tests/RunCMake/Make/CMP0113-NEW-build-stdout.txt
new file mode 100644
index 0000000..a6b851e
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-NEW-build-stdout.txt
@@ -0,0 +1 @@
+Generating output-not-created.*Built target drive1
diff --git a/Tests/RunCMake/Make/CMP0113-NEW.cmake b/Tests/RunCMake/Make/CMP0113-NEW.cmake
new file mode 100644
index 0000000..a2d1db5
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0113 NEW)
+include(CMP0113-Common.cmake)
diff --git a/Tests/RunCMake/Make/CMP0113-OLD-build-stdout.txt b/Tests/RunCMake/Make/CMP0113-OLD-build-stdout.txt
new file mode 100644
index 0000000..f6e1f0f
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-OLD-build-stdout.txt
@@ -0,0 +1 @@
+Generating output-not-created.*Built target drive1.*Generating output-not-created.*Built target drive2
diff --git a/Tests/RunCMake/Make/CMP0113-OLD.cmake b/Tests/RunCMake/Make/CMP0113-OLD.cmake
new file mode 100644
index 0000000..b6ab120
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0113 OLD)
+include(CMP0113-Common.cmake)
diff --git a/Tests/RunCMake/Make/CMP0113-WARN-build-stdout.txt b/Tests/RunCMake/Make/CMP0113-WARN-build-stdout.txt
new file mode 100644
index 0000000..f6e1f0f
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-WARN-build-stdout.txt
@@ -0,0 +1 @@
+Generating output-not-created.*Built target drive1.*Generating output-not-created.*Built target drive2
diff --git a/Tests/RunCMake/Make/CMP0113-WARN.cmake b/Tests/RunCMake/Make/CMP0113-WARN.cmake
new file mode 100644
index 0000000..48e035a
--- /dev/null
+++ b/Tests/RunCMake/Make/CMP0113-WARN.cmake
@@ -0,0 +1,2 @@
+# Policy CMP0113 not set.
+include(CMP0113-Common.cmake)
diff --git a/Tests/RunCMake/Make/RunCMakeTest.cmake b/Tests/RunCMake/Make/RunCMakeTest.cmake
index 32aafca..5562aca 100644
--- a/Tests/RunCMake/Make/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Make/RunCMakeTest.cmake
@@ -41,3 +41,25 @@ run_VerboseBuild()
run_cmake(CustomCommandDepfile-ERROR)
run_cmake(IncludeRegexSubdir)
+
+function(run_CMP0113 val)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0113-${val}-build)
+ run_cmake(CMP0113-${val})
+ set(RunCMake_TEST_NO_CLEAN 1)
+ set(_backup_lang "$ENV{LANG}")
+ set(_backup_lc_Messages "$ENV{LC_MESSAGES}")
+ if(MAKE_IS_GNU)
+ set(RunCMake-stderr-file CMP0113-${val}-build-gnu-stderr.txt)
+ set(ENV{LANG} "C")
+ set(ENV{LC_MESSAGES} "C")
+ endif()
+ run_cmake_command(CMP0113-${val}-build ${CMAKE_COMMAND} --build .)
+ set(ENV{LANG} "${_backup_lang}")
+ set(ENV{LC_MESSAGES} "${_backup_lc_messages}")
+endfunction()
+
+if(NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
+ run_CMP0113(WARN)
+ run_CMP0113(OLD)
+ run_CMP0113(NEW)
+endif()
diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
index fe13e81..b3f3a5e 100644
--- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
+++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
@@ -33,6 +33,7 @@
\* CMP0105
\* CMP0108
\* CMP0112
+ \* CMP0113
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)