| /* 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; |
| } |