Bläddra i källkod

Merge topic 'autogen_global_target'

0e97ef74d8 Autogen: Add release notes for CMAKE_GLOBAL_AUTOGEN/RCC_TARGET
2ef8fe2222 Autogen: Add documentation for CMAKE_GLOBAL_AUTOGEN/RCC_TARGET
8c8731b422 Autogen: Add test for CMAKE_GLOBAL_AUTOGEN/RCC_TARGET
3baa817c34 Autogen: Add support for global ``autogen`` and ``autorcc`` targets
3327d3bb20 Autogen: Add cmQtAutoGenGlobalInitializer class

Acked-by: Kitware Robot <[email protected]>
Merge-request: !2567
Brad King 7 år sedan
förälder
incheckning
c310480c5d
33 ändrade filer med 638 tillägg och 68 borttagningar
  1. 1 0
      Help/manual/cmake-qt.7.rst
  2. 4 0
      Help/manual/cmake-variables.7.rst
  3. 4 0
      Help/prop_tgt/AUTOMOC.rst
  4. 4 0
      Help/prop_tgt/AUTORCC.rst
  5. 4 0
      Help/prop_tgt/AUTOUIC.rst
  6. 8 0
      Help/release/dev/autogen_global_target.rst
  7. 18 0
      Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
  8. 13 0
      Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst
  9. 18 0
      Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst
  10. 13 0
      Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst
  11. 2 0
      Source/CMakeLists.txt
  12. 5 59
      Source/cmGlobalGenerator.cxx
  13. 185 0
      Source/cmQtAutoGenGlobalInitializer.cxx
  14. 47 0
      Source/cmQtAutoGenGlobalInitializer.h
  15. 25 7
      Source/cmQtAutoGenInitializer.cxx
  16. 8 2
      Source/cmQtAutoGenInitializer.h
  17. 1 0
      Tests/QtAutogen/CommonTests.cmake
  18. 123 0
      Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
  19. 28 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/CMakeLists.txt
  20. 5 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/data.qrc
  21. 20 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/item.cpp
  22. 15 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/item.hpp
  23. 15 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/main.cpp
  24. 2 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/CMakeLists.txt
  25. 6 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.cpp
  26. 6 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.hpp
  27. 5 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/CMakeLists.txt
  28. 6 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.cpp
  29. 6 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.hpp
  30. 5 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/CMakeLists.txt
  31. 6 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.cpp
  32. 6 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.hpp
  33. 24 0
      Tests/QtAutogen/GlobalAutogenTarget/GAT/view.ui

+ 1 - 0
Help/manual/cmake-qt.7.rst

@@ -236,6 +236,7 @@ when either
   :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC`, :prop_sf:`SKIP_AUTOGEN`
   or :policy:`CMP0071`
 - :prop_tgt:`AUTOGEN_TARGET_DEPENDS` lists a source file
+- :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled
 
 qtmain.lib on Windows
 =====================

+ 4 - 0
Help/manual/cmake-variables.7.rst

@@ -345,6 +345,10 @@ Variables that Control the Build
    /variable/CMAKE_FOLDER
    /variable/CMAKE_Fortran_FORMAT
    /variable/CMAKE_Fortran_MODULE_DIRECTORY
+   /variable/CMAKE_GLOBAL_AUTOGEN_TARGET
+   /variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
+   /variable/CMAKE_GLOBAL_AUTORCC_TARGET
+   /variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME
    /variable/CMAKE_GNUtoMS
    /variable/CMAKE_INCLUDE_CURRENT_DIR
    /variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE

+ 4 - 0
Help/prop_tgt/AUTOMOC.rst

@@ -86,5 +86,9 @@ enabling :prop_sf:`SKIP_AUTOMOC` or the broader :prop_sf:`SKIP_AUTOGEN`.
 The number of parallel ``moc`` processes to start can be modified by
 setting :prop_tgt:`AUTOGEN_PARALLEL`.
 
+A global ``autogen`` target that depends on all :prop_tgt:`AUTOMOC` generated
+``<ORIGIN>_autogen`` targets in the project can be generated by enabling
+:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`.
+
 See the :manual:`cmake-qt(7)` manual for more information on using CMake
 with Qt.

+ 4 - 0
Help/prop_tgt/AUTORCC.rst

@@ -35,5 +35,9 @@ generate unspecified unique names for ``rcc``.  Therefore if
 Source files can be excluded from :prop_tgt:`AUTORCC` processing by
 enabling :prop_sf:`SKIP_AUTORCC` or the broader :prop_sf:`SKIP_AUTOGEN`.
 
+A global ``autorcc`` target that depends on all :prop_tgt:`AUTORCC` targets
+in the project can be generated by enabling
+:variable:`CMAKE_GLOBAL_AUTORCC_TARGET`.
+
 See the :manual:`cmake-qt(7)` manual for more information on using CMake
 with Qt.

+ 4 - 0
Help/prop_tgt/AUTOUIC.rst

@@ -36,5 +36,9 @@ enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`.
 The number of parallel ``uic`` processes to start can be modified by
 setting :prop_tgt:`AUTOGEN_PARALLEL`.
 
+A global ``autogen`` target that depends on all :prop_tgt:`AUTOUIC` generated
+``<ORIGIN>_autogen`` targets in the project can be generated by enabling
+:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`.
+
 See the :manual:`cmake-qt(7)` manual for more information on using CMake
 with Qt.

+ 8 - 0
Help/release/dev/autogen_global_target.rst

@@ -0,0 +1,8 @@
+autogen_global_target
+---------------------
+
+* The new variables :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET`,
+  :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`,
+  :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` and
+  :variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME` control the generation
+  of global ``autogen`` and ``autorcc`` targets.

+ 18 - 0
Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst

@@ -0,0 +1,18 @@
+CMAKE_GLOBAL_AUTOGEN_TARGET
+---------------------------
+
+Switch to enable generation of a global ``autogen`` target.
+
+When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a custom target
+``autogen`` is generated.  This target depends on all :prop_tgt:`AUTOMOC` and
+:prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project.
+By building the global ``autogen`` target, all :prop_tgt:`AUTOMOC` and
+:prop_tgt:`AUTOUIC` files in the project will be generated.
+
+The name of the global ``autogen`` target can be changed by setting
+:variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`.
+
+By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.

+ 13 - 0
Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst

@@ -0,0 +1,13 @@
+CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
+--------------------------------
+
+Change the name of the global ``autogen`` target.
+
+When :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled, a global custom target
+named ``autogen`` is created.  :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME`
+allows to set a different name for that target.
+
+By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.

+ 18 - 0
Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst

@@ -0,0 +1,18 @@
+CMAKE_GLOBAL_AUTORCC_TARGET
+---------------------------
+
+Switch to enable generation of a global ``autorcc`` target.
+
+When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a custom target
+``autorcc`` is generated. This target depends on all :prop_tgt:`AUTORCC`
+generated ``<ORIGIN>_arcc_<QRC>`` targets in the project.
+By building the global ``autorcc`` target, all :prop_tgt:`AUTORCC`
+files in the project will be generated.
+
+The name of the global ``autorcc`` target can be changed by setting
+:variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME`.
+
+By default :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.

+ 13 - 0
Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst

@@ -0,0 +1,13 @@
+CMAKE_GLOBAL_AUTORCC_TARGET_NAME
+--------------------------------
+
+Change the name of the global ``autorcc`` target.
+
+When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a global custom target
+named ``autorcc`` is created.  :variable:`CMAKE_GLOBAL_AUTORCC_TARGET_NAME`
+allows to set a different name for that target.
+
+By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME` is unset.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.

+ 2 - 0
Source/CMakeLists.txt

@@ -320,6 +320,8 @@ set(SRCS
   cmQtAutoGen.h
   cmQtAutoGenerator.cxx
   cmQtAutoGenerator.h
+  cmQtAutoGenGlobalInitializer.cxx
+  cmQtAutoGenGlobalInitializer.h
   cmQtAutoGenInitializer.cxx
   cmQtAutoGenInitializer.h
   cmQtAutoGeneratorMocUic.cxx

+ 5 - 59
Source/cmGlobalGenerator.cxx

@@ -34,8 +34,6 @@
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmQtAutoGen.h"
-#include "cmQtAutoGenInitializer.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -46,6 +44,7 @@
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
 #  include "cmCryptoHash.h"
+#  include "cmQtAutoGenGlobalInitializer.h"
 #  include "cm_jsoncpp_value.h"
 #  include "cm_jsoncpp_writer.h"
 #endif
@@ -1469,64 +1468,11 @@ bool cmGlobalGenerator::ComputeTargetDepends()
 bool cmGlobalGenerator::QtAutoGen()
 {
 #ifdef CMAKE_BUILD_WITH_CMAKE
-  std::vector<std::unique_ptr<cmQtAutoGenInitializer>> autogenInits;
-
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
-    const std::vector<cmGeneratorTarget*>& targets =
-      localGen->GetGeneratorTargets();
-    // Find targets that require AUTOGEN processing
-    for (cmGeneratorTarget* target : targets) {
-      if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
-        continue;
-      }
-      if (target->GetType() != cmStateEnums::EXECUTABLE &&
-          target->GetType() != cmStateEnums::STATIC_LIBRARY &&
-          target->GetType() != cmStateEnums::SHARED_LIBRARY &&
-          target->GetType() != cmStateEnums::MODULE_LIBRARY &&
-          target->GetType() != cmStateEnums::OBJECT_LIBRARY) {
-        continue;
-      }
-      if (target->IsImported()) {
-        continue;
-      }
-
-      const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC");
-      const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC");
-      const bool rccEnabled = target->GetPropertyAsBool("AUTORCC");
-      if (!mocEnabled && !uicEnabled && !rccEnabled) {
-        continue;
-      }
-
-      auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
-      // don't do anything if there is no Qt4 or Qt5Core (which contains moc)
-      if (qtVersion.Major != 4 && qtVersion.Major != 5) {
-        continue;
-      }
-
-      autogenInits.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
-        target, mocEnabled, uicEnabled, rccEnabled, qtVersion));
-    }
-  }
-
-  if (!autogenInits.empty()) {
-    // Initialize custom targets
-    for (auto& autoGen : autogenInits) {
-      if (!autoGen->InitCustomTargets()) {
-        return false;
-      }
-    }
-
-    // Setup custom targets
-    for (auto& autoGen : autogenInits) {
-      if (!autoGen->SetupCustomTargets()) {
-        return false;
-      }
-      autoGen.reset(nullptr);
-    }
-  }
-#endif
-
+  cmQtAutoGenGlobalInitializer initializer(this->LocalGenerators);
+  return initializer.generate();
+#else
   return true;
+#endif
 }
 
 cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer(

+ 185 - 0
Source/cmQtAutoGenGlobalInitializer.cxx

@@ -0,0 +1,185 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmQtAutoGenGlobalInitializer.h"
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenInitializer.h"
+
+#include "cmAlgorithms.h"
+#include "cmCustomCommandLines.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+#include <memory>
+#include <utility>
+
+cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
+  std::vector<cmLocalGenerator*> const& localGenerators)
+{
+  for (cmLocalGenerator* localGen : localGenerators) {
+    // Detect global autogen and autorcc target names
+    bool globalAutoGenTarget = false;
+    bool globalAutoRccTarget = false;
+    {
+      cmMakefile* makefile = localGen->GetMakefile();
+      // Detect global autogen target name
+      if (cmSystemTools::IsOn(
+            makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET"))) {
+        std::string targetName =
+          makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME");
+        if (targetName.empty()) {
+          targetName = "autogen";
+        }
+        GlobalAutoGenTargets_.emplace(localGen, std::move(targetName));
+        globalAutoGenTarget = true;
+      }
+
+      // Detect global autorcc target name
+      if (cmSystemTools::IsOn(
+            makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET"))) {
+        std::string targetName =
+          makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME");
+        if (targetName.empty()) {
+          targetName = "autorcc";
+        }
+        GlobalAutoRccTargets_.emplace(localGen, std::move(targetName));
+        globalAutoRccTarget = true;
+      }
+    }
+
+    // Find targets that require AUTOMOC/UIC/RCC processing
+    for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) {
+      // Process only certain target types
+      switch (target->GetType()) {
+        case cmStateEnums::EXECUTABLE:
+        case cmStateEnums::STATIC_LIBRARY:
+        case cmStateEnums::SHARED_LIBRARY:
+        case cmStateEnums::MODULE_LIBRARY:
+        case cmStateEnums::OBJECT_LIBRARY:
+          // Process target
+          break;
+        default:
+          // Don't process target
+          continue;
+      }
+      if (target->IsImported()) {
+        // Don't process target
+        continue;
+      }
+
+      bool const moc = target->GetPropertyAsBool("AUTOMOC");
+      bool const uic = target->GetPropertyAsBool("AUTOUIC");
+      bool const rcc = target->GetPropertyAsBool("AUTORCC");
+      if (moc || uic || rcc) {
+        // We support Qt4 and Qt5
+        auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
+        if ((qtVersion.Major == 4) || (qtVersion.Major == 5)) {
+          // Create autogen target initializer
+          Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
+            this, target, qtVersion, moc, uic, rcc, globalAutoGenTarget,
+            globalAutoRccTarget));
+        }
+      }
+    }
+  }
+}
+
+cmQtAutoGenGlobalInitializer::~cmQtAutoGenGlobalInitializer()
+{
+}
+
+void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget(
+  cmLocalGenerator* localGen, std::string const& name,
+  std::string const& comment)
+{
+  // Test if the target already exists
+  if (localGen->FindGeneratorTargetToUse(name) == nullptr) {
+    cmMakefile* makefile = localGen->GetMakefile();
+
+    // Create utility target
+    cmTarget* target = makefile->AddUtilityCommand(
+      name, cmMakefile::TargetOrigin::Generator, true,
+      makefile->GetHomeOutputDirectory().c_str() /*work dir*/,
+      std::vector<std::string>() /*output*/,
+      std::vector<std::string>() /*depends*/, cmCustomCommandLines(), false,
+      comment.c_str());
+    localGen->AddGeneratorTarget(new cmGeneratorTarget(target, localGen));
+
+    // Set FOLDER property in the target
+    {
+      char const* folder =
+        makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
+      if (folder != nullptr) {
+        target->SetProperty("FOLDER", folder);
+      }
+    }
+  }
+}
+
+void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen(
+  cmLocalGenerator* localGen, std::string const& targetName)
+{
+  auto it = GlobalAutoGenTargets_.find(localGen);
+  if (it != GlobalAutoGenTargets_.end()) {
+    cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
+    if (target != nullptr) {
+      target->Target->AddUtility(targetName, localGen->GetMakefile());
+    }
+  }
+}
+
+void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
+  cmLocalGenerator* localGen, std::string const& targetName)
+{
+  auto it = GlobalAutoRccTargets_.find(localGen);
+  if (it != GlobalAutoRccTargets_.end()) {
+    cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
+    if (target != nullptr) {
+      target->Target->AddUtility(targetName, localGen->GetMakefile());
+    }
+  }
+}
+
+bool cmQtAutoGenGlobalInitializer::generate()
+{
+  return (InitializeCustomTargets() && SetupCustomTargets());
+}
+
+bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets()
+{
+  // Initialize global autogen targets
+  {
+    std::string const comment = "Global AUTOGEN target";
+    for (auto const& pair : GlobalAutoGenTargets_) {
+      GetOrCreateGlobalTarget(pair.first, pair.second, comment);
+    }
+  }
+  // Initialize global autorcc targets
+  {
+    std::string const comment = "Global AUTORCC target";
+    for (auto const& pair : GlobalAutoRccTargets_) {
+      GetOrCreateGlobalTarget(pair.first, pair.second, comment);
+    }
+  }
+  // Initialize per target autogen targets
+  for (auto& initializer : Initializers_) {
+    if (!initializer->InitCustomTargets()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool cmQtAutoGenGlobalInitializer::SetupCustomTargets()
+{
+  for (auto& initializer : Initializers_) {
+    if (!initializer->SetupCustomTargets()) {
+      return false;
+    }
+  }
+  return true;
+}

+ 47 - 0
Source/cmQtAutoGenGlobalInitializer.h

@@ -0,0 +1,47 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmQtAutoGenGlobalInitializer_h
+#define cmQtAutoGenGlobalInitializer_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <map>
+#include <memory> // IWYU pragma: keep
+#include <string>
+#include <vector>
+
+class cmLocalGenerator;
+class cmQtAutoGenInitializer;
+
+/// @brief Initializes the QtAutoGen generators
+class cmQtAutoGenGlobalInitializer
+{
+public:
+  cmQtAutoGenGlobalInitializer(
+    std::vector<cmLocalGenerator*> const& localGenerators);
+  ~cmQtAutoGenGlobalInitializer();
+
+  bool generate();
+
+private:
+  friend class cmQtAutoGenInitializer;
+
+  bool InitializeCustomTargets();
+  bool SetupCustomTargets();
+
+  void GetOrCreateGlobalTarget(cmLocalGenerator* localGen,
+                               std::string const& name,
+                               std::string const& comment);
+
+  void AddToGlobalAutoGen(cmLocalGenerator* localGen,
+                          std::string const& targetName);
+  void AddToGlobalAutoRcc(cmLocalGenerator* localGen,
+                          std::string const& targetName);
+
+private:
+  std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_;
+  std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_;
+  std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_;
+};
+
+#endif

+ 25 - 7
Source/cmQtAutoGenInitializer.cxx

@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmQtAutoGenInitializer.h"
 #include "cmQtAutoGen.h"
+#include "cmQtAutoGenGlobalInitializer.h"
 
 #include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
@@ -174,17 +175,19 @@ static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin,
   return cycle;
 }
 
-cmQtAutoGenInitializer::cmQtAutoGenInitializer(cmGeneratorTarget* target,
-                                               bool mocEnabled,
-                                               bool uicEnabled,
-                                               bool rccEnabled,
-                                               IntegerVersion const& qtVersion)
-  : Target(target)
+cmQtAutoGenInitializer::cmQtAutoGenInitializer(
+  cmQtAutoGenGlobalInitializer* globalInitializer, cmGeneratorTarget* target,
+  IntegerVersion const& qtVersion, bool mocEnabled, bool uicEnabled,
+  bool rccEnabled, bool globalAutogenTarget, bool globalAutoRccTarget)
+  : GlobalInitializer(globalInitializer)
+  , Target(target)
   , QtVersion(qtVersion)
 {
+  AutogenTarget.GlobalTarget = globalAutogenTarget;
   Moc.Enabled = mocEnabled;
   Uic.Enabled = uicEnabled;
   Rcc.Enabled = rccEnabled;
+  Rcc.GlobalTarget = globalAutoRccTarget;
 }
 
 bool cmQtAutoGenInitializer::InitCustomTargets()
@@ -882,6 +885,10 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
     if (!this->AutogenTarget.DependFiles.empty()) {
       usePRE_BUILD = false;
     }
+    // Cannot use PRE_BUILD when a global autogen target is in place
+    if (AutogenTarget.GlobalTarget) {
+      usePRE_BUILD = false;
+    }
   }
   // Create the autogen target/command
   if (usePRE_BUILD) {
@@ -961,6 +968,12 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
 
     // Add autogen target to the origin target dependencies
     this->Target->Target->AddUtility(this->AutogenTarget.Name, makefile);
+
+    // Add autogen target to the global autogen target dependencies
+    if (this->AutogenTarget.GlobalTarget) {
+      this->GlobalInitializer->AddToGlobalAutoGen(localGen,
+                                                  this->AutogenTarget.Name);
+    }
   }
 
   return true;
@@ -1004,7 +1017,7 @@ bool cmQtAutoGenInitializer::InitRccTargets()
     std::string ccComment = "Automatic RCC for ";
     ccComment += FileProjectRelativePath(makefile, qrc.QrcFile);
 
-    if (qrc.Generated) {
+    if (qrc.Generated || this->Rcc.GlobalTarget) {
       // Create custom rcc target
       std::string ccName;
       {
@@ -1035,6 +1048,11 @@ bool cmQtAutoGenInitializer::InitRccTargets()
       }
       // Add autogen target to the origin target dependencies
       this->Target->Target->AddUtility(ccName, makefile);
+
+      // Add autogen target to the global autogen target dependencies
+      if (this->Rcc.GlobalTarget) {
+        this->GlobalInitializer->AddToGlobalAutoRcc(localGen, ccName);
+      }
     } else {
       // Create custom rcc command
       {

+ 8 - 2
Source/cmQtAutoGenInitializer.h

@@ -13,6 +13,7 @@
 
 class cmGeneratorTarget;
 class cmTarget;
+class cmQtAutoGenGlobalInitializer;
 
 /// @brief Initializes the QtAutoGen generators
 class cmQtAutoGenInitializer : public cmQtAutoGen
@@ -46,9 +47,11 @@ public:
 public:
   static IntegerVersion GetQtVersion(cmGeneratorTarget const* target);
 
-  cmQtAutoGenInitializer(cmGeneratorTarget* target, bool mocEnabled,
+  cmQtAutoGenInitializer(cmQtAutoGenGlobalInitializer* globalInitializer,
+                         cmGeneratorTarget* target,
+                         IntegerVersion const& qtVersion, bool mocEnabled,
                          bool uicEnabled, bool rccEnabled,
-                         IntegerVersion const& qtVersion);
+                         bool globalAutogenTarget, bool globalAutoRccTarget);
 
   bool InitCustomTargets();
   bool SetupCustomTargets();
@@ -76,6 +79,7 @@ private:
                      std::string& errorMessage);
 
 private:
+  cmQtAutoGenGlobalInitializer* GlobalInitializer;
   cmGeneratorTarget* Target;
 
   // Configuration
@@ -100,6 +104,7 @@ private:
   struct
   {
     std::string Name;
+    bool GlobalTarget = false;
     // Settings
     std::string Parallel;
     // Configuration files
@@ -148,6 +153,7 @@ private:
   struct
   {
     bool Enabled = false;
+    bool GlobalTarget = false;
     std::string Executable;
     std::vector<std::string> ListOptions;
     std::vector<Qrc> Qrcs;

+ 1 - 0
Tests/QtAutogen/CommonTests.cmake

@@ -7,6 +7,7 @@ ADD_AUTOGEN_TEST(UicOnly uicOnly)
 ADD_AUTOGEN_TEST(RccOnly rccOnly)
 ADD_AUTOGEN_TEST(RccEmpty rccEmpty)
 ADD_AUTOGEN_TEST(RccOffMocLibrary)
+ADD_AUTOGEN_TEST(GlobalAutogenTarget)
 if(QT_TEST_ALLOW_QT_MACROS)
   ADD_AUTOGEN_TEST(MocSkipSource)
 endif()

+ 123 - 0
Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt

@@ -0,0 +1,123 @@
+cmake_minimum_required(VERSION 3.12)
+project(GlobalAutogenTarget)
+include("../AutogenTest.cmake")
+
+# This tests
+# CMAKE_GLOBAL_AUTOGEN_TARGET,
+# CMAKE_GLOBAL_AUTORCC_TARGET,
+# CMAKE_GLOBAL_AUTOGEN_TARGET_NAME and
+# CMAKE_GLOBAL_AUTORCC_TARGET_NAME
+# for the latter two with different values in different subdirectories.
+
+# Directories
+set(GAT_SDIR "${CMAKE_CURRENT_SOURCE_DIR}/GAT")
+set(GAT_BDIR "${CMAKE_CURRENT_BINARY_DIR}/GAT")
+# Files
+set(MCA "sda/sda_autogen/mocs_compilation.cpp")
+set(MCB "sdb/sdb_autogen/mocs_compilation.cpp")
+set(MCC "sdc/sdc_autogen/mocs_compilation.cpp")
+set(MCG "gat_autogen/mocs_compilation.cpp")
+
+set(DRA "sda/sda_autogen/*qrc_data.cpp")
+set(DRB "sdb/sdb_autogen/*qrc_data.cpp")
+set(DRC "sdc/sdc_autogen/*qrc_data.cpp")
+set(DRG "gat_autogen/*qrc_data.cpp")
+
+# -- Utility macros
+macro(GAT_FIND_FILES VAR NAME)
+    file(GLOB_RECURSE ${VAR} ${GAT_BDIR}/*${NAME})
+endmacro()
+
+macro(GAT_FIND_FILE NAME)
+    GAT_FIND_FILES(LST ${NAME})
+    if(LST)
+        message("Good find ${LST}")
+    else()
+        message(SEND_ERROR "Expected to find ${GAT_BDIR}/${NAME}")
+    endif()
+    unset(LST)
+endmacro()
+
+macro(GAT_FIND_FILE_NOT NAME)
+    GAT_FIND_FILES(LST ${NAME})
+    if(LST)
+        message(SEND_ERROR "Not expected to find ${GAT_BDIR}/${NAME}")
+    else()
+        message("Good not find ${GAT_BDIR}/${NAME}")
+    endif()
+    unset(LST)
+endmacro()
+
+macro(GAT_BUILD_TARGET NAME)
+    message("___ Building GAT ${NAME} target ___")
+    execute_process(
+        COMMAND "${CMAKE_COMMAND}" --build "${GAT_BDIR}" --target ${NAME}
+        WORKING_DIRECTORY "${GAT_BDIR}"
+        RESULT_VARIABLE result)
+    if (result)
+      message(SEND_ERROR "Building of GAT ${NAME} target failed")
+    endif()
+endmacro()
+
+
+# -- Remove and recreate build directory
+file(REMOVE_RECURSE ${GAT_BDIR})
+file(MAKE_DIRECTORY ${GAT_BDIR})
+
+
+# -- Configure project
+message("___ Configuring GAT project ___")
+execute_process(
+    COMMAND "${CMAKE_COMMAND}" "${GAT_SDIR}"
+        "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+        "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+        "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+    WORKING_DIRECTORY "${GAT_BDIR}"
+    OUTPUT_VARIABLE output
+    RESULT_VARIABLE result)
+if (result)
+  message(SEND_ERROR "Configuring of GAT project failed")
+else()
+  message("Configuring of GAT project succeeded")
+  message("${output}")
+endif()
+
+
+# -- Build autogen subtargets
+GAT_BUILD_TARGET("autogen")
+GAT_FIND_FILE("${MCA}")
+GAT_FIND_FILE_NOT("${MCB}")
+GAT_FIND_FILE_NOT("${MCC}")
+GAT_FIND_FILE("${MCG}")
+
+GAT_BUILD_TARGET("global_autogen_sdb")
+GAT_FIND_FILE("${MCA}")
+GAT_FIND_FILE("${MCB}")
+GAT_FIND_FILE_NOT("${MCC}")
+GAT_FIND_FILE("${MCG}")
+
+GAT_BUILD_TARGET("all_autogen")
+GAT_FIND_FILE("${MCA}")
+GAT_FIND_FILE("${MCB}")
+GAT_FIND_FILE("${MCC}")
+GAT_FIND_FILE("${MCG}")
+
+
+# -- Build autorcc subtargets
+GAT_BUILD_TARGET("autorcc")
+GAT_FIND_FILE("${DRA}")
+GAT_FIND_FILE_NOT("${DRB}")
+GAT_FIND_FILE_NOT("${DRC}")
+GAT_FIND_FILE("${DRG}")
+
+GAT_BUILD_TARGET("global_autorcc_sdb")
+GAT_FIND_FILE("${DRA}")
+GAT_FIND_FILE("${DRB}")
+GAT_FIND_FILE_NOT("${DRC}")
+GAT_FIND_FILE("${DRG}")
+
+GAT_BUILD_TARGET("all_autorcc")
+GAT_FIND_FILE("${DRA}")
+GAT_FIND_FILE("${DRB}")
+GAT_FIND_FILE("${DRC}")
+GAT_FIND_FILE("${DRG}")

+ 28 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/CMakeLists.txt

@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.12)
+project(GAT)
+include("../../AutogenTest.cmake")
+
+# Include directories
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+# Enable AUTOMOC/UIC/RCC
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+# Disable ORIGN_DEPENDS and enable AUTOGEN global targets
+set(CMAKE_AUTOGEN_ORIGIN_DEPENDS OFF)
+set(CMAKE_GLOBAL_AUTOGEN_TARGET ON)
+set(CMAKE_GLOBAL_AUTORCC_TARGET ON)
+
+add_subdirectory(sda)
+add_subdirectory(sdb)
+add_subdirectory(sdc)
+
+# Add custom target that depends on all autogen/autorcc targets
+add_custom_target(all_autogen DEPENDS autogen global_autogen_sdb global_autogen_sdc)
+add_custom_target(all_autorcc DEPENDS autorcc global_autorcc_sdb global_autorcc_sdc)
+
+# Main target
+add_executable(gat data.qrc item.cpp main.cpp)
+target_link_libraries(gat ${QT_LIBRARIES})
+target_link_libraries(gat sda sdb sdc)

+ 5 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/data.qrc

@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+  <file>item.cpp</file>
+</qresource>
+</RCC>

+ 20 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/item.cpp

@@ -0,0 +1,20 @@
+#include "item.hpp"
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class MocLocal : public QObject
+{
+  Q_OBJECT;
+
+public:
+  MocLocal() = default;
+  ~MocLocal() = default;
+};
+
+void Item::go()
+{
+  Ui_View ui;
+  MocLocal obj;
+}
+
+#include "item.moc"

+ 15 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/item.hpp

@@ -0,0 +1,15 @@
+#ifndef ITEM_HPP
+#define ITEM_HPP
+
+#include <QObject>
+// Include ui_view.h in source and header
+#include <ui_view.h>
+
+class Item : public QObject
+{
+  Q_OBJECT
+  Q_SLOT
+  void go();
+};
+
+#endif

+ 15 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/main.cpp

@@ -0,0 +1,15 @@
+#include "item.hpp"
+#include "sda/sda.hpp"
+#include "sdb/sdb.hpp"
+#include "sdc/sdc.hpp"
+
+int main(int argv, char** args)
+{
+  // Object instances
+  Item item;
+  // Library calls
+  sda();
+  sdb();
+  sdc();
+  return 0;
+}

+ 2 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/CMakeLists.txt

@@ -0,0 +1,2 @@
+add_library(sda ../item.cpp ../data.qrc sda.cpp)
+target_link_libraries(sda ${QT_LIBRARIES})

+ 6 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.cpp

@@ -0,0 +1,6 @@
+#include <item.hpp>
+
+void sda()
+{
+  Item item;
+}

+ 6 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sda/sda.hpp

@@ -0,0 +1,6 @@
+#ifndef SDA_HPP
+#define SDA_HPP
+
+void sda();
+
+#endif

+ 5 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/CMakeLists.txt

@@ -0,0 +1,5 @@
+set(CMAKE_GLOBAL_AUTOGEN_TARGET_NAME "global_autogen_sdb")
+set(CMAKE_GLOBAL_AUTORCC_TARGET_NAME "global_autorcc_sdb")
+
+add_library(sdb ../item.cpp ../data.qrc sdb.cpp)
+target_link_libraries(sdb ${QT_LIBRARIES})

+ 6 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.cpp

@@ -0,0 +1,6 @@
+#include <item.hpp>
+
+void sdb()
+{
+  Item item;
+}

+ 6 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sdb/sdb.hpp

@@ -0,0 +1,6 @@
+#ifndef SDB_HPP
+#define SDB_HPP
+
+void sdb();
+
+#endif

+ 5 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/CMakeLists.txt

@@ -0,0 +1,5 @@
+set(CMAKE_GLOBAL_AUTOGEN_TARGET_NAME "global_autogen_sdc")
+set(CMAKE_GLOBAL_AUTORCC_TARGET_NAME "global_autorcc_sdc")
+
+add_library(sdc ../item.cpp ../data.qrc sdc.cpp)
+target_link_libraries(sdc ${QT_LIBRARIES})

+ 6 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.cpp

@@ -0,0 +1,6 @@
+#include <item.hpp>
+
+void sdc()
+{
+  Item item;
+}

+ 6 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/sdc/sdc.hpp

@@ -0,0 +1,6 @@
+#ifndef SDC_HPP
+#define SDC_HPP
+
+void sdc();
+
+#endif

+ 24 - 0
Tests/QtAutogen/GlobalAutogenTarget/GAT/view.ui

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>View</class>
+ <widget class="QWidget" name="Base">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <widget class="QTreeView" name="treeView"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>