소스 검색

Autogen: Add AUTO(MOC|RCC|UIC)_EXECUTABLE target properties

Allow to force moc/rcc/uic compiler used for AUTO(MOC|RCC|UIC).

Setting these properties is only necessary if you are going to do
strange things like build these tools as part of your own build system.

Setting these properties will also prevent cmake from testing the
binary: It is user-provided and assumed to be valid.
Tobias Hunger 7 년 전
부모
커밋
cd32886b2f

+ 3 - 0
Help/manual/cmake-properties.7.rst

@@ -129,13 +129,16 @@ Properties on Targets
    /prop_tgt/AUTOGEN_TARGET_DEPENDS
    /prop_tgt/AUTOGEN_TARGET_DEPENDS
    /prop_tgt/AUTOMOC_COMPILER_PREDEFINES
    /prop_tgt/AUTOMOC_COMPILER_PREDEFINES
    /prop_tgt/AUTOMOC_DEPEND_FILTERS
    /prop_tgt/AUTOMOC_DEPEND_FILTERS
+   /prop_tgt/AUTOMOC_EXECUTABLE
    /prop_tgt/AUTOMOC_MACRO_NAMES
    /prop_tgt/AUTOMOC_MACRO_NAMES
    /prop_tgt/AUTOMOC_MOC_OPTIONS
    /prop_tgt/AUTOMOC_MOC_OPTIONS
    /prop_tgt/AUTOMOC
    /prop_tgt/AUTOMOC
    /prop_tgt/AUTOUIC
    /prop_tgt/AUTOUIC
+   /prop_tgt/AUTOUIC_EXECUTABLE
    /prop_tgt/AUTOUIC_OPTIONS
    /prop_tgt/AUTOUIC_OPTIONS
    /prop_tgt/AUTOUIC_SEARCH_PATHS
    /prop_tgt/AUTOUIC_SEARCH_PATHS
    /prop_tgt/AUTORCC
    /prop_tgt/AUTORCC
+   /prop_tgt/AUTORCC_EXECUTABLE
    /prop_tgt/AUTORCC_OPTIONS
    /prop_tgt/AUTORCC_OPTIONS
    /prop_tgt/BINARY_DIR
    /prop_tgt/BINARY_DIR
    /prop_tgt/BUILD_RPATH
    /prop_tgt/BUILD_RPATH

+ 3 - 0
Help/prop_tgt/AUTOMOC.rst

@@ -58,6 +58,9 @@ source files at build time and invoke moc accordingly.
 This property is initialized by the value of the :variable:`CMAKE_AUTOMOC`
 This property is initialized by the value of the :variable:`CMAKE_AUTOMOC`
 variable if it is set when a target is created.
 variable if it is set when a target is created.
 
 
+The ``moc`` executable will be detected automatically, but can be forced to
+a certain binary using the :prop_tgt:`AUTOMOC_EXECUTABLE` property.
+
 Additional command line options for ``moc`` can be set via the
 Additional command line options for ``moc`` can be set via the
 :prop_tgt:`AUTOMOC_MOC_OPTIONS` property.
 :prop_tgt:`AUTOMOC_MOC_OPTIONS` property.
 
 

+ 15 - 0
Help/prop_tgt/AUTOMOC_EXECUTABLE.rst

@@ -0,0 +1,15 @@
+AUTOMOC_EXECUTABLE
+------------------
+
+:prop_tgt:`AUTOMOC_EXECUTABLE` is file path pointing to the ``moc``
+executable to use for :prop_tgt:`AUTOMOC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``moc`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``moc`` can not work -- e.g. because
+you are building the ``moc`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.

+ 3 - 0
Help/prop_tgt/AUTORCC.rst

@@ -21,6 +21,9 @@ If the ``.qrc`` file is :prop_sf:`GENERATED` though, a
 Additional command line options for rcc can be set via the
 Additional command line options for rcc can be set via the
 :prop_sf:`AUTORCC_OPTIONS` source file property on the ``.qrc`` file.
 :prop_sf:`AUTORCC_OPTIONS` source file property on the ``.qrc`` file.
 
 
+The ``rcc`` executable will be detected automatically, but can be forced to
+a certain binary using the :prop_tgt:`AUTORCC_EXECUTABLE` property.
+
 The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group
 The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group
 the autorcc targets together in an IDE, e.g. in MSVS.
 the autorcc targets together in an IDE, e.g. in MSVS.
 
 

+ 15 - 0
Help/prop_tgt/AUTORCC_EXECUTABLE.rst

@@ -0,0 +1,15 @@
+AUTORCC_EXECUTABLE
+------------------
+
+:prop_tgt:`AUTORCC_EXECUTABLE` is file path pointing to the ``rcc``
+executable to use for :prop_tgt:`AUTORCC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``rcc`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``rcc`` can not work -- e.g. because
+you are building the ``rcc`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.

+ 3 - 0
Help/prop_tgt/AUTOUIC.rst

@@ -30,6 +30,9 @@ Additional command line options for ``uic`` can be set via the
 The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the
 The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the
 autouic targets together in an IDE, e.g. in MSVS.
 autouic targets together in an IDE, e.g. in MSVS.
 
 
+The ``uic`` executable will be detected automatically, but can be forced to
+a certain binary using the :prop_tgt:`AUTOUIC_EXECUTABLE` property.
+
 Source files can be excluded from :prop_tgt:`AUTOUIC` processing by
 Source files can be excluded from :prop_tgt:`AUTOUIC` processing by
 enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`.
 enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`.
 
 

+ 15 - 0
Help/prop_tgt/AUTOUIC_EXECUTABLE.rst

@@ -0,0 +1,15 @@
+AUTOUIC_EXECUTABLE
+------------------
+
+:prop_tgt:`AUTOUIC_EXECUTABLE` is file path pointing to the ``uic``
+executable to use for :prop_tgt:`AUTOUIC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``uic`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``uic`` can not work -- e.g. because
+you are building the ``uic`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.

+ 9 - 0
Help/release/dev/autogen_executables.rst

@@ -0,0 +1,9 @@
+AUTO*_EXECUTABLE
+----------------
+
+* The :prop_tgt:`AUTOMOC_EXECUTABLE`, :prop_tgt:`AUTORCC_EXECUTABLE` and
+  :prop_tgt:`AUTOUIC_EXECUTABLE` target properties all take a path to an
+  executable and force automoc/autorcc/autouic to use this executable.
+
+  Setting these will also prevent the configure time testing for these
+  executables. This is mainly useful when you build these tools yourself.

+ 17 - 5
Source/cmQtAutoGenGlobalInitializer.cxx

@@ -75,14 +75,26 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
       bool const uic = target->GetPropertyAsBool("AUTOUIC");
       bool const uic = target->GetPropertyAsBool("AUTOUIC");
       bool const rcc = target->GetPropertyAsBool("AUTORCC");
       bool const rcc = target->GetPropertyAsBool("AUTORCC");
       if (moc || uic || rcc) {
       if (moc || uic || rcc) {
-        // We support Qt4 and Qt5
+        std::string const mocExec =
+          target->GetSafeProperty("AUTOMOC_EXECUTABLE");
+        std::string const uicExec =
+          target->GetSafeProperty("AUTOUIC_EXECUTABLE");
+        std::string const rccExec =
+          target->GetSafeProperty("AUTORCC_EXECUTABLE");
+
+        // We support Qt4, Qt5 and Qt6
         auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
         auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
-        if ((qtVersion.Major == 4) || (qtVersion.Major == 5) ||
-            (qtVersion.Major == 6)) {
+        bool const validQt = (qtVersion.Major == 4) ||
+          (qtVersion.Major == 5) || (qtVersion.Major == 6);
+        bool const mocIsValid = moc && (validQt || !mocExec.empty());
+        bool const uicIsValid = uic && (validQt || !uicExec.empty());
+        bool const rccIsValid = rcc && (validQt || !rccExec.empty());
+
+        if (mocIsValid || uicIsValid || rccIsValid) {
           // Create autogen target initializer
           // Create autogen target initializer
           Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
           Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
-            this, target, qtVersion, moc, uic, rcc, globalAutoGenTarget,
-            globalAutoRccTarget));
+            this, target, qtVersion, mocIsValid, uicIsValid, rccIsValid,
+            globalAutoGenTarget, globalAutoRccTarget));
         }
         }
       }
       }
     }
     }

+ 48 - 13
Source/cmQtAutoGenInitializer.cxx

@@ -9,6 +9,7 @@
 #include "cmCustomCommandLines.h"
 #include "cmCustomCommandLines.h"
 #include "cmDuration.h"
 #include "cmDuration.h"
 #include "cmFilePathChecksum.h"
 #include "cmFilePathChecksum.h"
+#include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGenerator.h"
 #include "cmLinkItem.h"
 #include "cmLinkItem.h"
@@ -398,8 +399,16 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
     }
     }
 
 
     // Init uic specific settings
     // Init uic specific settings
-    if (this->Uic.Enabled && !InitUic()) {
-      return false;
+    if (this->Uic.Enabled) {
+      if (InitUic()) {
+        auto* uicTarget = makefile->FindTargetToUse(
+          GetQtExecutableTargetName(this->QtVersion, "uic"));
+        if (uicTarget != nullptr) {
+          this->AutogenTarget.DependTargets.insert(uicTarget);
+        }
+      } else {
+        return false;
+      }
     }
     }
 
 
     // Autogen target name
     // Autogen target name
@@ -440,6 +449,12 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
       this->AutogenTarget.DependOrigin =
       this->AutogenTarget.DependOrigin =
         this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
         this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
 
 
+      auto* mocTarget = makefile->FindTargetToUse(
+        GetQtExecutableTargetName(this->QtVersion, "moc"));
+      if (mocTarget != nullptr) {
+        this->AutogenTarget.DependTargets.insert(mocTarget);
+      }
+
       std::string const deps =
       std::string const deps =
         this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
         this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
       if (!deps.empty()) {
       if (!deps.empty()) {
@@ -1095,6 +1110,7 @@ bool cmQtAutoGenInitializer::InitRccTargets()
 {
 {
   cmMakefile* makefile = this->Target->Target->GetMakefile();
   cmMakefile* makefile = this->Target->Target->GetMakefile();
   cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
   cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
+  auto rccTargetName = GetQtExecutableTargetName(this->QtVersion, "rcc");
 
 
   for (Qrc const& qrc : this->Rcc.Qrcs) {
   for (Qrc const& qrc : this->Rcc.Qrcs) {
     // Register info file as generated by CMake
     // Register info file as generated by CMake
@@ -1105,6 +1121,11 @@ bool cmQtAutoGenInitializer::InitRccTargets()
     std::vector<std::string> ccOutput;
     std::vector<std::string> ccOutput;
     ccOutput.push_back(qrc.RccFile);
     ccOutput.push_back(qrc.RccFile);
 
 
+    std::vector<std::string> ccDepends;
+    // Add the .qrc and info file to the custom command dependencies
+    ccDepends.push_back(qrc.QrcFile);
+    ccDepends.push_back(qrc.InfoFile);
+
     cmCustomCommandLines commandLines;
     cmCustomCommandLines commandLines;
     if (this->MultiConfig) {
     if (this->MultiConfig) {
       // Build for all configurations
       // Build for all configurations
@@ -1140,15 +1161,12 @@ bool cmQtAutoGenInitializer::InitRccTargets()
           ccName += "_";
           ccName += "_";
           ccName += qrc.PathChecksum;
           ccName += qrc.PathChecksum;
         }
         }
-        std::vector<std::string> ccDepends;
-        // Add the .qrc and info file to the custom target dependencies
-        ccDepends.push_back(qrc.QrcFile);
-        ccDepends.push_back(qrc.InfoFile);
 
 
         cmTarget* autoRccTarget = makefile->AddUtilityCommand(
         cmTarget* autoRccTarget = makefile->AddUtilityCommand(
           ccName, cmMakefile::TargetOrigin::Generator, true,
           ccName, cmMakefile::TargetOrigin::Generator, true,
           this->Dir.Work.c_str(), ccOutput, ccDepends, commandLines, false,
           this->Dir.Work.c_str(), ccOutput, ccDepends, commandLines, false,
           ccComment.c_str());
           ccComment.c_str());
+
         // Create autogen generator target
         // Create autogen generator target
         localGen->AddGeneratorTarget(
         localGen->AddGeneratorTarget(
           new cmGeneratorTarget(autoRccTarget, localGen));
           new cmGeneratorTarget(autoRccTarget, localGen));
@@ -1157,6 +1175,9 @@ bool cmQtAutoGenInitializer::InitRccTargets()
         if (!this->TargetsFolder.empty()) {
         if (!this->TargetsFolder.empty()) {
           autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str());
           autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str());
         }
         }
+        if (!rccTargetName.empty()) {
+          autoRccTarget->AddUtility(rccTargetName, makefile);
+        }
       }
       }
       // Add autogen target to the origin target dependencies
       // Add autogen target to the origin target dependencies
       this->Target->Target->AddUtility(ccName, makefile);
       this->Target->Target->AddUtility(ccName, makefile);
@@ -1169,16 +1190,15 @@ bool cmQtAutoGenInitializer::InitRccTargets()
       // Create custom rcc command
       // Create custom rcc command
       {
       {
         std::vector<std::string> ccByproducts;
         std::vector<std::string> ccByproducts;
-        std::vector<std::string> ccDepends;
-        // Add the .qrc and info file to the custom command dependencies
-        ccDepends.push_back(qrc.QrcFile);
-        ccDepends.push_back(qrc.InfoFile);
 
 
         // Add the resource files to the dependencies
         // Add the resource files to the dependencies
         for (std::string const& fileName : qrc.Resources) {
         for (std::string const& fileName : qrc.Resources) {
           // Add resource file to the custom command dependencies
           // Add resource file to the custom command dependencies
           ccDepends.push_back(fileName);
           ccDepends.push_back(fileName);
         }
         }
+        if (!rccTargetName.empty()) {
+          ccDepends.push_back(rccTargetName);
+        }
         makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends,
         makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends,
                                            /*main_dependency*/ std::string(),
                                            /*main_dependency*/ std::string(),
                                            commandLines, ccComment.c_str(),
                                            commandLines, ccComment.c_str(),
@@ -1421,21 +1441,36 @@ std::pair<bool, std::string> GetQtExecutable(
   const cmQtAutoGen::IntegerVersion& qtVersion, cmGeneratorTarget* target,
   const cmQtAutoGen::IntegerVersion& qtVersion, cmGeneratorTarget* target,
   const std::string& executable, bool ignoreMissingTarget, std::string* output)
   const std::string& executable, bool ignoreMissingTarget, std::string* output)
 {
 {
+  const std::string upperExecutable = cmSystemTools::UpperCase(executable);
+  std::string result =
+    target->Target->GetSafeProperty("AUTO" + upperExecutable + "_EXECUTABLE");
+  if (!result.empty()) {
+    cmListFileBacktrace lfbt = target->Target->GetMakefile()->GetBacktrace();
+    cmGeneratorExpression ge(lfbt);
+    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(result);
+    result = cge->Evaluate(target->GetLocalGenerator(), "");
+
+    return std::make_pair(true, result);
+  }
+
   std::string err;
   std::string err;
-  std::string result;
 
 
   // Find executable
   // Find executable
   {
   {
     const std::string targetName =
     const std::string targetName =
       GetQtExecutableTargetName(qtVersion, executable);
       GetQtExecutableTargetName(qtVersion, executable);
     if (targetName.empty()) {
     if (targetName.empty()) {
-      err = "The AUTOMOC, AUTOUIC and AUTORCC feature ";
+      err = "The AUTO" + upperExecutable + " feature ";
       err += "supports only Qt 4, Qt 5 and Qt 6.";
       err += "supports only Qt 4, Qt 5 and Qt 6.";
     } else {
     } else {
       cmLocalGenerator* localGen = target->GetLocalGenerator();
       cmLocalGenerator* localGen = target->GetLocalGenerator();
       cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName);
       cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName);
       if (tgt != nullptr) {
       if (tgt != nullptr) {
-        result = tgt->ImportedGetLocation("");
+        if (tgt->IsImported()) {
+          result = tgt->ImportedGetLocation("");
+        } else {
+          result = tgt->GetLocation("");
+        }
       } else {
       } else {
         if (ignoreMissingTarget) {
         if (ignoreMissingTarget) {
           return std::make_pair(true, "");
           return std::make_pair(true, "");