| /* 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 <set> | 
 | #include <utility> | 
 |  | 
 | #include <cm/memory> | 
 |  | 
 | #include "cmCustomCommand.h" | 
 | #include "cmDuration.h" | 
 | #include "cmGeneratorTarget.h" | 
 | #include "cmLocalGenerator.h" | 
 | #include "cmMakefile.h" | 
 | #include "cmMessageType.h" | 
 | #include "cmPolicies.h" | 
 | #include "cmProcessOutput.h" | 
 | #include "cmQtAutoGen.h" | 
 | #include "cmQtAutoGenInitializer.h" | 
 | #include "cmState.h" | 
 | #include "cmStateTypes.h" | 
 | #include "cmStringAlgorithms.h" | 
 | #include "cmSystemTools.h" | 
 | #include "cmTarget.h" | 
 | #include "cmValue.h" | 
 |  | 
 | cmQtAutoGenGlobalInitializer::Keywords::Keywords() | 
 |   : AUTOMOC("AUTOMOC") | 
 |   , AUTOUIC("AUTOUIC") | 
 |   , AUTORCC("AUTORCC") | 
 |   , AUTOMOC_EXECUTABLE("AUTOMOC_EXECUTABLE") | 
 |   , AUTOUIC_EXECUTABLE("AUTOUIC_EXECUTABLE") | 
 |   , AUTORCC_EXECUTABLE("AUTORCC_EXECUTABLE") | 
 |   , SKIP_AUTOGEN("SKIP_AUTOGEN") | 
 |   , SKIP_AUTOMOC("SKIP_AUTOMOC") | 
 |   , SKIP_AUTOUIC("SKIP_AUTOUIC") | 
 |   , SKIP_AUTORCC("SKIP_AUTORCC") | 
 |   , AUTOUIC_OPTIONS("AUTOUIC_OPTIONS") | 
 |   , AUTORCC_OPTIONS("AUTORCC_OPTIONS") | 
 |   , qrc("qrc") | 
 |   , ui("ui") | 
 | { | 
 | } | 
 |  | 
 | cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( | 
 |   std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators) | 
 | { | 
 |   for (const auto& 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 (makefile->IsOn("CMAKE_GLOBAL_AUTOGEN_TARGET")) { | 
 |         std::string targetName = | 
 |           makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME"); | 
 |         if (targetName.empty()) { | 
 |           targetName = "autogen"; | 
 |         } | 
 |         this->GlobalAutoGenTargets_.emplace(localGen.get(), | 
 |                                             std::move(targetName)); | 
 |         globalAutoGenTarget = true; | 
 |       } | 
 |  | 
 |       // Detect global autorcc target name | 
 |       if (makefile->IsOn("CMAKE_GLOBAL_AUTORCC_TARGET")) { | 
 |         std::string targetName = | 
 |           makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME"); | 
 |         if (targetName.empty()) { | 
 |           targetName = "autorcc"; | 
 |         } | 
 |         this->GlobalAutoRccTargets_.emplace(localGen.get(), | 
 |                                             std::move(targetName)); | 
 |         globalAutoRccTarget = true; | 
 |       } | 
 |     } | 
 |  | 
 |     // Find targets that require AUTOMOC/UIC/RCC processing | 
 |     for (const auto& 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; | 
 |       } | 
 |       std::set<std::string> const& languages = | 
 |         target->GetAllConfigCompileLanguages(); | 
 |       // cmGeneratorTarget::GetAllConfigCompileLanguages caches the target's | 
 |       // sources. Clear it so that OBJECT library targets that are AUTOGEN | 
 |       // initialized after this target get their added mocs_compilation.cpp | 
 |       // source acknowledged by this target. | 
 |       target->ClearSourcesCache(); | 
 |       if (languages.count("CSharp")) { | 
 |         // Don't process target if it's a CSharp target | 
 |         continue; | 
 |       } | 
 |  | 
 |       bool const moc = target->GetPropertyAsBool(this->kw().AUTOMOC); | 
 |       bool const uic = target->GetPropertyAsBool(this->kw().AUTOUIC); | 
 |       bool const rcc = target->GetPropertyAsBool(this->kw().AUTORCC); | 
 |       if (moc || uic || rcc) { | 
 |         std::string const& mocExec = | 
 |           target->GetSafeProperty(this->kw().AUTOMOC_EXECUTABLE); | 
 |         std::string const& uicExec = | 
 |           target->GetSafeProperty(this->kw().AUTOUIC_EXECUTABLE); | 
 |         std::string const& rccExec = | 
 |           target->GetSafeProperty(this->kw().AUTORCC_EXECUTABLE); | 
 |  | 
 |         // We support Qt4, Qt5 and Qt6 | 
 |         auto qtVersion = | 
 |           cmQtAutoGenInitializer::GetQtVersion(target.get(), mocExec); | 
 |         bool const validQt = (qtVersion.first.Major == 4) || | 
 |           (qtVersion.first.Major == 5) || (qtVersion.first.Major == 6); | 
 |  | 
 |         bool const mocAvailable = (validQt || !mocExec.empty()); | 
 |         bool const uicAvailable = (validQt || !uicExec.empty()); | 
 |         bool const rccAvailable = (validQt || !rccExec.empty()); | 
 |         bool const mocIsValid = (moc && mocAvailable); | 
 |         bool const uicIsValid = (uic && uicAvailable); | 
 |         bool const rccIsValid = (rcc && rccAvailable); | 
 |         // Disabled AUTOMOC/UIC/RCC warning | 
 |         bool const mocDisabled = (moc && !mocAvailable); | 
 |         bool const uicDisabled = (uic && !uicAvailable); | 
 |         bool const rccDisabled = (rcc && !rccAvailable); | 
 |         if (mocDisabled || uicDisabled || rccDisabled) { | 
 |           cmAlphaNum version = (qtVersion.second == 0) | 
 |             ? cmAlphaNum("<QTVERSION>") | 
 |             : cmAlphaNum(qtVersion.second); | 
 |           cmAlphaNum component = uicDisabled ? "Widgets" : "Core"; | 
 |  | 
 |           std::string const msg = cmStrCat( | 
 |             "AUTOGEN: No valid Qt version found for target ", | 
 |             target->GetName(), ".  ", | 
 |             cmQtAutoGen::Tools(mocDisabled, uicDisabled, rccDisabled), | 
 |             " disabled.  Consider adding:\n", "  find_package(Qt", version, | 
 |             " COMPONENTS ", component, ")\n", "to your CMakeLists.txt file."); | 
 |           target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg); | 
 |         } | 
 |         if (mocIsValid || uicIsValid || rccIsValid) { | 
 |           // Create autogen target initializer | 
 |           this->Initializers_.emplace_back( | 
 |             cm::make_unique<cmQtAutoGenInitializer>( | 
 |               this, target.get(), qtVersion.first, mocIsValid, uicIsValid, | 
 |               rccIsValid, globalAutoGenTarget, globalAutoRccTarget)); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | cmQtAutoGenGlobalInitializer::~cmQtAutoGenGlobalInitializer() = default; | 
 |  | 
 | 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 | 
 |     auto cc = cm::make_unique<cmCustomCommand>(); | 
 |     cc->SetWorkingDirectory(makefile->GetHomeOutputDirectory().c_str()); | 
 |     cc->SetCMP0116Status(cmPolicies::NEW); | 
 |     cc->SetEscapeOldStyle(false); | 
 |     cc->SetComment(comment.c_str()); | 
 |     cmTarget* target = localGen->AddUtilityCommand(name, true, std::move(cc)); | 
 |     localGen->AddGeneratorTarget( | 
 |       cm::make_unique<cmGeneratorTarget>(target, localGen)); | 
 |  | 
 |     // Set FOLDER property in the target | 
 |     { | 
 |       cmValue folder = | 
 |         makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); | 
 |       if (folder) { | 
 |         target->SetProperty("FOLDER", folder); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen( | 
 |   cmLocalGenerator* localGen, std::string const& targetName) | 
 | { | 
 |   auto it = this->GlobalAutoGenTargets_.find(localGen); | 
 |   if (it != this->GlobalAutoGenTargets_.end()) { | 
 |     cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second); | 
 |     if (target != nullptr) { | 
 |       target->Target->AddUtility(targetName, false, localGen->GetMakefile()); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc( | 
 |   cmLocalGenerator* localGen, std::string const& targetName) | 
 | { | 
 |   auto it = this->GlobalAutoRccTargets_.find(localGen); | 
 |   if (it != this->GlobalAutoRccTargets_.end()) { | 
 |     cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second); | 
 |     if (target != nullptr) { | 
 |       target->Target->AddUtility(targetName, false, localGen->GetMakefile()); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | cmQtAutoGen::CompilerFeaturesHandle | 
 | cmQtAutoGenGlobalInitializer::GetCompilerFeatures( | 
 |   std::string const& generator, std::string const& executable, | 
 |   std::string& error) | 
 | { | 
 |   // Check if we have cached features | 
 |   { | 
 |     auto it = this->CompilerFeatures_.find(executable); | 
 |     if (it != this->CompilerFeatures_.end()) { | 
 |       return it->second; | 
 |     } | 
 |   } | 
 |  | 
 |   // Check if the executable exists | 
 |   if (!cmSystemTools::FileExists(executable, true)) { | 
 |     error = cmStrCat("The \"", generator, "\" executable ", | 
 |                      cmQtAutoGen::Quoted(executable), " does not exist."); | 
 |     return cmQtAutoGen::CompilerFeaturesHandle(); | 
 |   } | 
 |  | 
 |   // Test the executable | 
 |   std::string stdOut; | 
 |   { | 
 |     std::string stdErr; | 
 |     std::vector<std::string> command; | 
 |     command.emplace_back(executable); | 
 |     command.emplace_back("-h"); | 
 |     int retVal = 0; | 
 |     const bool runResult = cmSystemTools::RunSingleCommand( | 
 |       command, &stdOut, &stdErr, &retVal, nullptr, cmSystemTools::OUTPUT_NONE, | 
 |       cmDuration::zero(), cmProcessOutput::Auto); | 
 |     if (!runResult) { | 
 |       error = cmStrCat("Test run of \"", generator, "\" executable ", | 
 |                        cmQtAutoGen::Quoted(executable), " failed.\n", | 
 |                        cmQtAutoGen::QuotedCommand(command), '\n', stdOut, '\n', | 
 |                        stdErr); | 
 |       return cmQtAutoGen::CompilerFeaturesHandle(); | 
 |     } | 
 |   } | 
 |  | 
 |   // Create valid handle | 
 |   cmQtAutoGen::CompilerFeaturesHandle res = | 
 |     std::make_shared<cmQtAutoGen::CompilerFeatures>(); | 
 |   res->HelpOutput = std::move(stdOut); | 
 |  | 
 |   // Register compiler features | 
 |   this->CompilerFeatures_.emplace(executable, res); | 
 |  | 
 |   return res; | 
 | } | 
 |  | 
 | bool cmQtAutoGenGlobalInitializer::generate() | 
 | { | 
 |   return (this->InitializeCustomTargets() && this->SetupCustomTargets()); | 
 | } | 
 |  | 
 | bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets() | 
 | { | 
 |   // Initialize global autogen targets | 
 |   { | 
 |     std::string const comment = "Global AUTOGEN target"; | 
 |     for (auto const& pair : this->GlobalAutoGenTargets_) { | 
 |       this->GetOrCreateGlobalTarget(pair.first, pair.second, comment); | 
 |     } | 
 |   } | 
 |   // Initialize global autorcc targets | 
 |   { | 
 |     std::string const comment = "Global AUTORCC target"; | 
 |     for (auto const& pair : this->GlobalAutoRccTargets_) { | 
 |       this->GetOrCreateGlobalTarget(pair.first, pair.second, comment); | 
 |     } | 
 |   } | 
 |   // Initialize per target autogen targets | 
 |   for (auto& initializer : this->Initializers_) { | 
 |     if (!initializer->InitCustomTargets()) { | 
 |       return false; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool cmQtAutoGenGlobalInitializer::SetupCustomTargets() | 
 | { | 
 |   for (auto& initializer : this->Initializers_) { | 
 |     if (!initializer->SetupCustomTargets()) { | 
 |       return false; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } |