From 4a92df86670f6407531242cf81ebcec056cc3eb5 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 26 Sep 2019 11:56:56 -0400
Subject: cmGlobalNinjaGenerator: Remove unused AddDependencyToAll overload

---
 Source/cmGlobalNinjaGenerator.cxx | 5 -----
 Source/cmGlobalNinjaGenerator.h   | 1 -
 2 files changed, 6 deletions(-)

diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 7bba874..3a3c5fb 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -893,11 +893,6 @@ void cmGlobalNinjaGenerator::AddDependencyToAll(cmGeneratorTarget* target)
   this->AppendTargetOutputs(target, this->AllDependencies);
 }
 
-void cmGlobalNinjaGenerator::AddDependencyToAll(const std::string& input)
-{
-  this->AllDependencies.push_back(input);
-}
-
 void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
 {
   for (auto const& asd : this->AssumedSourceDependencies) {
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index dca783f..3549946 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -295,7 +295,6 @@ public:
   void AppendTargetDependsClosure(cmGeneratorTarget const* target,
                                   cmNinjaOuts& outputs, bool omit_self);
   void AddDependencyToAll(cmGeneratorTarget* target);
-  void AddDependencyToAll(const std::string& input);
 
   const std::vector<cmLocalGenerator*>& GetLocalGenerators() const
   {
-- 
cgit v0.12


From be7857f40d4cee1cd3de6900c9de6b45cb332fe7 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 27 Sep 2019 10:13:39 -0400
Subject: cmLocalCommonGenerator: Mark GetConfigName as const

---
 Source/cmLocalCommonGenerator.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h
index abebbc2..eaef6ab 100644
--- a/Source/cmLocalCommonGenerator.h
+++ b/Source/cmLocalCommonGenerator.h
@@ -25,7 +25,7 @@ public:
                          std::string wd);
   ~cmLocalCommonGenerator() override;
 
-  std::string const& GetConfigName() { return this->ConfigName; }
+  std::string const& GetConfigName() const { return this->ConfigName; }
 
   std::string GetWorkingDirectory() const { return this->WorkingDirectory; }
 
-- 
cgit v0.12


From 11fb377eb96e6a90ea96126a2d22739f6983182a Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 27 Sep 2019 11:15:00 -0400
Subject: cmLocalUnixMakefileGenerator3: Mark GetRelativeTargetDirectory const

---
 Source/cmLocalUnixMakefileGenerator3.cxx | 2 +-
 Source/cmLocalUnixMakefileGenerator3.h   | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 1d87e93..c50989e 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -809,7 +809,7 @@ void cmLocalUnixMakefileGenerator3::WriteConvenienceRule(
 }
 
 std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory(
-  cmGeneratorTarget* target)
+  cmGeneratorTarget const* target) const
 {
   std::string dir =
     cmStrCat(this->HomeRelativeOutputPath, this->GetTargetDirectory(target));
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index c02c0dc..f2295ef 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -139,7 +139,8 @@ public:
   void WriteSpecialTargetsTop(std::ostream& makefileStream);
   void WriteSpecialTargetsBottom(std::ostream& makefileStream);
 
-  std::string GetRelativeTargetDirectory(cmGeneratorTarget* target);
+  std::string GetRelativeTargetDirectory(
+    cmGeneratorTarget const* target) const;
 
   // File pairs for implicit dependency scanning.  The key of the map
   // is the depender and the value is the explicit dependee.
-- 
cgit v0.12


From 0733a94f648d63e8492fbcff3413cef461cb18d8 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Wed, 25 Sep 2019 14:09:43 -0400
Subject: Ninja,Makefile: Fix subdir "all" with nested EXCLUDE_FROM_ALL subdir

The "all" target defined for a subdirectory (e.g. `cd sub; make` or
`ninja sub/all`) should not include the "all" targets from nested
subdirectories (e.g. `sub/sub`) that are marked as `EXCLUDE_FROM_ALL`.
Fix this and add a test case.

Issue: #19753
Co-Author: Sebastian Holtermann <sebholt@xwmw.org>
---
 Source/cmGlobalNinjaGenerator.cxx                                    | 3 +++
 Source/cmGlobalUnixMakefileGenerator3.cxx                            | 3 +++
 Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake                 | 1 +
 Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt        | 2 ++
 Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt | 1 +
 Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/subsub.cpp     | 4 ++++
 Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake       | 1 +
 Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake           | 1 +
 8 files changed, 16 insertions(+)
 create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt
 create mode 100644 Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/subsub.cpp

diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 3a3c5fb..0339193 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1123,6 +1123,9 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
     // The directory-level rule should depend on the directory-level
     // rules of the subdirectories.
     for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
+      if (state.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+        continue;
+      }
       std::string const& currentBinaryDir =
         state.GetDirectory().GetCurrentBinary();
       folderTargets.push_back(
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 4ce3d5e..df4673d 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -429,6 +429,9 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
   // The directory-level rule should depend on the directory-level
   // rules of the subdirectories.
   for (cmStateSnapshot const& c : lg->GetStateSnapshot().GetChildren()) {
+    if (check_all && c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+      continue;
+    }
     std::string subdir =
       cmStrCat(c.GetDirectory().GetCurrentBinary(), '/', pass);
     depends.push_back(std::move(subdir));
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
index ff676a6..fbcfe7b 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
@@ -11,4 +11,5 @@ set(foo_lib \"$<TARGET_FILE:foo>\")
 set(bar_lib \"$<TARGET_FILE:bar>\")
 set(zot_lib \"$<TARGET_FILE:zot>\")
 set(subinc_lib \"$<TARGET_FILE:subinc>\")
+set(subsub_lib \"$<TARGET_FILE:subsub>\")
 ")
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt
index 790da54..9ed9e55 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/CMakeLists.txt
@@ -1,5 +1,7 @@
 project(ExcludeFromAllSub NONE)
 
+add_subdirectory(SubSub EXCLUDE_FROM_ALL)
+
 add_library(bar STATIC EXCLUDE_FROM_ALL bar.cpp)
 
 add_library(zot STATIC zot.cpp)
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt
new file mode 100644
index 0000000..14f7973
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(subsub STATIC subsub.cpp)
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/subsub.cpp b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/subsub.cpp
new file mode 100644
index 0000000..ca689ed
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/subsub.cpp
@@ -0,0 +1,4 @@
+int subsub()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake
index 297ad1e..afacf6e 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake
@@ -18,6 +18,7 @@ if(EXISTS ${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
   foreach(file
       "${main_exe}"
       "${bar_lib}"
+      "${subsub_lib}"
       )
     if(EXISTS "${file}")
       set(RunCMake_TEST_FAILED
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
index 433c032..b229f4c 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
@@ -21,6 +21,7 @@ if(EXISTS ${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
   foreach(file
       "${zot_lib}"
       "${bar_lib}"
+      "${subsub_lib}"
       )
     if(EXISTS "${file}")
       set(RunCMake_TEST_FAILED
-- 
cgit v0.12


From a49cd4d1a75f20180a349cdfea3fd384eedf3e8b Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 26 Sep 2019 14:35:55 -0400
Subject: Ninja: Fix EXCLUDE_FROM_ALL OFF on sub/sub/tgt in sub/all

Defer adding a test to a later commit after all generators have been
fixed.

Issue: #19753
---
 Source/cmGlobalNinjaGenerator.cxx | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 0339193..62106ac 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1114,8 +1114,25 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
            type == cmStateEnums::SHARED_LIBRARY ||
            type == cmStateEnums::MODULE_LIBRARY ||
            type == cmStateEnums::OBJECT_LIBRARY ||
-           type == cmStateEnums::UTILITY) &&
-          !gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+           type == cmStateEnums::UTILITY)) {
+        if (const char* exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) {
+          if (cmIsOn(exclude)) {
+            // This target has been explicitly excluded.
+            continue;
+          }
+          // This target has been explicitly un-excluded.  The directory-level
+          // rule for every directory between this and the root (exclusive)
+          // should depend on the target-level rule for this target.
+          cmStateSnapshot dir =
+            lg->GetStateSnapshot().GetBuildsystemDirectoryParent();
+          cmStateSnapshot parent = dir.GetBuildsystemDirectoryParent();
+          while (parent.IsValid()) {
+            std::string const& folder = dir.GetDirectory().GetCurrentBinary();
+            targetsPerFolder[folder].push_back(gt->GetName());
+            dir = parent;
+            parent = parent.GetBuildsystemDirectoryParent();
+          }
+        }
         folderTargets.push_back(gt->GetName());
       }
     }
-- 
cgit v0.12


From a75586c775eb8f663ca1372ff20f9a51e1ad420d Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 27 Sep 2019 08:50:54 -0400
Subject: Ninja: Simplify top-level "all" target generation

Remove its dedicated implementation and update the per-directory "all"
target generation to work for the top-level directory too.
---
 Source/cmGlobalNinjaGenerator.cxx | 45 +++++++++++----------------------------
 Source/cmGlobalNinjaGenerator.h   | 12 +----------
 Source/cmLocalNinjaGenerator.cxx  |  6 ------
 3 files changed, 14 insertions(+), 49 deletions(-)

diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 62106ac..3497828 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -20,6 +20,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpressionEvaluationFile.h"
 #include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalNinjaGenerator.h"
@@ -888,11 +889,6 @@ void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os)
      << cmVersion::GetMinorVersion() << "\n\n";
 }
 
-void cmGlobalNinjaGenerator::AddDependencyToAll(cmGeneratorTarget* target)
-{
-  this->AppendTargetOutputs(target, this->AllDependencies);
-}
-
 void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
 {
   for (auto const& asd : this->AssumedSourceDependencies) {
@@ -1091,19 +1087,11 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
   cmGlobalNinjaGenerator::WriteDivider(os);
   os << "# Folder targets.\n\n";
 
-  std::string const& rootBinaryDir =
-    this->LocalGenerators[0]->GetBinaryDirectory();
-
   std::map<std::string, cmNinjaDeps> targetsPerFolder;
   for (cmLocalGenerator const* lg : this->LocalGenerators) {
     std::string const& currentBinaryFolder(
       lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
 
-    // Do not generate a rule for the root binary dir.
-    if (currentBinaryFolder == rootBinaryDir) {
-      continue;
-    }
-
     // The directory-level rule should depend on the target-level rules
     // for all targets in the directory.
     cmNinjaDeps& folderTargets = targetsPerFolder[currentBinaryFolder];
@@ -1121,19 +1109,16 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
             continue;
           }
           // This target has been explicitly un-excluded.  The directory-level
-          // rule for every directory between this and the root (exclusive)
-          // should depend on the target-level rule for this target.
-          cmStateSnapshot dir =
-            lg->GetStateSnapshot().GetBuildsystemDirectoryParent();
-          cmStateSnapshot parent = dir.GetBuildsystemDirectoryParent();
-          while (parent.IsValid()) {
+          // rule for every directory between this and the root should depend
+          // on the target-level rule for this target.
+          for (cmStateSnapshot dir =
+                 lg->GetStateSnapshot().GetBuildsystemDirectoryParent();
+               dir.IsValid(); dir = dir.GetBuildsystemDirectoryParent()) {
             std::string const& folder = dir.GetDirectory().GetCurrentBinary();
-            targetsPerFolder[folder].push_back(gt->GetName());
-            dir = parent;
-            parent = parent.GetBuildsystemDirectoryParent();
+            this->AppendTargetOutputs(gt, targetsPerFolder[folder]);
           }
         }
-        folderTargets.push_back(gt->GetName());
+        this->AppendTargetOutputs(gt, folderTargets);
       }
     }
 
@@ -1296,22 +1281,18 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
   cmGlobalNinjaGenerator::WriteDivider(os);
   os << "# Built-in targets\n\n";
 
-  this->WriteTargetAll(os);
+  this->WriteTargetDefault(os);
   this->WriteTargetRebuildManifest(os);
   this->WriteTargetClean(os);
   this->WriteTargetHelp(os);
 }
 
-void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
+void cmGlobalNinjaGenerator::WriteTargetDefault(std::ostream& os)
 {
-  cmNinjaBuild build("phony");
-  build.Comment = "The main all target.";
-  build.Outputs.push_back(this->TargetAll);
-  build.ExplicitDeps = this->AllDependencies;
-  this->WriteBuild(os, build);
-
   if (!this->HasOutputPathPrefix()) {
-    cmGlobalNinjaGenerator::WriteDefault(os, build.Outputs,
+    cmNinjaDeps all;
+    all.push_back(this->TargetAll);
+    cmGlobalNinjaGenerator::WriteDefault(os, all,
                                          "Make the all target the default.");
   }
 }
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 3549946..1bfbffa 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -17,7 +17,6 @@
 
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalCommonGenerator.h"
-#include "cmGlobalGenerator.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmNinjaTypes.h"
 #include "cmPolicies.h"
@@ -294,18 +293,12 @@ public:
                                   cmNinjaDeps& outputs);
   void AppendTargetDependsClosure(cmGeneratorTarget const* target,
                                   cmNinjaOuts& outputs, bool omit_self);
-  void AddDependencyToAll(cmGeneratorTarget* target);
 
   const std::vector<cmLocalGenerator*>& GetLocalGenerators() const
   {
     return LocalGenerators;
   }
 
-  bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target)
-  {
-    return cmGlobalGenerator::IsExcluded(root, target);
-  }
-
   int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; }
 
   void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target);
@@ -372,7 +365,7 @@ private:
   void WriteUnknownExplicitDependencies(std::ostream& os);
 
   void WriteBuiltinTargets(std::ostream& os);
-  void WriteTargetAll(std::ostream& os);
+  void WriteTargetDefault(std::ostream& os);
   void WriteTargetRebuildManifest(std::ostream& os);
   bool WriteTargetCleanAdditional(std::ostream& os);
   void WriteTargetClean(std::ostream& os);
@@ -399,9 +392,6 @@ private:
   /// Length of rule command, used by rsp file evaluation
   std::unordered_map<std::string, int> RuleCmdLength;
 
-  /// The set of dependencies to add to the "all" target.
-  cmNinjaDeps AllDependencies;
-
   bool UsingGCCOnWindows = false;
 
   /// The set of custom commands we have seen.
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index fed8be5..187a847 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -88,12 +88,6 @@ void cmLocalNinjaGenerator::Generate()
     auto tg = cmNinjaTargetGenerator::New(target);
     if (tg) {
       tg->Generate();
-      // Add the target to "all" if required.
-      if (!this->GetGlobalNinjaGenerator()->IsExcluded(
-            this->GetGlobalNinjaGenerator()->GetLocalGenerators()[0],
-            target)) {
-        this->GetGlobalNinjaGenerator()->AddDependencyToAll(target);
-      }
     }
   }
 
-- 
cgit v0.12


From d713bcb6427381ab8743084726196a4eed96c135 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 27 Sep 2019 09:23:35 -0400
Subject: Ninja: Factor out per-dir "all" target computation into common
 generator

This will make it re-usable for the Makefile generator.
---
 Source/cmGlobalCommonGenerator.cxx | 66 +++++++++++++++++++++++++++++++
 Source/cmGlobalCommonGenerator.h   | 24 ++++++++++++
 Source/cmGlobalNinjaGenerator.cxx  | 80 +++++++++++---------------------------
 3 files changed, 112 insertions(+), 58 deletions(-)

diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx
index bf992b4..93ff00b 100644
--- a/Source/cmGlobalCommonGenerator.cxx
+++ b/Source/cmGlobalCommonGenerator.cxx
@@ -2,6 +2,15 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalCommonGenerator.h"
 
+#include "cmGeneratorTarget.h"
+#include "cmLocalGenerator.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+
+#include <utility>
+
 class cmake;
 
 cmGlobalCommonGenerator::cmGlobalCommonGenerator(cmake* cm)
@@ -10,3 +19,60 @@ cmGlobalCommonGenerator::cmGlobalCommonGenerator(cmake* cm)
 }
 
 cmGlobalCommonGenerator::~cmGlobalCommonGenerator() = default;
+
+std::map<std::string, cmGlobalCommonGenerator::DirectoryTarget>
+cmGlobalCommonGenerator::ComputeDirectoryTargets() const
+{
+  std::map<std::string, DirectoryTarget> dirTargets;
+  for (cmLocalGenerator* lg : this->LocalGenerators) {
+    std::string const& currentBinaryDir(
+      lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
+    DirectoryTarget& dirTarget = dirTargets[currentBinaryDir];
+    dirTarget.LG = lg;
+
+    // The directory-level rule should depend on the target-level rules
+    // for all targets in the directory.
+    for (auto gt : lg->GetGeneratorTargets()) {
+      cmStateEnums::TargetType const type = gt->GetType();
+      if (type != cmStateEnums::EXECUTABLE &&
+          type != cmStateEnums::STATIC_LIBRARY &&
+          type != cmStateEnums::SHARED_LIBRARY &&
+          type != cmStateEnums::MODULE_LIBRARY &&
+          type != cmStateEnums::OBJECT_LIBRARY &&
+          type != cmStateEnums::UTILITY) {
+        continue;
+      }
+      DirectoryTarget::Target t;
+      t.GT = gt;
+      if (const char* exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) {
+        if (cmIsOn(exclude)) {
+          // This target has been explicitly excluded.
+          t.ExcludeFromAll = true;
+        } else {
+          // This target has been explicitly un-excluded.  The directory-level
+          // rule for every directory between this and the root should depend
+          // on the target-level rule for this target.
+          for (cmStateSnapshot dir =
+                 lg->GetStateSnapshot().GetBuildsystemDirectoryParent();
+               dir.IsValid(); dir = dir.GetBuildsystemDirectoryParent()) {
+            std::string const& d = dir.GetDirectory().GetCurrentBinary();
+            dirTargets[d].Targets.emplace_back(t);
+          }
+        }
+      }
+      dirTarget.Targets.emplace_back(t);
+    }
+
+    // The directory-level rule should depend on the directory-level
+    // rules of the subdirectories.
+    for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
+      DirectoryTarget::Dir d;
+      d.Path = state.GetDirectory().GetCurrentBinary();
+      d.ExcludeFromAll =
+        state.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL");
+      dirTarget.Children.emplace_back(std::move(d));
+    }
+  }
+
+  return dirTargets;
+}
diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h
index e19118b..de81da7 100644
--- a/Source/cmGlobalCommonGenerator.h
+++ b/Source/cmGlobalCommonGenerator.h
@@ -7,7 +7,13 @@
 
 #include "cmGlobalGenerator.h"
 
+#include <map>
+#include <string>
+#include <vector>
+
 class cmake;
+class cmGeneratorTarget;
+class cmLocalGenerator;
 
 /** \class cmGlobalCommonGenerator
  * \brief Common infrastructure for Makefile and Ninja global generators.
@@ -17,6 +23,24 @@ class cmGlobalCommonGenerator : public cmGlobalGenerator
 public:
   cmGlobalCommonGenerator(cmake* cm);
   ~cmGlobalCommonGenerator() override;
+
+  struct DirectoryTarget
+  {
+    cmLocalGenerator* LG = nullptr;
+    struct Target
+    {
+      cmGeneratorTarget const* GT = nullptr;
+      bool ExcludeFromAll = false;
+    };
+    std::vector<Target> Targets;
+    struct Dir
+    {
+      std::string Path;
+      bool ExcludeFromAll = false;
+    };
+    std::vector<Dir> Children;
+  };
+  std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const;
 };
 
 #endif
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 3497828..d8fe258 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1087,68 +1087,32 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
   cmGlobalNinjaGenerator::WriteDivider(os);
   os << "# Folder targets.\n\n";
 
-  std::map<std::string, cmNinjaDeps> targetsPerFolder;
-  for (cmLocalGenerator const* lg : this->LocalGenerators) {
-    std::string const& currentBinaryFolder(
-      lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
-
-    // The directory-level rule should depend on the target-level rules
-    // for all targets in the directory.
-    cmNinjaDeps& folderTargets = targetsPerFolder[currentBinaryFolder];
-    for (auto gt : lg->GetGeneratorTargets()) {
-      cmStateEnums::TargetType const type = gt->GetType();
-      if ((type == cmStateEnums::EXECUTABLE ||
-           type == cmStateEnums::STATIC_LIBRARY ||
-           type == cmStateEnums::SHARED_LIBRARY ||
-           type == cmStateEnums::MODULE_LIBRARY ||
-           type == cmStateEnums::OBJECT_LIBRARY ||
-           type == cmStateEnums::UTILITY)) {
-        if (const char* exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) {
-          if (cmIsOn(exclude)) {
-            // This target has been explicitly excluded.
-            continue;
-          }
-          // This target has been explicitly un-excluded.  The directory-level
-          // rule for every directory between this and the root should depend
-          // on the target-level rule for this target.
-          for (cmStateSnapshot dir =
-                 lg->GetStateSnapshot().GetBuildsystemDirectoryParent();
-               dir.IsValid(); dir = dir.GetBuildsystemDirectoryParent()) {
-            std::string const& folder = dir.GetDirectory().GetCurrentBinary();
-            this->AppendTargetOutputs(gt, targetsPerFolder[folder]);
-          }
-        }
-        this->AppendTargetOutputs(gt, folderTargets);
-      }
-    }
+  std::map<std::string, DirectoryTarget> dirTargets =
+    this->ComputeDirectoryTargets();
 
-    // The directory-level rule should depend on the directory-level
-    // rules of the subdirectories.
-    for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
-      if (state.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
-        continue;
+  for (auto const& it : dirTargets) {
+    cmNinjaBuild build("phony");
+    cmGlobalNinjaGenerator::WriteDivider(os);
+    std::string const& currentBinaryDir = it.first;
+    DirectoryTarget const& dt = it.second;
+
+    // Setup target
+    build.Comment = "Folder: " + currentBinaryDir;
+    build.Outputs.emplace_back(
+      this->ConvertToNinjaPath(currentBinaryDir + "/all"));
+    for (DirectoryTarget::Target const& t : dt.Targets) {
+      if (!t.ExcludeFromAll) {
+        this->AppendTargetOutputs(t.GT, build.ExplicitDeps);
       }
-      std::string const& currentBinaryDir =
-        state.GetDirectory().GetCurrentBinary();
-      folderTargets.push_back(
-        this->ConvertToNinjaPath(currentBinaryDir + "/all"));
     }
-  }
-
-  if (!targetsPerFolder.empty()) {
-    cmNinjaBuild build("phony");
-    build.Outputs.emplace_back("");
-    for (auto& it : targetsPerFolder) {
-      cmGlobalNinjaGenerator::WriteDivider(os);
-      std::string const& currentBinaryDir = it.first;
-
-      // Setup target
-      build.Comment = "Folder: " + currentBinaryDir;
-      build.Outputs[0] = this->ConvertToNinjaPath(currentBinaryDir + "/all");
-      build.ExplicitDeps = std::move(it.second);
-      // Write target
-      this->WriteBuild(os, build);
+    for (DirectoryTarget::Dir const& d : dt.Children) {
+      if (!d.ExcludeFromAll) {
+        build.ExplicitDeps.emplace_back(
+          this->ConvertToNinjaPath(d.Path + "/all"));
+      }
     }
+    // Write target
+    this->WriteBuild(os, build);
   }
 }
 
-- 
cgit v0.12


From 742084337010ed26c19132a8b9d96e9e4891f9f6 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 27 Sep 2019 11:48:58 -0400
Subject: Makefiles: Fix EXCLUDE_FROM_ALL OFF on sub/sub/tgt in sub/all

Defer adding a test to a later commit after all generators have been
fixed.

Issue: #19753
Co-Author: Sebastian Holtermann <sebholt@xwmw.org>
---
 Source/cmGlobalUnixMakefileGenerator3.cxx | 89 ++++++++++---------------------
 Source/cmGlobalUnixMakefileGenerator3.h   |  4 +-
 2 files changed, 31 insertions(+), 62 deletions(-)

diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index df4673d..4c2d69f 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -230,17 +230,14 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
     depends.push_back(this->EmptyRuleHackDepends);
   }
 
-  // Write and empty all:
-  lg->WriteMakeRule(makefileStream, "The main recursive all target", "all",
-                    depends, no_commands, true);
-
-  // Write an empty preinstall:
-  lg->WriteMakeRule(makefileStream, "The main recursive preinstall target",
-                    "preinstall", depends, no_commands, true);
-
   // Write out the "special" stuff
   lg->WriteSpecialTargetsTop(makefileStream);
 
+  // Write the directory level rules.
+  for (auto const& it : this->ComputeDirectoryTargets()) {
+    this->WriteDirectoryRules2(makefileStream, it.second);
+  }
+
   // Write the target convenience rules
   for (cmLocalGenerator* localGen : this->LocalGenerators) {
     this->WriteConvenienceRules2(
@@ -396,44 +393,37 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
 }
 
 void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
-  std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg,
-  const char* pass, bool check_all, bool check_relink,
-  std::vector<std::string> const& commands)
+  std::ostream& ruleFileStream, DirectoryTarget const& dt, const char* pass,
+  bool check_all, bool check_relink, std::vector<std::string> const& commands)
 {
-  // Get the relative path to the subdirectory from the top.
+  auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
   std::string makeTarget =
     cmStrCat(lg->GetCurrentBinaryDirectory(), '/', pass);
 
   // The directory-level rule should depend on the target-level rules
   // for all targets in the directory.
   std::vector<std::string> depends;
-  for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
-    int type = gtarget->GetType();
-    if ((type == cmStateEnums::EXECUTABLE) ||
-        (type == cmStateEnums::STATIC_LIBRARY) ||
-        (type == cmStateEnums::SHARED_LIBRARY) ||
-        (type == cmStateEnums::MODULE_LIBRARY) ||
-        (type == cmStateEnums::OBJECT_LIBRARY) ||
-        (type == cmStateEnums::UTILITY)) {
-      // Add this to the list of depends rules in this directory.
-      if ((!check_all || !gtarget->GetPropertyAsBool("EXCLUDE_FROM_ALL")) &&
-          (!check_relink ||
-           gtarget->NeedRelinkBeforeInstall(lg->GetConfigName()))) {
-        std::string tname =
-          cmStrCat(lg->GetRelativeTargetDirectory(gtarget), '/', pass);
-        depends.push_back(std::move(tname));
-      }
+  for (DirectoryTarget::Target const& t : dt.Targets) {
+    // Add this to the list of depends rules in this directory.
+    if ((!check_all || !t.ExcludeFromAll) &&
+        (!check_relink ||
+         t.GT->NeedRelinkBeforeInstall(lg->GetConfigName()))) {
+      // The target may be from a different directory; use its local gen.
+      auto const* tlg = static_cast<cmLocalUnixMakefileGenerator3 const*>(
+        t.GT->GetLocalGenerator());
+      std::string tname =
+        cmStrCat(tlg->GetRelativeTargetDirectory(t.GT), '/', pass);
+      depends.push_back(std::move(tname));
     }
   }
 
   // The directory-level rule should depend on the directory-level
   // rules of the subdirectories.
-  for (cmStateSnapshot const& c : lg->GetStateSnapshot().GetChildren()) {
-    if (check_all && c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+  for (DirectoryTarget::Dir const& d : dt.Children) {
+    if (check_all && d.ExcludeFromAll) {
       continue;
     }
-    std::string subdir =
-      cmStrCat(c.GetDirectory().GetCurrentBinary(), '/', pass);
+    std::string subdir = cmStrCat(d.Path, '/', pass);
     depends.push_back(std::move(subdir));
   }
 
@@ -455,8 +445,9 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
 }
 
 void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
-  std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
+  std::ostream& ruleFileStream, DirectoryTarget const& dt)
 {
+  auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
   // Begin the directory-level rules section.
   {
     std::string dir =
@@ -471,19 +462,17 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
     ruleFileStream << "\n\n";
   }
 
-  if (!lg->IsRootMakefile()) {
-    // Write directory-level rules for "all".
-    this->WriteDirectoryRule2(ruleFileStream, lg, "all", true, false);
+  // Write directory-level rules for "all".
+  this->WriteDirectoryRule2(ruleFileStream, dt, "all", true, false);
 
-    // Write directory-level rules for "preinstall".
-    this->WriteDirectoryRule2(ruleFileStream, lg, "preinstall", true, true);
-  }
+  // Write directory-level rules for "preinstall".
+  this->WriteDirectoryRule2(ruleFileStream, dt, "preinstall", true, true);
 
   // Write directory-level rules for "clean".
   {
     std::vector<std::string> cmds;
     lg->AppendDirectoryCleanCommand(cmds);
-    this->WriteDirectoryRule2(ruleFileStream, lg, "clean", false, false, cmds);
+    this->WriteDirectoryRule2(ruleFileStream, dt, "clean", false, false, cmds);
   }
 }
 
@@ -630,9 +619,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
   std::string localName;
   std::string makeTargetName;
 
-  // write the directory level rules for this local gen
-  this->WriteDirectoryRules2(ruleFileStream, lg);
-
   bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
   if (regenerate) {
     depends.emplace_back("cmake_check_build_system");
@@ -698,15 +684,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
       lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
                         localName, depends, commands, true);
 
-      // add the all/all dependency
-      if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
-        depends.clear();
-        depends.push_back(localName);
-        commands.clear();
-        lg->WriteMakeRule(ruleFileStream, "Include target in all.", "all",
-                          depends, commands, true);
-      }
-
       // Write the rule.
       commands.clear();
 
@@ -760,14 +737,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
         lg->WriteMakeRule(ruleFileStream,
                           "Pre-install relink rule for target.", localName,
                           depends, commands, true);
-
-        if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
-          depends.clear();
-          depends.push_back(localName);
-          commands.clear();
-          lg->WriteMakeRule(ruleFileStream, "Prepare target for install.",
-                            "preinstall", depends, commands, true);
-        }
       }
 
       // add the clean rule
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 6a39509..79db30e 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -164,11 +164,11 @@ protected:
                               cmLocalUnixMakefileGenerator3*);
 
   void WriteDirectoryRule2(std::ostream& ruleFileStream,
-                           cmLocalUnixMakefileGenerator3* lg, const char* pass,
+                           DirectoryTarget const& dt, const char* pass,
                            bool check_all, bool check_relink,
                            std::vector<std::string> const& commands = {});
   void WriteDirectoryRules2(std::ostream& ruleFileStream,
-                            cmLocalUnixMakefileGenerator3* lg);
+                            DirectoryTarget const& dt);
 
   void AppendGlobalTargetDepends(std::vector<std::string>& depends,
                                  cmGeneratorTarget* target);
-- 
cgit v0.12


From 8a15e75fe351579314f92dd9d9e2c6faeac5ad71 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 26 Sep 2019 11:47:14 -0400
Subject: Tests: Cover EXCLUDE_FROM_ALL OFF on sub/sub/tgt in sub/all

Issue: #19753
---
 Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake                 | 1 +
 Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt | 2 ++
 Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake       | 1 +
 Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake           | 1 +
 4 files changed, 5 insertions(+)

diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
index fbcfe7b..57ab938 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll.cmake
@@ -12,4 +12,5 @@ set(bar_lib \"$<TARGET_FILE:bar>\")
 set(zot_lib \"$<TARGET_FILE:zot>\")
 set(subinc_lib \"$<TARGET_FILE:subinc>\")
 set(subsub_lib \"$<TARGET_FILE:subsub>\")
+set(subsubinc_lib \"$<TARGET_FILE:subsubinc>\")
 ")
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt
index 14f7973..ec28275 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/SubSub/CMakeLists.txt
@@ -1 +1,3 @@
 add_library(subsub STATIC subsub.cpp)
+add_library(subsubinc STATIC subsub.cpp)
+set_property(TARGET subsubinc PROPERTY EXCLUDE_FROM_ALL OFF)
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake
index afacf6e..d318c10 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check-sub.cmake
@@ -8,6 +8,7 @@ if(EXISTS ${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
       "${foo_lib}"
       "${subinc_lib}"
       "${zot_lib}"
+      "${subsubinc_lib}"
       )
     if(NOT EXISTS "${file}")
       set(RunCMake_TEST_FAILED
diff --git a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
index b229f4c..d4bdef2 100644
--- a/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
+++ b/Tests/RunCMake/add_subdirectory/ExcludeFromAll/check.cmake
@@ -8,6 +8,7 @@ if(EXISTS ${RunCMake_TEST_BINARY_DIR}/check-debug.cmake)
       "${foo_lib}"
       "${subinc_lib}"
       "${main_exe}"
+      "${subsubinc_lib}"
       )
     if(EXISTS "${file}")
       # Remove for next step of test.
-- 
cgit v0.12