From 9cfa213aa62e8a7b73fd0ba63e6e80ba86082e52 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Wed, 17 Jan 2018 17:21:57 +0100 Subject: Autogen: Rename cmQtAutogeneratorInitializer to cmQtAutoGenInitializer --- Source/CMakeLists.txt | 4 +- Source/cmGlobalGenerator.cxx | 10 +- Source/cmGlobalGenerator.h | 4 +- Source/cmQtAutoGenInitializer.cxx | 1461 +++++++++++++++++++++++++++++++ Source/cmQtAutoGenInitializer.h | 102 +++ Source/cmQtAutoGeneratorInitializer.cxx | 1461 ------------------------------- Source/cmQtAutoGeneratorInitializer.h | 102 --- 7 files changed, 1572 insertions(+), 1572 deletions(-) create mode 100644 Source/cmQtAutoGenInitializer.cxx create mode 100644 Source/cmQtAutoGenInitializer.h delete mode 100644 Source/cmQtAutoGeneratorInitializer.cxx delete mode 100644 Source/cmQtAutoGeneratorInitializer.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1b46377..cd1287c 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -313,8 +313,8 @@ set(SRCS cmQtAutoGen.h cmQtAutoGenerator.cxx cmQtAutoGenerator.h - cmQtAutoGeneratorInitializer.cxx - cmQtAutoGeneratorInitializer.h + cmQtAutoGenInitializer.cxx + cmQtAutoGenInitializer.h cmQtAutoGeneratorMocUic.cxx cmQtAutoGeneratorMocUic.h cmQtAutoGeneratorRcc.cxx diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index fd9b488..47a9390 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -33,7 +33,7 @@ #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmPolicies.h" -#include "cmQtAutoGeneratorInitializer.h" +#include "cmQtAutoGenInitializer.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -1473,10 +1473,10 @@ bool cmGlobalGenerator::ComputeTargetDepends() return true; } -std::vector> +std::vector> cmGlobalGenerator::CreateQtAutoGenInitializers() { - std::vector> autogenInits; + std::vector> autogenInits; #ifdef CMAKE_BUILD_WITH_CMAKE for (cmLocalGenerator* localGen : this->LocalGenerators) { @@ -1506,13 +1506,13 @@ cmGlobalGenerator::CreateQtAutoGenInitializers() } std::string qtVersionMajor = - cmQtAutoGeneratorInitializer::GetQtMajorVersion(target); + cmQtAutoGenInitializer::GetQtMajorVersion(target); // don't do anything if there is no Qt4 or Qt5Core (which contains moc) if (qtVersionMajor != "4" && qtVersionMajor != "5") { continue; } - autogenInits.emplace_back(new cmQtAutoGeneratorInitializer( + autogenInits.emplace_back(new cmQtAutoGenInitializer( target, mocEnabled, uicEnabled, rccEnabled, qtVersionMajor)); } } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 92e6a29..3ebff82 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -32,7 +32,7 @@ class cmLinkLineComputer; class cmLocalGenerator; class cmMakefile; class cmOutputConverter; -class cmQtAutoGeneratorInitializer; +class cmQtAutoGenInitializer; class cmSourceFile; class cmStateDirectory; class cmake; @@ -437,7 +437,7 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; // Qt auto generators - std::vector> + std::vector> CreateQtAutoGenInitializers(); std::string SelectMakeProgram(const std::string& makeProgram, diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx new file mode 100644 index 0000000..0b67981 --- /dev/null +++ b/Source/cmQtAutoGenInitializer.cxx @@ -0,0 +1,1461 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmQtAutoGen.h" +#include "cmQtAutoGenInitializer.h" + +#include "cmAlgorithms.h" +#include "cmCustomCommand.h" +#include "cmCustomCommandLines.h" +#include "cmFilePathChecksum.h" +#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmLinkItem.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmOutputConverter.h" +#include "cmPolicies.h" +#include "cmProcessOutput.h" +#include "cmSourceFile.h" +#include "cmSourceGroup.h" +#include "cmState.h" +#include "cmStateTypes.h" +#include "cmSystemTools.h" +#include "cmTarget.h" +#include "cm_sys_stat.h" +#include "cmake.h" +#include "cmsys/FStream.hxx" +#include "cmsys/SystemInformation.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +inline static const char* SafeString(const char* value) +{ + return (value != nullptr) ? value : ""; +} + +inline static std::string GetSafeProperty(cmGeneratorTarget const* target, + const char* key) +{ + return std::string(SafeString(target->GetProperty(key))); +} + +inline static std::string GetSafeProperty(cmSourceFile const* sf, + const char* key) +{ + return std::string(SafeString(sf->GetProperty(key))); +} + +static std::size_t GetParallelCPUCount() +{ + static std::size_t count = 0; + // Detect only on the first call + if (count == 0) { + cmsys::SystemInformation info; + info.RunCPUCheck(); + count = info.GetNumberOfPhysicalCPU(); + count = std::max(count, 1); + count = std::min(count, cmQtAutoGen::ParallelMax); + } + return count; +} + +static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, + std::string const& value) +{ + makefile->AddDefinition(key, + cmOutputConverter::EscapeForCMake(value).c_str()); +} + +static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, + const std::vector& values) +{ + makefile->AddDefinition( + key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); +} + +static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, + const std::set& values) +{ + makefile->AddDefinition( + key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); +} + +static void AddDefinitionEscaped( + cmMakefile* makefile, const char* key, + const std::vector>& lists) +{ + std::vector seplist; + for (const std::vector& list : lists) { + std::string blist = "{"; + blist += cmJoin(list, ";"); + blist += "}"; + seplist.push_back(std::move(blist)); + } + makefile->AddDefinition(key, cmOutputConverter::EscapeForCMake( + cmJoin(seplist, cmQtAutoGen::ListSep)) + .c_str()); +} + +static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName, + cmQtAutoGen::GeneratorT genType) +{ + cmSourceGroup* sourceGroup = nullptr; + // Acquire source group + { + std::string property; + std::string groupName; + { + std::array props; + // Use generator specific group name + switch (genType) { + case cmQtAutoGen::GeneratorT::MOC: + props[0] = "AUTOMOC_SOURCE_GROUP"; + break; + case cmQtAutoGen::GeneratorT::RCC: + props[0] = "AUTORCC_SOURCE_GROUP"; + break; + default: + props[0] = "AUTOGEN_SOURCE_GROUP"; + break; + } + props[1] = "AUTOGEN_SOURCE_GROUP"; + for (std::string& prop : props) { + const char* propName = makefile->GetState()->GetGlobalProperty(prop); + if ((propName != nullptr) && (*propName != '\0')) { + groupName = propName; + property = std::move(prop); + break; + } + } + } + // Generate a source group on demand + if (!groupName.empty()) { + sourceGroup = makefile->GetOrCreateSourceGroup(groupName); + if (sourceGroup == nullptr) { + std::ostringstream ost; + ost << cmQtAutoGen::GeneratorNameUpper(genType); + ost << ": " << property; + ost << ": Could not find or create the source group "; + ost << cmQtAutoGen::Quoted(groupName); + cmSystemTools::Error(ost.str().c_str()); + return false; + } + } + } + if (sourceGroup != nullptr) { + sourceGroup->AddGroupFile(fileName); + } + return true; +} + +static void AddCleanFile(cmMakefile* makefile, std::string const& fileName) +{ + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(), + false); +} + +static std::string FileProjectRelativePath(cmMakefile* makefile, + std::string const& fileName) +{ + std::string res; + { + std::string pSource = cmSystemTools::RelativePath( + makefile->GetCurrentSourceDirectory(), fileName.c_str()); + std::string pBinary = cmSystemTools::RelativePath( + makefile->GetCurrentBinaryDirectory(), fileName.c_str()); + if (pSource.size() < pBinary.size()) { + res = std::move(pSource); + } else if (pBinary.size() < fileName.size()) { + res = std::move(pBinary); + } else { + res = fileName; + } + } + return res; +} + +/* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its + * recursive STATIC_LIBRARY dependencies depends on targetOrigin + * (STATIC_LIBRARY cycle). + */ +static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, + cmGeneratorTarget const* targetDepend, + std::string const& config) +{ + bool cycle = false; + if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) && + (targetDepend->GetType() == cmStateEnums::STATIC_LIBRARY)) { + std::set knownLibs; + std::deque testLibs; + + // Insert initial static_library dependency + knownLibs.insert(targetDepend); + testLibs.push_back(targetDepend); + + while (!testLibs.empty()) { + cmGeneratorTarget const* testTarget = testLibs.front(); + testLibs.pop_front(); + // Check if the test target is the origin target (cycle) + if (testTarget == targetOrigin) { + cycle = true; + break; + } + // Collect all static_library dependencies from the test target + cmLinkImplementationLibraries const* libs = + testTarget->GetLinkImplementationLibraries(config); + if (libs != nullptr) { + for (cmLinkItem const& item : libs->Libraries) { + cmGeneratorTarget const* depTarget = item.Target; + if ((depTarget != nullptr) && + (depTarget->GetType() == cmStateEnums::STATIC_LIBRARY) && + knownLibs.insert(depTarget).second) { + testLibs.push_back(depTarget); + } + } + } + } + } + return cycle; +} + +cmQtAutoGenInitializer::cmQtAutoGenInitializer( + cmGeneratorTarget* target, bool mocEnabled, bool uicEnabled, bool rccEnabled, + std::string const& qtVersionMajor) + : Target(target) + , MocEnabled(mocEnabled) + , UicEnabled(uicEnabled) + , RccEnabled(rccEnabled) + , QtVersionMajor(qtVersionMajor) + , MultiConfig(MultiConfigT::WRAPPER) +{ + this->QtVersionMinor = + cmQtAutoGenInitializer::GetQtMinorVersion(target, this->QtVersionMajor); +} + +void cmQtAutoGenInitializer::InitCustomTargets() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); + + // Configurations + this->ConfigDefault = makefile->GetConfigurations(this->ConfigsList); + if (this->ConfigsList.empty()) { + this->ConfigsList.push_back(this->ConfigDefault); + } + + // Multi configuration + { + if (!globalGen->IsMultiConfig()) { + this->MultiConfig = MultiConfigT::SINGLE; + } + + // FIXME: Xcode does not support per-config sources, yet. + // (EXCLUDED_SOURCE_FILE_NAMES) + // if (globalGen->GetName().find("Xcode") != std::string::npos) { + // return MultiConfigT::MULTI; + //} + + // FIXME: Visual Studio does not support per-config sources, yet. + // (EXCLUDED_SOURCE_FILE_NAMES) + // if (globalGen->GetName().find("Visual Studio") != std::string::npos) { + // return MultiConfigT::MULTI; + //} + } + + // Autogen target name + this->AutogenTargetName = this->Target->GetName(); + this->AutogenTargetName += "_autogen"; + + // Autogen directories + { + // Collapsed current binary directory + std::string const cbd = cmSystemTools::CollapseFullPath( + "", makefile->GetCurrentBinaryDirectory()); + + // Autogen info dir + this->DirInfo = cbd; + this->DirInfo += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); + this->DirInfo += "/"; + this->DirInfo += this->AutogenTargetName; + this->DirInfo += ".dir"; + cmSystemTools::ConvertToUnixSlashes(this->DirInfo); + + // Autogen build dir + this->DirBuild = GetSafeProperty(this->Target, "AUTOGEN_BUILD_DIR"); + if (this->DirBuild.empty()) { + this->DirBuild = cbd; + this->DirBuild += "/"; + this->DirBuild += this->AutogenTargetName; + } + cmSystemTools::ConvertToUnixSlashes(this->DirBuild); + + // Working directory + this->DirWork = cbd; + cmSystemTools::ConvertToUnixSlashes(this->DirWork); + } + + // Autogen files + { + this->AutogenInfoFile = this->DirInfo; + this->AutogenInfoFile += "/AutogenInfo.cmake"; + + this->AutogenSettingsFile = this->DirInfo; + this->AutogenSettingsFile += "/AutogenOldSettings.txt"; + } + + // Autogen target FOLDER property + { + const char* folder = + makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); + if (folder == nullptr) { + folder = + makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); + } + // Inherit FOLDER property from target (#13688) + if (folder == nullptr) { + folder = SafeString(this->Target->Target->GetProperty("FOLDER")); + } + if (folder != nullptr) { + this->AutogenFolder = folder; + } + } + + std::set autogenDependFiles; + std::set autogenDependTargets; + std::vector autogenProvides; + + // Remove build directories on cleanup + AddCleanFile(makefile, this->DirBuild); + // Remove old settings on cleanup + { + std::string base = this->DirInfo; + base += "/AutogenOldSettings"; + if (this->MultiConfig == MultiConfigT::SINGLE) { + AddCleanFile(makefile, base.append(".cmake")); + } else { + for (std::string const& cfg : this->ConfigsList) { + std::string filename = base; + filename += "_"; + filename += cfg; + filename += ".cmake"; + AddCleanFile(makefile, filename); + } + } + } + + // Add moc compilation to generated files list + if (this->MocEnabled) { + std::string const mocsComp = this->DirBuild + "/mocs_compilation.cpp"; + auto files = this->AddGeneratedSource(mocsComp, GeneratorT::MOC); + for (std::string& file : files) { + autogenProvides.push_back(std::move(file)); + } + } + + // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES + if (this->MocEnabled || this->UicEnabled) { + std::string includeDir = this->DirBuild + "/include"; + if (this->MultiConfig != MultiConfigT::SINGLE) { + includeDir += "_$"; + } + this->Target->AddIncludeDirectory(includeDir, true); + } + + // Acquire rcc executable and features + if (this->RccEnabled) { + { + std::string err; + if (this->QtVersionMajor == "5") { + cmGeneratorTarget* tgt = + localGen->FindGeneratorTargetToUse("Qt5::rcc"); + if (tgt != nullptr) { + this->RccExecutable = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTORCC: Qt5::rcc target not found"; + } + } else if (QtVersionMajor == "4") { + cmGeneratorTarget* tgt = + localGen->FindGeneratorTargetToUse("Qt4::rcc"); + if (tgt != nullptr) { + this->RccExecutable = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTORCC: Qt4::rcc target not found"; + } + } else { + err = "The AUTORCC feature supports only Qt 4 and Qt 5"; + } + if (!err.empty()) { + err += " ("; + err += this->Target->GetName(); + err += ")"; + cmSystemTools::Error(err.c_str()); + } + } + // Detect if rcc supports (-)-list + if (!this->RccExecutable.empty() && (this->QtVersionMajor == "5")) { + std::vector command; + command.push_back(this->RccExecutable); + command.push_back("--help"); + std::string rccStdOut; + std::string rccStdErr; + int retVal = 0; + bool result = cmSystemTools::RunSingleCommand( + command, &rccStdOut, &rccStdErr, &retVal, nullptr, + cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); + if (result && retVal == 0 && + rccStdOut.find("--list") != std::string::npos) { + this->RccListOptions.push_back("--list"); + } else { + this->RccListOptions.push_back("-list"); + } + } + } + + // Extract relevant source files + std::vector generatedSources; + std::vector generatedHeaders; + { + std::string const qrcExt = "qrc"; + std::vector srcFiles; + this->Target->GetConfigCommonSourceFiles(srcFiles); + for (cmSourceFile* sf : srcFiles) { + if (sf->GetPropertyAsBool("SKIP_AUTOGEN")) { + continue; + } + // sf->GetExtension() is only valid after sf->GetFullPath() ... + std::string const& fPath = sf->GetFullPath(); + std::string const& ext = sf->GetExtension(); + // Register generated files that will be scanned by moc or uic + if (this->MocEnabled || this->UicEnabled) { + cmSystemTools::FileFormat const fileType = + cmSystemTools::GetFileFormat(ext.c_str()); + if ((fileType == cmSystemTools::CXX_FILE_FORMAT) || + (fileType == cmSystemTools::HEADER_FILE_FORMAT)) { + std::string const absPath = cmSystemTools::GetRealPath(fPath); + if ((this->MocEnabled && !sf->GetPropertyAsBool("SKIP_AUTOMOC")) || + (this->UicEnabled && !sf->GetPropertyAsBool("SKIP_AUTOUIC"))) { + // Register source + const bool generated = sf->GetPropertyAsBool("GENERATED"); + if (fileType == cmSystemTools::HEADER_FILE_FORMAT) { + if (generated) { + generatedHeaders.push_back(absPath); + } else { + this->Headers.push_back(absPath); + } + } else { + if (generated) { + generatedSources.push_back(absPath); + } else { + this->Sources.push_back(absPath); + } + } + } + } + } + // Register rcc enabled files + if (this->RccEnabled && (ext == qrcExt) && + !sf->GetPropertyAsBool("SKIP_AUTORCC")) { + // Register qrc file + { + Qrc qrc; + qrc.QrcFile = cmSystemTools::GetRealPath(fPath); + qrc.QrcName = + cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile); + qrc.Generated = sf->GetPropertyAsBool("GENERATED"); + // RCC options + { + std::string const opts = GetSafeProperty(sf, "AUTORCC_OPTIONS"); + if (!opts.empty()) { + cmSystemTools::ExpandListArgument(opts, qrc.Options); + } + } + this->Qrcs.push_back(std::move(qrc)); + } + } + } + // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's + // sources meta data cache. 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. + this->Target->ClearSourcesCache(); + } + // Read skip files from makefile sources + if (this->MocEnabled || this->UicEnabled) { + std::string pathError; + for (cmSourceFile* sf : makefile->GetSourceFiles()) { + // sf->GetExtension() is only valid after sf->GetFullPath() ... + // Since we're iterating over source files that might be not in the + // target we need to check for path errors (not existing files). + std::string const& fPath = sf->GetFullPath(&pathError); + if (!pathError.empty()) { + pathError.clear(); + continue; + } + cmSystemTools::FileFormat const fileType = + cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); + if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && + !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { + continue; + } + const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN"); + const bool mocSkip = + this->MocEnabled && (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC")); + const bool uicSkip = + this->UicEnabled && (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC")); + if (mocSkip || uicSkip) { + std::string const absFile = cmSystemTools::GetRealPath(fPath); + if (mocSkip) { + this->MocSkip.insert(absFile); + } + if (uicSkip) { + this->UicSkip.insert(absFile); + } + } + } + } + + // Process GENERATED sources and headers + if (!generatedSources.empty() || !generatedHeaders.empty()) { + // Check status of policy CMP0071 + bool policyAccept = false; + bool policyWarn = false; + cmPolicies::PolicyStatus const CMP0071_status = + makefile->GetPolicyStatus(cmPolicies::CMP0071); + switch (CMP0071_status) { + case cmPolicies::WARN: + policyWarn = true; + CM_FALLTHROUGH; + case cmPolicies::OLD: + // Ignore GENERATED file + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Process GENERATED file + policyAccept = true; + break; + } + + if (policyAccept) { + // Accept GENERATED sources + for (std::string const& absFile : generatedHeaders) { + this->Headers.push_back(absFile); + autogenDependFiles.insert(absFile); + } + for (std::string const& absFile : generatedSources) { + this->Sources.push_back(absFile); + autogenDependFiles.insert(absFile); + } + } else { + if (policyWarn) { + std::string msg; + msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071); + msg += "\n"; + std::string tools; + std::string property; + if (this->MocEnabled && this->UicEnabled) { + tools = "AUTOMOC and AUTOUIC"; + property = "SKIP_AUTOGEN"; + } else if (this->MocEnabled) { + tools = "AUTOMOC"; + property = "SKIP_AUTOMOC"; + } else if (this->UicEnabled) { + tools = "AUTOUIC"; + property = "SKIP_AUTOUIC"; + } + msg += "For compatibility, CMake is excluding the GENERATED source " + "file(s):\n"; + for (const std::string& absFile : generatedHeaders) { + msg.append(" ").append(Quoted(absFile)).append("\n"); + } + for (const std::string& absFile : generatedSources) { + msg.append(" ").append(Quoted(absFile)).append("\n"); + } + msg += "from processing by "; + msg += tools; + msg += + ". If any of the files should be processed, set CMP0071 to NEW. " + "If any of the files should not be processed, " + "explicitly exclude them by setting the source file property "; + msg += property; + msg += ":\n set_property(SOURCE file.h PROPERTY "; + msg += property; + msg += " ON)\n"; + makefile->IssueMessage(cmake::AUTHOR_WARNING, msg); + } + } + // Clear lists + generatedSources.clear(); + generatedHeaders.clear(); + } + // Sort headers and sources + if (this->MocEnabled || this->UicEnabled) { + std::sort(this->Headers.begin(), this->Headers.end()); + std::sort(this->Sources.begin(), this->Sources.end()); + } + + // Process qrc files + if (!this->Qrcs.empty()) { + const bool QtV5 = (this->QtVersionMajor == "5"); + // Target rcc options + std::vector optionsTarget; + cmSystemTools::ExpandListArgument( + GetSafeProperty(this->Target, "AUTORCC_OPTIONS"), optionsTarget); + + // Check if file name is unique + for (Qrc& qrc : this->Qrcs) { + qrc.Unique = true; + for (Qrc const& qrc2 : this->Qrcs) { + if ((&qrc != &qrc2) && (qrc.QrcName == qrc2.QrcName)) { + qrc.Unique = false; + break; + } + } + } + // Path checksum and file names + { + cmFilePathChecksum const fpathCheckSum(makefile); + for (Qrc& qrc : this->Qrcs) { + qrc.PathChecksum = fpathCheckSum.getPart(qrc.QrcFile); + // RCC output file name + { + std::string rccFile = this->DirBuild + "/"; + rccFile += qrc.PathChecksum; + rccFile += "/qrc_"; + rccFile += qrc.QrcName; + rccFile += ".cpp"; + qrc.RccFile = std::move(rccFile); + } + { + std::string base = this->DirInfo; + base += "/RCC"; + base += qrc.QrcName; + if (!qrc.Unique) { + base += qrc.PathChecksum; + } + qrc.InfoFile = base; + qrc.InfoFile += "Info.cmake"; + qrc.SettingsFile = base; + qrc.SettingsFile += "Settings.txt"; + } + } + } + // RCC options + for (Qrc& qrc : this->Qrcs) { + // Target options + std::vector opts = optionsTarget; + // Merge computed "-name XYZ" option + { + std::string name = qrc.QrcName; + // Replace '-' with '_'. The former is not valid for symbol names. + std::replace(name.begin(), name.end(), '-', '_'); + if (!qrc.Unique) { + name += "_"; + name += qrc.PathChecksum; + } + std::vector nameOpts; + nameOpts.emplace_back("-name"); + nameOpts.emplace_back(std::move(name)); + RccMergeOptions(opts, nameOpts, QtV5); + } + // Merge file option + RccMergeOptions(opts, qrc.Options, QtV5); + qrc.Options = std::move(opts); + } + for (Qrc& qrc : this->Qrcs) { + // Register file at target + std::vector const ccOutput = + this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC); + + cmCustomCommandLines commandLines; + { + cmCustomCommandLine currentLine; + currentLine.push_back(cmSystemTools::GetCMakeCommand()); + currentLine.push_back("-E"); + currentLine.push_back("cmake_autorcc"); + currentLine.push_back(qrc.InfoFile); + currentLine.push_back("$"); + commandLines.push_back(std::move(currentLine)); + } + std::string ccComment = "Automatic RCC for "; + ccComment += FileProjectRelativePath(makefile, qrc.QrcFile); + + if (qrc.Generated) { + // Create custom rcc target + std::string ccName; + { + ccName = this->Target->GetName(); + ccName += "_arcc_"; + ccName += qrc.QrcName; + if (!qrc.Unique) { + ccName += "_"; + ccName += qrc.PathChecksum; + } + std::vector 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( + ccName, cmMakefile::TargetOrigin::Generator, true, + this->DirWork.c_str(), ccOutput, ccDepends, commandLines, false, + ccComment.c_str()); + // Create autogen generator target + localGen->AddGeneratorTarget( + new cmGeneratorTarget(autoRccTarget, localGen)); + + // Set FOLDER property in autogen target + if (!this->AutogenFolder.empty()) { + autoRccTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); + } + } + // Add autogen target to the origin target dependencies + this->Target->Target->AddUtility(ccName, makefile); + } else { + // Create custom rcc command + { + std::vector ccByproducts; + std::vector 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 + { + std::string error; + if (RccListInputs(qrc.QrcFile, qrc.Resources, error)) { + for (std::string const& fileName : qrc.Resources) { + // Add resource file to the custom command dependencies + ccDepends.push_back(fileName); + } + } else { + cmSystemTools::Error(error.c_str()); + } + } + makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends, + /*main_dependency*/ std::string(), + commandLines, ccComment.c_str(), + this->DirWork.c_str()); + } + // Reconfigure when .qrc file changes + makefile->AddCMakeDependFile(qrc.QrcFile); + } + } + } + + // Create _autogen target + if (this->MocEnabled || this->UicEnabled) { + // Add user defined autogen target dependencies + { + std::string const deps = + GetSafeProperty(this->Target, "AUTOGEN_TARGET_DEPENDS"); + if (!deps.empty()) { + std::vector extraDeps; + cmSystemTools::ExpandListArgument(deps, extraDeps); + for (std::string const& depName : extraDeps) { + // Allow target and file dependencies + auto* depTarget = makefile->FindTargetToUse(depName); + if (depTarget != nullptr) { + autogenDependTargets.insert(depTarget); + } else { + autogenDependFiles.insert(depName); + } + } + } + } + + // Compose target comment + std::string autogenComment; + { + std::string tools; + if (this->MocEnabled) { + tools += "MOC"; + } + if (this->UicEnabled) { + if (!tools.empty()) { + tools += " and "; + } + tools += "UIC"; + } + autogenComment = "Automatic "; + autogenComment += tools; + autogenComment += " for target "; + autogenComment += this->Target->GetName(); + } + + // Compose command lines + cmCustomCommandLines commandLines; + { + cmCustomCommandLine currentLine; + currentLine.push_back(cmSystemTools::GetCMakeCommand()); + currentLine.push_back("-E"); + currentLine.push_back("cmake_autogen"); + currentLine.push_back(this->AutogenInfoFile); + currentLine.push_back("$"); + commandLines.push_back(std::move(currentLine)); + } + + // Use PRE_BUILD on demand + bool usePRE_BUILD = false; + if (globalGen->GetName().find("Visual Studio") != std::string::npos) { + // Under VS use a PRE_BUILD event instead of a separate target to + // reduce the number of targets loaded into the IDE. + // This also works around a VS 11 bug that may skip updating the target: + // https://connect.microsoft.com/VisualStudio/feedback/details/769495 + usePRE_BUILD = true; + } + // Disable PRE_BUILD in some cases + if (usePRE_BUILD) { + // Cannot use PRE_BUILD with file depends + if (!autogenDependFiles.empty()) { + usePRE_BUILD = false; + } + } + // Create the autogen target/command + if (usePRE_BUILD) { + // Add additional autogen target dependencies to origin target + for (cmTarget* depTarget : autogenDependTargets) { + this->Target->Target->AddUtility(depTarget->GetName(), makefile); + } + + // Add the pre-build command directly to bypass the OBJECT_LIBRARY + // rejection in cmMakefile::AddCustomCommandToTarget because we know + // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. + // + // PRE_BUILD does not support file dependencies! + const std::vector no_output; + const std::vector no_deps; + cmCustomCommand cc(makefile, no_output, autogenProvides, no_deps, + commandLines, autogenComment.c_str(), + this->DirWork.c_str()); + cc.SetEscapeOldStyle(false); + cc.SetEscapeAllowMakeVars(true); + this->Target->Target->AddPreBuildCommand(cc); + } else { + + // Add link library target dependencies to the autogen target + // dependencies + { + // add_dependencies/addUtility do not support generator expressions. + // We depend only on the libraries found in all configs therefore. + std::map commonTargets; + for (std::string const& config : this->ConfigsList) { + cmLinkImplementationLibraries const* libs = + this->Target->GetLinkImplementationLibraries(config); + if (libs != nullptr) { + for (cmLinkItem const& item : libs->Libraries) { + cmGeneratorTarget const* libTarget = item.Target; + if ((libTarget != nullptr) && + !StaticLibraryCycle(this->Target, libTarget, config)) { + // Increment target config count + commonTargets[libTarget]++; + } + } + } + } + for (auto const& item : commonTargets) { + if (item.second == this->ConfigsList.size()) { + autogenDependTargets.insert(item.first->Target); + } + } + } + + // Create autogen target + cmTarget* autogenTarget = makefile->AddUtilityCommand( + this->AutogenTargetName, cmMakefile::TargetOrigin::Generator, true, + this->DirWork.c_str(), /*byproducts=*/autogenProvides, + std::vector(autogenDependFiles.begin(), + autogenDependFiles.end()), + commandLines, false, autogenComment.c_str()); + // Create autogen generator target + localGen->AddGeneratorTarget( + new cmGeneratorTarget(autogenTarget, localGen)); + + // Forward origin utilities to autogen target + for (std::string const& depName : this->Target->Target->GetUtilities()) { + autogenTarget->AddUtility(depName, makefile); + } + // Add additional autogen target dependencies to autogen target + for (cmTarget* depTarget : autogenDependTargets) { + autogenTarget->AddUtility(depTarget->GetName(), makefile); + } + + // Set FOLDER property in autogen target + if (!this->AutogenFolder.empty()) { + autogenTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); + } + + // Add autogen target to the origin target dependencies + this->Target->Target->AddUtility(this->AutogenTargetName, makefile); + } + } +} + +void cmQtAutoGenInitializer::SetupCustomTargets() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + // forget the variables added here afterwards again: + cmMakefile::ScopePushPop varScope(makefile); + static_cast(varScope); + + // Configuration suffixes + std::map configSuffixes; + for (std::string const& cfg : this->ConfigsList) { + std::string& suffix = configSuffixes[cfg]; + suffix = "_"; + suffix += cfg; + } + + // Basic setup + AddDefinitionEscaped(makefile, "_multi_config", + MultiConfigName(this->MultiConfig)); + AddDefinitionEscaped(makefile, "_build_dir", this->DirBuild); + { + std::string parallel = GetSafeProperty(this->Target, "AUTOGEN_PARALLEL"); + // Autodetect number of CPUs + if (parallel.empty() || (parallel == "AUTO")) { + parallel = std::to_string(GetParallelCPUCount()); + } + AddDefinitionEscaped(makefile, "_parallel", parallel); + } + + if (this->MocEnabled || this->UicEnabled) { + AddDefinitionEscaped(makefile, "_qt_version_major", this->QtVersionMajor); + AddDefinitionEscaped(makefile, "_settings_file", + this->AutogenSettingsFile); + AddDefinitionEscaped(makefile, "_sources", this->Sources); + AddDefinitionEscaped(makefile, "_headers", this->Headers); + + if (this->MocEnabled) { + this->SetupCustomTargetsMoc(); + } + if (this->UicEnabled) { + this->SetupCustomTargetsUic(); + } + } + if (this->RccEnabled) { + AddDefinitionEscaped(makefile, "_qt_rcc_executable", this->RccExecutable); + AddDefinitionEscaped(makefile, "_qt_rcc_list_options", + this->RccListOptions); + } + + // Create info directory on demand + if (!cmSystemTools::MakeDirectory(this->DirInfo)) { + std::string emsg = ("Could not create directory: "); + emsg += Quoted(this->DirInfo); + cmSystemTools::Error(emsg.c_str()); + } + + auto ReOpenInfoFile = [](cmsys::ofstream& ofs, + std::string const& fileName) -> bool { + // Ensure we have write permission + mode_t perm = 0; +#if defined(_WIN32) && !defined(__CYGWIN__) + mode_t mode_write = S_IWRITE; +#else + mode_t mode_write = S_IWUSR; +#endif + cmSystemTools::GetPermissions(fileName, perm); + if (!(perm & mode_write)) { + cmSystemTools::SetPermissions(fileName, perm | mode_write); + } + + ofs.open(fileName.c_str(), std::ios::app); + if (!ofs) { + // File open error + std::string error = "Internal CMake error when trying to open file: "; + error += Quoted(fileName); + error += " for writing."; + cmSystemTools::Error(error.c_str()); + } + return static_cast(ofs); + }; + + // Generate autogen target info file + if (this->MocEnabled || this->UicEnabled) { + { + std::string infoFileIn = cmSystemTools::GetCMakeRoot(); + infoFileIn += "/Modules/AutogenInfo.cmake.in"; + makefile->ConfigureFile( + infoFileIn.c_str(), this->AutogenInfoFile.c_str(), false, true, false); + } + + // Append custom definitions to info file + // -------------------------------------- + cmsys::ofstream ofs; + if (ReOpenInfoFile(ofs, this->AutogenInfoFile)) { + auto OfsWriteMap = [&ofs]( + const char* key, std::map const& map) { + for (auto const& item : map) { + ofs << "set(" << key << "_" << item.first << " " + << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; + } + }; + ofs << "# Configurations options\n"; + OfsWriteMap("AM_CONFIG_SUFFIX", configSuffixes); + OfsWriteMap("AM_MOC_DEFINITIONS", this->ConfigMocDefines); + OfsWriteMap("AM_MOC_INCLUDES", this->ConfigMocIncludes); + OfsWriteMap("AM_UIC_TARGET_OPTIONS", this->ConfigUicOptions); + // Settings files (only require for multi configuration generators) + if (this->MultiConfig != MultiConfigT::SINGLE) { + std::map settingsFiles; + for (std::string const& cfg : this->ConfigsList) { + settingsFiles[cfg] = + AppendFilenameSuffix(this->AutogenSettingsFile, "_" + cfg); + } + OfsWriteMap("AM_SETTINGS_FILE", settingsFiles); + } + } + } + + // Generate auto RCC info files + if (this->RccEnabled) { + std::string infoFileIn = cmSystemTools::GetCMakeRoot(); + infoFileIn += "/Modules/AutoRccInfo.cmake.in"; + for (Qrc const& qrc : this->Qrcs) { + // Configure info file + makefile->ConfigureFile(infoFileIn.c_str(), qrc.InfoFile.c_str(), false, + true, false); + + // Append custom definitions to info file + // -------------------------------------- + cmsys::ofstream ofs; + if (ReOpenInfoFile(ofs, qrc.InfoFile)) { + { + ofs << "# Job\n"; + auto OfsWrite = [&ofs](const char* key, std::string const& value) { + ofs << "set(" << key << " " + << cmOutputConverter::EscapeForCMake(value) << ")\n"; + + }; + OfsWrite("ARCC_SETTINGS_FILE", qrc.SettingsFile); + OfsWrite("ARCC_SOURCE", qrc.QrcFile); + OfsWrite("ARCC_OUTPUT", qrc.RccFile); + OfsWrite("ARCC_OPTIONS", cmJoin(qrc.Options, ";")); + OfsWrite("ARCC_INPUTS", cmJoin(qrc.Resources, ";")); + } + { + ofs << "# Configurations options\n"; + auto OfsWriteMap = [&ofs]( + const char* key, std::map const& map) { + for (auto const& item : map) { + ofs << "set(" << key << "_" << item.first << " " + << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; + } + }; + OfsWriteMap("ARCC_CONFIG_SUFFIX", configSuffixes); + + // Settings files (only require for multi configuration generators) + if (this->MultiConfig != MultiConfigT::SINGLE) { + std::map settingsFiles; + for (std::string const& cfg : this->ConfigsList) { + settingsFiles[cfg] = + AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg); + } + OfsWriteMap("ARCC_SETTINGS_FILE", settingsFiles); + } + } + } else { + break; + } + } + } +} + +void cmQtAutoGenInitializer::SetupCustomTargetsMoc() +{ + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + AddDefinitionEscaped(makefile, "_moc_skip", this->MocSkip); + AddDefinitionEscaped(makefile, "_moc_options", + GetSafeProperty(this->Target, "AUTOMOC_MOC_OPTIONS")); + AddDefinitionEscaped(makefile, "_moc_relaxed_mode", + makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE") ? "TRUE" + : "FALSE"); + AddDefinitionEscaped(makefile, "_moc_macro_names", + GetSafeProperty(this->Target, "AUTOMOC_MACRO_NAMES")); + AddDefinitionEscaped( + makefile, "_moc_depend_filters", + GetSafeProperty(this->Target, "AUTOMOC_DEPEND_FILTERS")); + + // Compiler predefines + if (this->Target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && + this->QtVersionGreaterOrEqual(5, 8)) { + AddDefinitionEscaped( + makefile, "_moc_predefs_cmd", + makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND")); + } + // Moc includes and compile definitions + { + auto GetIncludeDirs = [this, + localGen](std::string const& cfg) -> std::string { + // Get the include dirs for this target, without stripping the implicit + // include dirs off, see + // https://gitlab.kitware.com/cmake/cmake/issues/13667 + std::vector includeDirs; + localGen->GetIncludeDirectories(includeDirs, this->Target, "CXX", cfg, + false); + return cmJoin(includeDirs, ";"); + }; + auto GetCompileDefinitions = + [this, localGen](std::string const& cfg) -> std::string { + std::set defines; + localGen->AddCompileDefinitions(defines, this->Target, cfg, "CXX"); + return cmJoin(defines, ";"); + }; + + // Default configuration settings + std::string const includeDirs = GetIncludeDirs(this->ConfigDefault); + std::string const compileDefs = GetCompileDefinitions(this->ConfigDefault); + // Other configuration settings + for (std::string const& cfg : this->ConfigsList) { + { + std::string const configIncludeDirs = GetIncludeDirs(cfg); + if (configIncludeDirs != includeDirs) { + this->ConfigMocIncludes[cfg] = configIncludeDirs; + } + } + { + std::string const configCompileDefs = GetCompileDefinitions(cfg); + if (configCompileDefs != compileDefs) { + this->ConfigMocDefines[cfg] = configCompileDefs; + } + } + } + AddDefinitionEscaped(makefile, "_moc_include_dirs", includeDirs); + AddDefinitionEscaped(makefile, "_moc_compile_defs", compileDefs); + } + + // Moc executable + { + std::string mocExec; + std::string err; + + if (this->QtVersionMajor == "5") { + cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::moc"); + if (tgt != nullptr) { + mocExec = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTOMOC: Qt5::moc target not found"; + } + } else if (this->QtVersionMajor == "4") { + cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::moc"); + if (tgt != nullptr) { + mocExec = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTOMOC: Qt4::moc target not found"; + } + } else { + err = "The AUTOMOC feature supports only Qt 4 and Qt 5"; + } + + if (err.empty()) { + AddDefinitionEscaped(makefile, "_qt_moc_executable", mocExec); + } else { + err += " ("; + err += this->Target->GetName(); + err += ")"; + cmSystemTools::Error(err.c_str()); + } + } +} + +void cmQtAutoGenInitializer::SetupCustomTargetsUic() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + // Uic search paths + { + std::vector uicSearchPaths; + { + std::string const usp = + GetSafeProperty(this->Target, "AUTOUIC_SEARCH_PATHS"); + if (!usp.empty()) { + cmSystemTools::ExpandListArgument(usp, uicSearchPaths); + std::string const srcDir = makefile->GetCurrentSourceDirectory(); + for (std::string& path : uicSearchPaths) { + path = cmSystemTools::CollapseFullPath(path, srcDir); + } + } + } + AddDefinitionEscaped(makefile, "_uic_search_paths", uicSearchPaths); + } + // Uic target options + { + auto UicGetOpts = [this](std::string const& cfg) -> std::string { + std::vector opts; + this->Target->GetAutoUicOptions(opts, cfg); + return cmJoin(opts, ";"); + }; + + // Default settings + std::string const uicOpts = UicGetOpts(this->ConfigDefault); + AddDefinitionEscaped(makefile, "_uic_target_options", uicOpts); + + // Configuration specific settings + for (std::string const& cfg : this->ConfigsList) { + std::string const configUicOpts = UicGetOpts(cfg); + if (configUicOpts != uicOpts) { + this->ConfigUicOptions[cfg] = configUicOpts; + } + } + } + // .ui files skip and options + { + std::vector uiFileFiles; + std::vector> uiFileOptions; + { + std::string const uiExt = "ui"; + std::string pathError; + for (cmSourceFile* sf : makefile->GetSourceFiles()) { + // sf->GetExtension() is only valid after sf->GetFullPath() ... + // Since we're iterating over source files that might be not in the + // target we need to check for path errors (not existing files). + std::string const& fPath = sf->GetFullPath(&pathError); + if (!pathError.empty()) { + pathError.clear(); + continue; + } + if (sf->GetExtension() == uiExt) { + std::string const absFile = cmSystemTools::GetRealPath(fPath); + // Check if the .ui file should be skipped + if (sf->GetPropertyAsBool("SKIP_AUTOUIC") || + sf->GetPropertyAsBool("SKIP_AUTOGEN")) { + this->UicSkip.insert(absFile); + } + // Check if the .ui file has uic options + std::string const uicOpts = GetSafeProperty(sf, "AUTOUIC_OPTIONS"); + if (!uicOpts.empty()) { + // Check if file isn't skipped + if (this->UicSkip.count(absFile) == 0) { + uiFileFiles.push_back(absFile); + std::vector optsVec; + cmSystemTools::ExpandListArgument(uicOpts, optsVec); + uiFileOptions.push_back(std::move(optsVec)); + } + } + } + } + } + AddDefinitionEscaped(makefile, "_qt_uic_options_files", uiFileFiles); + AddDefinitionEscaped(makefile, "_qt_uic_options_options", uiFileOptions); + } + + AddDefinitionEscaped(makefile, "_uic_skip", this->UicSkip); + + // Uic executable + { + std::string err; + std::string uicExec; + + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + if (this->QtVersionMajor == "5") { + cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::uic"); + if (tgt != nullptr) { + uicExec = SafeString(tgt->ImportedGetLocation("")); + } else { + // Project does not use Qt5Widgets, but has AUTOUIC ON anyway + } + } else if (this->QtVersionMajor == "4") { + cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::uic"); + if (tgt != nullptr) { + uicExec = SafeString(tgt->ImportedGetLocation("")); + } else { + err = "AUTOUIC: Qt4::uic target not found"; + } + } else { + err = "The AUTOUIC feature supports only Qt 4 and Qt 5"; + } + + if (err.empty()) { + AddDefinitionEscaped(makefile, "_qt_uic_executable", uicExec); + } else { + err += " ("; + err += this->Target->GetName(); + err += ")"; + cmSystemTools::Error(err.c_str()); + } + } +} + +std::vector cmQtAutoGenInitializer::AddGeneratedSource( + std::string const& filename, GeneratorT genType) +{ + std::vector genFiles; + // Register source file in makefile and source group + if (this->MultiConfig != MultiConfigT::MULTI) { + genFiles.push_back(filename); + } else { + for (std::string const& cfg : this->ConfigsList) { + genFiles.push_back(AppendFilenameSuffix(filename, "_" + cfg)); + } + } + { + cmMakefile* makefile = this->Target->Target->GetMakefile(); + for (std::string const& genFile : genFiles) { + { + cmSourceFile* gFile = makefile->GetOrCreateSource(genFile, true); + gFile->SetProperty("GENERATED", "1"); + gFile->SetProperty("SKIP_AUTOGEN", "On"); + } + AddToSourceGroup(makefile, genFile, genType); + } + } + + // Add source file to target + if (this->MultiConfig != MultiConfigT::MULTI) { + this->Target->AddSource(filename); + } else { + for (std::string const& cfg : this->ConfigsList) { + std::string src = "$<$Target->AddSource(src); + } + } + + return genFiles; +} + +std::string cmQtAutoGenInitializer::GetQtMajorVersion( + cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string qtMajor = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); + if (qtMajor.empty()) { + qtMajor = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); + } + const char* targetQtVersion = + target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""); + if (targetQtVersion != nullptr) { + qtMajor = targetQtVersion; + } + return qtMajor; +} + +std::string cmQtAutoGenInitializer::GetQtMinorVersion( + cmGeneratorTarget const* target, std::string const& qtVersionMajor) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string qtMinor; + if (qtVersionMajor == "5") { + qtMinor = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR"); + } + if (qtMinor.empty()) { + qtMinor = makefile->GetSafeDefinition("QT_VERSION_MINOR"); + } + + const char* targetQtVersion = + target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", ""); + if (targetQtVersion != nullptr) { + qtMinor = targetQtVersion; + } + return qtMinor; +} + +bool cmQtAutoGenInitializer::QtVersionGreaterOrEqual( + unsigned long requestMajor, unsigned long requestMinor) const +{ + unsigned long majorUL(0); + unsigned long minorUL(0); + if (cmSystemTools::StringToULong(this->QtVersionMajor.c_str(), &majorUL) && + cmSystemTools::StringToULong(this->QtVersionMinor.c_str(), &minorUL)) { + return (majorUL > requestMajor) || + (majorUL == requestMajor && minorUL >= requestMinor); + } + return false; +} + +/// @brief Reads the resource files list from from a .qrc file +/// @arg fileName Must be the absolute path of the .qrc file +/// @return True if the rcc file was successfully read +bool cmQtAutoGenInitializer::RccListInputs(std::string const& fileName, + std::vector& files, + std::string& error) +{ + if (!cmSystemTools::FileExists(fileName.c_str())) { + error = "rcc resource file does not exist:\n "; + error += Quoted(fileName); + error += "\n"; + return false; + } + if (!RccListOptions.empty()) { + // Use rcc for file listing + if (RccExecutable.empty()) { + error = "rcc executable not available"; + return false; + } + + // Run rcc list command in the directory of the qrc file with the pathless + // qrc file name argument. This way rcc prints relative paths. + // This avoids issues on Windows when the qrc file is in a path that + // contains non-ASCII characters. + std::string const fileDir = cmSystemTools::GetFilenamePath(fileName); + std::string const fileNameName = cmSystemTools::GetFilenameName(fileName); + + bool result = false; + int retVal = 0; + std::string rccStdOut; + std::string rccStdErr; + { + std::vector cmd; + cmd.push_back(RccExecutable); + cmd.insert(cmd.end(), RccListOptions.begin(), RccListOptions.end()); + cmd.push_back(fileNameName); + result = cmSystemTools::RunSingleCommand( + cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), + cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); + } + if (!result || retVal) { + error = "rcc list process failed for:\n "; + error += Quoted(fileName); + error += "\n"; + error += rccStdOut; + error += "\n"; + error += rccStdErr; + error += "\n"; + return false; + } + if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) { + return false; + } + } else { + // We can't use rcc for the file listing. + // Read the qrc file content into string and parse it. + { + std::string qrcContents; + { + cmsys::ifstream ifs(fileName.c_str()); + if (ifs) { + std::ostringstream osst; + osst << ifs.rdbuf(); + qrcContents = osst.str(); + } else { + error = "rcc file not readable:\n "; + error += Quoted(fileName); + error += "\n"; + return false; + } + } + // Parse string content + RccListParseContent(qrcContents, files); + } + } + + // Convert relative paths to absolute paths + RccListConvertFullPath(cmSystemTools::GetFilenamePath(fileName), files); + return true; +} diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h new file mode 100644 index 0000000..a667017 --- /dev/null +++ b/Source/cmQtAutoGenInitializer.h @@ -0,0 +1,102 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGenInitializer_h +#define cmQtAutoGenInitializer_h + +#include "cmConfigure.h" // IWYU pragma: keep +#include "cmQtAutoGen.h" + +#include +#include +#include +#include + +class cmGeneratorTarget; + +/// @brief Initializes the QtAutoGen generators +class cmQtAutoGenInitializer : public cmQtAutoGen +{ +public: + static std::string GetQtMajorVersion(cmGeneratorTarget const* target); + static std::string GetQtMinorVersion(cmGeneratorTarget const* target, + std::string const& qtVersionMajor); + + class Qrc + { + public: + Qrc() + : Generated(false) + , Unique(false) + { + } + + public: + std::string QrcFile; + std::string QrcName; + std::string PathChecksum; + std::string InfoFile; + std::string SettingsFile; + std::string RccFile; + bool Generated; + bool Unique; + std::vector Options; + std::vector Resources; + }; + +public: + cmQtAutoGenInitializer(cmGeneratorTarget* target, bool mocEnabled, + bool uicEnabled, bool rccEnabled, + std::string const& qtVersionMajor); + + void InitCustomTargets(); + void SetupCustomTargets(); + +private: + void SetupCustomTargetsMoc(); + void SetupCustomTargetsUic(); + + std::vector AddGeneratedSource(std::string const& filename, + GeneratorT genType); + + bool QtVersionGreaterOrEqual(unsigned long requestMajor, + unsigned long requestMinor) const; + + bool RccListInputs(std::string const& fileName, + std::vector& files, + std::string& errorMessage); + +private: + cmGeneratorTarget* Target; + bool MocEnabled; + bool UicEnabled; + bool RccEnabled; + // Qt + std::string QtVersionMajor; + std::string QtVersionMinor; + std::string RccExecutable; + std::vector RccListOptions; + // Configurations + std::string ConfigDefault; + std::vector ConfigsList; + MultiConfigT MultiConfig; + // Names + std::string AutogenTargetName; + std::string AutogenFolder; + std::string AutogenInfoFile; + std::string AutogenSettingsFile; + // Directories + std::string DirInfo; + std::string DirBuild; + std::string DirWork; + // Sources + std::vector Headers; + std::vector Sources; + std::set MocSkip; + std::set UicSkip; + std::map ConfigMocIncludes; + std::map ConfigMocDefines; + std::map ConfigUicOptions; + std::vector Qrcs; +}; + +#endif diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx deleted file mode 100644 index 29f3653..0000000 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ /dev/null @@ -1,1461 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmQtAutoGen.h" -#include "cmQtAutoGeneratorInitializer.h" - -#include "cmAlgorithms.h" -#include "cmCustomCommand.h" -#include "cmCustomCommandLines.h" -#include "cmFilePathChecksum.h" -#include "cmGeneratorTarget.h" -#include "cmGlobalGenerator.h" -#include "cmLinkItem.h" -#include "cmLocalGenerator.h" -#include "cmMakefile.h" -#include "cmOutputConverter.h" -#include "cmPolicies.h" -#include "cmProcessOutput.h" -#include "cmSourceFile.h" -#include "cmSourceGroup.h" -#include "cmState.h" -#include "cmStateTypes.h" -#include "cmSystemTools.h" -#include "cmTarget.h" -#include "cm_sys_stat.h" -#include "cmake.h" -#include "cmsys/FStream.hxx" -#include "cmsys/SystemInformation.hxx" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -inline static const char* SafeString(const char* value) -{ - return (value != nullptr) ? value : ""; -} - -inline static std::string GetSafeProperty(cmGeneratorTarget const* target, - const char* key) -{ - return std::string(SafeString(target->GetProperty(key))); -} - -inline static std::string GetSafeProperty(cmSourceFile const* sf, - const char* key) -{ - return std::string(SafeString(sf->GetProperty(key))); -} - -static std::size_t GetParallelCPUCount() -{ - static std::size_t count = 0; - // Detect only on the first call - if (count == 0) { - cmsys::SystemInformation info; - info.RunCPUCheck(); - count = info.GetNumberOfPhysicalCPU(); - count = std::max(count, 1); - count = std::min(count, cmQtAutoGen::ParallelMax); - } - return count; -} - -static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, - std::string const& value) -{ - makefile->AddDefinition(key, - cmOutputConverter::EscapeForCMake(value).c_str()); -} - -static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, - const std::vector& values) -{ - makefile->AddDefinition( - key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); -} - -static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, - const std::set& values) -{ - makefile->AddDefinition( - key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); -} - -static void AddDefinitionEscaped( - cmMakefile* makefile, const char* key, - const std::vector>& lists) -{ - std::vector seplist; - for (const std::vector& list : lists) { - std::string blist = "{"; - blist += cmJoin(list, ";"); - blist += "}"; - seplist.push_back(std::move(blist)); - } - makefile->AddDefinition(key, cmOutputConverter::EscapeForCMake( - cmJoin(seplist, cmQtAutoGen::ListSep)) - .c_str()); -} - -static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName, - cmQtAutoGen::GeneratorT genType) -{ - cmSourceGroup* sourceGroup = nullptr; - // Acquire source group - { - std::string property; - std::string groupName; - { - std::array props; - // Use generator specific group name - switch (genType) { - case cmQtAutoGen::GeneratorT::MOC: - props[0] = "AUTOMOC_SOURCE_GROUP"; - break; - case cmQtAutoGen::GeneratorT::RCC: - props[0] = "AUTORCC_SOURCE_GROUP"; - break; - default: - props[0] = "AUTOGEN_SOURCE_GROUP"; - break; - } - props[1] = "AUTOGEN_SOURCE_GROUP"; - for (std::string& prop : props) { - const char* propName = makefile->GetState()->GetGlobalProperty(prop); - if ((propName != nullptr) && (*propName != '\0')) { - groupName = propName; - property = std::move(prop); - break; - } - } - } - // Generate a source group on demand - if (!groupName.empty()) { - sourceGroup = makefile->GetOrCreateSourceGroup(groupName); - if (sourceGroup == nullptr) { - std::ostringstream ost; - ost << cmQtAutoGen::GeneratorNameUpper(genType); - ost << ": " << property; - ost << ": Could not find or create the source group "; - ost << cmQtAutoGen::Quoted(groupName); - cmSystemTools::Error(ost.str().c_str()); - return false; - } - } - } - if (sourceGroup != nullptr) { - sourceGroup->AddGroupFile(fileName); - } - return true; -} - -static void AddCleanFile(cmMakefile* makefile, std::string const& fileName) -{ - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(), - false); -} - -static std::string FileProjectRelativePath(cmMakefile* makefile, - std::string const& fileName) -{ - std::string res; - { - std::string pSource = cmSystemTools::RelativePath( - makefile->GetCurrentSourceDirectory(), fileName.c_str()); - std::string pBinary = cmSystemTools::RelativePath( - makefile->GetCurrentBinaryDirectory(), fileName.c_str()); - if (pSource.size() < pBinary.size()) { - res = std::move(pSource); - } else if (pBinary.size() < fileName.size()) { - res = std::move(pBinary); - } else { - res = fileName; - } - } - return res; -} - -/* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its - * recursive STATIC_LIBRARY dependencies depends on targetOrigin - * (STATIC_LIBRARY cycle). - */ -static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, - cmGeneratorTarget const* targetDepend, - std::string const& config) -{ - bool cycle = false; - if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) && - (targetDepend->GetType() == cmStateEnums::STATIC_LIBRARY)) { - std::set knownLibs; - std::deque testLibs; - - // Insert initial static_library dependency - knownLibs.insert(targetDepend); - testLibs.push_back(targetDepend); - - while (!testLibs.empty()) { - cmGeneratorTarget const* testTarget = testLibs.front(); - testLibs.pop_front(); - // Check if the test target is the origin target (cycle) - if (testTarget == targetOrigin) { - cycle = true; - break; - } - // Collect all static_library dependencies from the test target - cmLinkImplementationLibraries const* libs = - testTarget->GetLinkImplementationLibraries(config); - if (libs != nullptr) { - for (cmLinkItem const& item : libs->Libraries) { - cmGeneratorTarget const* depTarget = item.Target; - if ((depTarget != nullptr) && - (depTarget->GetType() == cmStateEnums::STATIC_LIBRARY) && - knownLibs.insert(depTarget).second) { - testLibs.push_back(depTarget); - } - } - } - } - } - return cycle; -} - -cmQtAutoGeneratorInitializer::cmQtAutoGeneratorInitializer( - cmGeneratorTarget* target, bool mocEnabled, bool uicEnabled, bool rccEnabled, - std::string const& qtVersionMajor) - : Target(target) - , MocEnabled(mocEnabled) - , UicEnabled(uicEnabled) - , RccEnabled(rccEnabled) - , QtVersionMajor(qtVersionMajor) - , MultiConfig(MultiConfigT::WRAPPER) -{ - this->QtVersionMinor = cmQtAutoGeneratorInitializer::GetQtMinorVersion( - target, this->QtVersionMajor); -} - -void cmQtAutoGeneratorInitializer::InitCustomTargets() -{ - cmMakefile* makefile = this->Target->Target->GetMakefile(); - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); - - // Configurations - this->ConfigDefault = makefile->GetConfigurations(this->ConfigsList); - if (this->ConfigsList.empty()) { - this->ConfigsList.push_back(this->ConfigDefault); - } - - // Multi configuration - { - if (!globalGen->IsMultiConfig()) { - this->MultiConfig = MultiConfigT::SINGLE; - } - - // FIXME: Xcode does not support per-config sources, yet. - // (EXCLUDED_SOURCE_FILE_NAMES) - // if (globalGen->GetName().find("Xcode") != std::string::npos) { - // return MultiConfigT::MULTI; - //} - - // FIXME: Visual Studio does not support per-config sources, yet. - // (EXCLUDED_SOURCE_FILE_NAMES) - // if (globalGen->GetName().find("Visual Studio") != std::string::npos) { - // return MultiConfigT::MULTI; - //} - } - - // Autogen target name - this->AutogenTargetName = this->Target->GetName(); - this->AutogenTargetName += "_autogen"; - - // Autogen directories - { - // Collapsed current binary directory - std::string const cbd = cmSystemTools::CollapseFullPath( - "", makefile->GetCurrentBinaryDirectory()); - - // Autogen info dir - this->DirInfo = cbd; - this->DirInfo += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); - this->DirInfo += "/"; - this->DirInfo += this->AutogenTargetName; - this->DirInfo += ".dir"; - cmSystemTools::ConvertToUnixSlashes(this->DirInfo); - - // Autogen build dir - this->DirBuild = GetSafeProperty(this->Target, "AUTOGEN_BUILD_DIR"); - if (this->DirBuild.empty()) { - this->DirBuild = cbd; - this->DirBuild += "/"; - this->DirBuild += this->AutogenTargetName; - } - cmSystemTools::ConvertToUnixSlashes(this->DirBuild); - - // Working directory - this->DirWork = cbd; - cmSystemTools::ConvertToUnixSlashes(this->DirWork); - } - - // Autogen files - { - this->AutogenInfoFile = this->DirInfo; - this->AutogenInfoFile += "/AutogenInfo.cmake"; - - this->AutogenSettingsFile = this->DirInfo; - this->AutogenSettingsFile += "/AutogenOldSettings.txt"; - } - - // Autogen target FOLDER property - { - const char* folder = - makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); - if (folder == nullptr) { - folder = - makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); - } - // Inherit FOLDER property from target (#13688) - if (folder == nullptr) { - folder = SafeString(this->Target->Target->GetProperty("FOLDER")); - } - if (folder != nullptr) { - this->AutogenFolder = folder; - } - } - - std::set autogenDependFiles; - std::set autogenDependTargets; - std::vector autogenProvides; - - // Remove build directories on cleanup - AddCleanFile(makefile, this->DirBuild); - // Remove old settings on cleanup - { - std::string base = this->DirInfo; - base += "/AutogenOldSettings"; - if (this->MultiConfig == MultiConfigT::SINGLE) { - AddCleanFile(makefile, base.append(".cmake")); - } else { - for (std::string const& cfg : this->ConfigsList) { - std::string filename = base; - filename += "_"; - filename += cfg; - filename += ".cmake"; - AddCleanFile(makefile, filename); - } - } - } - - // Add moc compilation to generated files list - if (this->MocEnabled) { - std::string const mocsComp = this->DirBuild + "/mocs_compilation.cpp"; - auto files = this->AddGeneratedSource(mocsComp, GeneratorT::MOC); - for (std::string& file : files) { - autogenProvides.push_back(std::move(file)); - } - } - - // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES - if (this->MocEnabled || this->UicEnabled) { - std::string includeDir = this->DirBuild + "/include"; - if (this->MultiConfig != MultiConfigT::SINGLE) { - includeDir += "_$"; - } - this->Target->AddIncludeDirectory(includeDir, true); - } - - // Acquire rcc executable and features - if (this->RccEnabled) { - { - std::string err; - if (this->QtVersionMajor == "5") { - cmGeneratorTarget* tgt = - localGen->FindGeneratorTargetToUse("Qt5::rcc"); - if (tgt != nullptr) { - this->RccExecutable = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTORCC: Qt5::rcc target not found"; - } - } else if (QtVersionMajor == "4") { - cmGeneratorTarget* tgt = - localGen->FindGeneratorTargetToUse("Qt4::rcc"); - if (tgt != nullptr) { - this->RccExecutable = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTORCC: Qt4::rcc target not found"; - } - } else { - err = "The AUTORCC feature supports only Qt 4 and Qt 5"; - } - if (!err.empty()) { - err += " ("; - err += this->Target->GetName(); - err += ")"; - cmSystemTools::Error(err.c_str()); - } - } - // Detect if rcc supports (-)-list - if (!this->RccExecutable.empty() && (this->QtVersionMajor == "5")) { - std::vector command; - command.push_back(this->RccExecutable); - command.push_back("--help"); - std::string rccStdOut; - std::string rccStdErr; - int retVal = 0; - bool result = cmSystemTools::RunSingleCommand( - command, &rccStdOut, &rccStdErr, &retVal, nullptr, - cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); - if (result && retVal == 0 && - rccStdOut.find("--list") != std::string::npos) { - this->RccListOptions.push_back("--list"); - } else { - this->RccListOptions.push_back("-list"); - } - } - } - - // Extract relevant source files - std::vector generatedSources; - std::vector generatedHeaders; - { - std::string const qrcExt = "qrc"; - std::vector srcFiles; - this->Target->GetConfigCommonSourceFiles(srcFiles); - for (cmSourceFile* sf : srcFiles) { - if (sf->GetPropertyAsBool("SKIP_AUTOGEN")) { - continue; - } - // sf->GetExtension() is only valid after sf->GetFullPath() ... - std::string const& fPath = sf->GetFullPath(); - std::string const& ext = sf->GetExtension(); - // Register generated files that will be scanned by moc or uic - if (this->MocEnabled || this->UicEnabled) { - cmSystemTools::FileFormat const fileType = - cmSystemTools::GetFileFormat(ext.c_str()); - if ((fileType == cmSystemTools::CXX_FILE_FORMAT) || - (fileType == cmSystemTools::HEADER_FILE_FORMAT)) { - std::string const absPath = cmSystemTools::GetRealPath(fPath); - if ((this->MocEnabled && !sf->GetPropertyAsBool("SKIP_AUTOMOC")) || - (this->UicEnabled && !sf->GetPropertyAsBool("SKIP_AUTOUIC"))) { - // Register source - const bool generated = sf->GetPropertyAsBool("GENERATED"); - if (fileType == cmSystemTools::HEADER_FILE_FORMAT) { - if (generated) { - generatedHeaders.push_back(absPath); - } else { - this->Headers.push_back(absPath); - } - } else { - if (generated) { - generatedSources.push_back(absPath); - } else { - this->Sources.push_back(absPath); - } - } - } - } - } - // Register rcc enabled files - if (this->RccEnabled && (ext == qrcExt) && - !sf->GetPropertyAsBool("SKIP_AUTORCC")) { - // Register qrc file - { - Qrc qrc; - qrc.QrcFile = cmSystemTools::GetRealPath(fPath); - qrc.QrcName = - cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile); - qrc.Generated = sf->GetPropertyAsBool("GENERATED"); - // RCC options - { - std::string const opts = GetSafeProperty(sf, "AUTORCC_OPTIONS"); - if (!opts.empty()) { - cmSystemTools::ExpandListArgument(opts, qrc.Options); - } - } - this->Qrcs.push_back(std::move(qrc)); - } - } - } - // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's - // sources meta data cache. 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. - this->Target->ClearSourcesCache(); - } - // Read skip files from makefile sources - if (this->MocEnabled || this->UicEnabled) { - std::string pathError; - for (cmSourceFile* sf : makefile->GetSourceFiles()) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... - // Since we're iterating over source files that might be not in the - // target we need to check for path errors (not existing files). - std::string const& fPath = sf->GetFullPath(&pathError); - if (!pathError.empty()) { - pathError.clear(); - continue; - } - cmSystemTools::FileFormat const fileType = - cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); - if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && - !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { - continue; - } - const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN"); - const bool mocSkip = - this->MocEnabled && (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC")); - const bool uicSkip = - this->UicEnabled && (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC")); - if (mocSkip || uicSkip) { - std::string const absFile = cmSystemTools::GetRealPath(fPath); - if (mocSkip) { - this->MocSkip.insert(absFile); - } - if (uicSkip) { - this->UicSkip.insert(absFile); - } - } - } - } - - // Process GENERATED sources and headers - if (!generatedSources.empty() || !generatedHeaders.empty()) { - // Check status of policy CMP0071 - bool policyAccept = false; - bool policyWarn = false; - cmPolicies::PolicyStatus const CMP0071_status = - makefile->GetPolicyStatus(cmPolicies::CMP0071); - switch (CMP0071_status) { - case cmPolicies::WARN: - policyWarn = true; - CM_FALLTHROUGH; - case cmPolicies::OLD: - // Ignore GENERATED file - break; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - // Process GENERATED file - policyAccept = true; - break; - } - - if (policyAccept) { - // Accept GENERATED sources - for (std::string const& absFile : generatedHeaders) { - this->Headers.push_back(absFile); - autogenDependFiles.insert(absFile); - } - for (std::string const& absFile : generatedSources) { - this->Sources.push_back(absFile); - autogenDependFiles.insert(absFile); - } - } else { - if (policyWarn) { - std::string msg; - msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071); - msg += "\n"; - std::string tools; - std::string property; - if (this->MocEnabled && this->UicEnabled) { - tools = "AUTOMOC and AUTOUIC"; - property = "SKIP_AUTOGEN"; - } else if (this->MocEnabled) { - tools = "AUTOMOC"; - property = "SKIP_AUTOMOC"; - } else if (this->UicEnabled) { - tools = "AUTOUIC"; - property = "SKIP_AUTOUIC"; - } - msg += "For compatibility, CMake is excluding the GENERATED source " - "file(s):\n"; - for (const std::string& absFile : generatedHeaders) { - msg.append(" ").append(Quoted(absFile)).append("\n"); - } - for (const std::string& absFile : generatedSources) { - msg.append(" ").append(Quoted(absFile)).append("\n"); - } - msg += "from processing by "; - msg += tools; - msg += - ". If any of the files should be processed, set CMP0071 to NEW. " - "If any of the files should not be processed, " - "explicitly exclude them by setting the source file property "; - msg += property; - msg += ":\n set_property(SOURCE file.h PROPERTY "; - msg += property; - msg += " ON)\n"; - makefile->IssueMessage(cmake::AUTHOR_WARNING, msg); - } - } - // Clear lists - generatedSources.clear(); - generatedHeaders.clear(); - } - // Sort headers and sources - if (this->MocEnabled || this->UicEnabled) { - std::sort(this->Headers.begin(), this->Headers.end()); - std::sort(this->Sources.begin(), this->Sources.end()); - } - - // Process qrc files - if (!this->Qrcs.empty()) { - const bool QtV5 = (this->QtVersionMajor == "5"); - // Target rcc options - std::vector optionsTarget; - cmSystemTools::ExpandListArgument( - GetSafeProperty(this->Target, "AUTORCC_OPTIONS"), optionsTarget); - - // Check if file name is unique - for (Qrc& qrc : this->Qrcs) { - qrc.Unique = true; - for (Qrc const& qrc2 : this->Qrcs) { - if ((&qrc != &qrc2) && (qrc.QrcName == qrc2.QrcName)) { - qrc.Unique = false; - break; - } - } - } - // Path checksum and file names - { - cmFilePathChecksum const fpathCheckSum(makefile); - for (Qrc& qrc : this->Qrcs) { - qrc.PathChecksum = fpathCheckSum.getPart(qrc.QrcFile); - // RCC output file name - { - std::string rccFile = this->DirBuild + "/"; - rccFile += qrc.PathChecksum; - rccFile += "/qrc_"; - rccFile += qrc.QrcName; - rccFile += ".cpp"; - qrc.RccFile = std::move(rccFile); - } - { - std::string base = this->DirInfo; - base += "/RCC"; - base += qrc.QrcName; - if (!qrc.Unique) { - base += qrc.PathChecksum; - } - qrc.InfoFile = base; - qrc.InfoFile += "Info.cmake"; - qrc.SettingsFile = base; - qrc.SettingsFile += "Settings.txt"; - } - } - } - // RCC options - for (Qrc& qrc : this->Qrcs) { - // Target options - std::vector opts = optionsTarget; - // Merge computed "-name XYZ" option - { - std::string name = qrc.QrcName; - // Replace '-' with '_'. The former is not valid for symbol names. - std::replace(name.begin(), name.end(), '-', '_'); - if (!qrc.Unique) { - name += "_"; - name += qrc.PathChecksum; - } - std::vector nameOpts; - nameOpts.emplace_back("-name"); - nameOpts.emplace_back(std::move(name)); - RccMergeOptions(opts, nameOpts, QtV5); - } - // Merge file option - RccMergeOptions(opts, qrc.Options, QtV5); - qrc.Options = std::move(opts); - } - for (Qrc& qrc : this->Qrcs) { - // Register file at target - std::vector const ccOutput = - this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC); - - cmCustomCommandLines commandLines; - { - cmCustomCommandLine currentLine; - currentLine.push_back(cmSystemTools::GetCMakeCommand()); - currentLine.push_back("-E"); - currentLine.push_back("cmake_autorcc"); - currentLine.push_back(qrc.InfoFile); - currentLine.push_back("$"); - commandLines.push_back(std::move(currentLine)); - } - std::string ccComment = "Automatic RCC for "; - ccComment += FileProjectRelativePath(makefile, qrc.QrcFile); - - if (qrc.Generated) { - // Create custom rcc target - std::string ccName; - { - ccName = this->Target->GetName(); - ccName += "_arcc_"; - ccName += qrc.QrcName; - if (!qrc.Unique) { - ccName += "_"; - ccName += qrc.PathChecksum; - } - std::vector 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( - ccName, cmMakefile::TargetOrigin::Generator, true, - this->DirWork.c_str(), ccOutput, ccDepends, commandLines, false, - ccComment.c_str()); - // Create autogen generator target - localGen->AddGeneratorTarget( - new cmGeneratorTarget(autoRccTarget, localGen)); - - // Set FOLDER property in autogen target - if (!this->AutogenFolder.empty()) { - autoRccTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); - } - } - // Add autogen target to the origin target dependencies - this->Target->Target->AddUtility(ccName, makefile); - } else { - // Create custom rcc command - { - std::vector ccByproducts; - std::vector 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 - { - std::string error; - if (RccListInputs(qrc.QrcFile, qrc.Resources, error)) { - for (std::string const& fileName : qrc.Resources) { - // Add resource file to the custom command dependencies - ccDepends.push_back(fileName); - } - } else { - cmSystemTools::Error(error.c_str()); - } - } - makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends, - /*main_dependency*/ std::string(), - commandLines, ccComment.c_str(), - this->DirWork.c_str()); - } - // Reconfigure when .qrc file changes - makefile->AddCMakeDependFile(qrc.QrcFile); - } - } - } - - // Create _autogen target - if (this->MocEnabled || this->UicEnabled) { - // Add user defined autogen target dependencies - { - std::string const deps = - GetSafeProperty(this->Target, "AUTOGEN_TARGET_DEPENDS"); - if (!deps.empty()) { - std::vector extraDeps; - cmSystemTools::ExpandListArgument(deps, extraDeps); - for (std::string const& depName : extraDeps) { - // Allow target and file dependencies - auto* depTarget = makefile->FindTargetToUse(depName); - if (depTarget != nullptr) { - autogenDependTargets.insert(depTarget); - } else { - autogenDependFiles.insert(depName); - } - } - } - } - - // Compose target comment - std::string autogenComment; - { - std::string tools; - if (this->MocEnabled) { - tools += "MOC"; - } - if (this->UicEnabled) { - if (!tools.empty()) { - tools += " and "; - } - tools += "UIC"; - } - autogenComment = "Automatic "; - autogenComment += tools; - autogenComment += " for target "; - autogenComment += this->Target->GetName(); - } - - // Compose command lines - cmCustomCommandLines commandLines; - { - cmCustomCommandLine currentLine; - currentLine.push_back(cmSystemTools::GetCMakeCommand()); - currentLine.push_back("-E"); - currentLine.push_back("cmake_autogen"); - currentLine.push_back(this->AutogenInfoFile); - currentLine.push_back("$"); - commandLines.push_back(std::move(currentLine)); - } - - // Use PRE_BUILD on demand - bool usePRE_BUILD = false; - if (globalGen->GetName().find("Visual Studio") != std::string::npos) { - // Under VS use a PRE_BUILD event instead of a separate target to - // reduce the number of targets loaded into the IDE. - // This also works around a VS 11 bug that may skip updating the target: - // https://connect.microsoft.com/VisualStudio/feedback/details/769495 - usePRE_BUILD = true; - } - // Disable PRE_BUILD in some cases - if (usePRE_BUILD) { - // Cannot use PRE_BUILD with file depends - if (!autogenDependFiles.empty()) { - usePRE_BUILD = false; - } - } - // Create the autogen target/command - if (usePRE_BUILD) { - // Add additional autogen target dependencies to origin target - for (cmTarget* depTarget : autogenDependTargets) { - this->Target->Target->AddUtility(depTarget->GetName(), makefile); - } - - // Add the pre-build command directly to bypass the OBJECT_LIBRARY - // rejection in cmMakefile::AddCustomCommandToTarget because we know - // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. - // - // PRE_BUILD does not support file dependencies! - const std::vector no_output; - const std::vector no_deps; - cmCustomCommand cc(makefile, no_output, autogenProvides, no_deps, - commandLines, autogenComment.c_str(), - this->DirWork.c_str()); - cc.SetEscapeOldStyle(false); - cc.SetEscapeAllowMakeVars(true); - this->Target->Target->AddPreBuildCommand(cc); - } else { - - // Add link library target dependencies to the autogen target - // dependencies - { - // add_dependencies/addUtility do not support generator expressions. - // We depend only on the libraries found in all configs therefore. - std::map commonTargets; - for (std::string const& config : this->ConfigsList) { - cmLinkImplementationLibraries const* libs = - this->Target->GetLinkImplementationLibraries(config); - if (libs != nullptr) { - for (cmLinkItem const& item : libs->Libraries) { - cmGeneratorTarget const* libTarget = item.Target; - if ((libTarget != nullptr) && - !StaticLibraryCycle(this->Target, libTarget, config)) { - // Increment target config count - commonTargets[libTarget]++; - } - } - } - } - for (auto const& item : commonTargets) { - if (item.second == this->ConfigsList.size()) { - autogenDependTargets.insert(item.first->Target); - } - } - } - - // Create autogen target - cmTarget* autogenTarget = makefile->AddUtilityCommand( - this->AutogenTargetName, cmMakefile::TargetOrigin::Generator, true, - this->DirWork.c_str(), /*byproducts=*/autogenProvides, - std::vector(autogenDependFiles.begin(), - autogenDependFiles.end()), - commandLines, false, autogenComment.c_str()); - // Create autogen generator target - localGen->AddGeneratorTarget( - new cmGeneratorTarget(autogenTarget, localGen)); - - // Forward origin utilities to autogen target - for (std::string const& depName : this->Target->Target->GetUtilities()) { - autogenTarget->AddUtility(depName, makefile); - } - // Add additional autogen target dependencies to autogen target - for (cmTarget* depTarget : autogenDependTargets) { - autogenTarget->AddUtility(depTarget->GetName(), makefile); - } - - // Set FOLDER property in autogen target - if (!this->AutogenFolder.empty()) { - autogenTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); - } - - // Add autogen target to the origin target dependencies - this->Target->Target->AddUtility(this->AutogenTargetName, makefile); - } - } -} - -void cmQtAutoGeneratorInitializer::SetupCustomTargets() -{ - cmMakefile* makefile = this->Target->Target->GetMakefile(); - - // forget the variables added here afterwards again: - cmMakefile::ScopePushPop varScope(makefile); - static_cast(varScope); - - // Configuration suffixes - std::map configSuffixes; - for (std::string const& cfg : this->ConfigsList) { - std::string& suffix = configSuffixes[cfg]; - suffix = "_"; - suffix += cfg; - } - - // Basic setup - AddDefinitionEscaped(makefile, "_multi_config", - MultiConfigName(this->MultiConfig)); - AddDefinitionEscaped(makefile, "_build_dir", this->DirBuild); - { - std::string parallel = GetSafeProperty(this->Target, "AUTOGEN_PARALLEL"); - // Autodetect number of CPUs - if (parallel.empty() || (parallel == "AUTO")) { - parallel = std::to_string(GetParallelCPUCount()); - } - AddDefinitionEscaped(makefile, "_parallel", parallel); - } - - if (this->MocEnabled || this->UicEnabled) { - AddDefinitionEscaped(makefile, "_qt_version_major", this->QtVersionMajor); - AddDefinitionEscaped(makefile, "_settings_file", - this->AutogenSettingsFile); - AddDefinitionEscaped(makefile, "_sources", this->Sources); - AddDefinitionEscaped(makefile, "_headers", this->Headers); - - if (this->MocEnabled) { - this->SetupCustomTargetsMoc(); - } - if (this->UicEnabled) { - this->SetupCustomTargetsUic(); - } - } - if (this->RccEnabled) { - AddDefinitionEscaped(makefile, "_qt_rcc_executable", this->RccExecutable); - AddDefinitionEscaped(makefile, "_qt_rcc_list_options", - this->RccListOptions); - } - - // Create info directory on demand - if (!cmSystemTools::MakeDirectory(this->DirInfo)) { - std::string emsg = ("Could not create directory: "); - emsg += Quoted(this->DirInfo); - cmSystemTools::Error(emsg.c_str()); - } - - auto ReOpenInfoFile = [](cmsys::ofstream& ofs, - std::string const& fileName) -> bool { - // Ensure we have write permission - mode_t perm = 0; -#if defined(_WIN32) && !defined(__CYGWIN__) - mode_t mode_write = S_IWRITE; -#else - mode_t mode_write = S_IWUSR; -#endif - cmSystemTools::GetPermissions(fileName, perm); - if (!(perm & mode_write)) { - cmSystemTools::SetPermissions(fileName, perm | mode_write); - } - - ofs.open(fileName.c_str(), std::ios::app); - if (!ofs) { - // File open error - std::string error = "Internal CMake error when trying to open file: "; - error += Quoted(fileName); - error += " for writing."; - cmSystemTools::Error(error.c_str()); - } - return static_cast(ofs); - }; - - // Generate autogen target info file - if (this->MocEnabled || this->UicEnabled) { - { - std::string infoFileIn = cmSystemTools::GetCMakeRoot(); - infoFileIn += "/Modules/AutogenInfo.cmake.in"; - makefile->ConfigureFile( - infoFileIn.c_str(), this->AutogenInfoFile.c_str(), false, true, false); - } - - // Append custom definitions to info file - // -------------------------------------- - cmsys::ofstream ofs; - if (ReOpenInfoFile(ofs, this->AutogenInfoFile)) { - auto OfsWriteMap = [&ofs]( - const char* key, std::map const& map) { - for (auto const& item : map) { - ofs << "set(" << key << "_" << item.first << " " - << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; - } - }; - ofs << "# Configurations options\n"; - OfsWriteMap("AM_CONFIG_SUFFIX", configSuffixes); - OfsWriteMap("AM_MOC_DEFINITIONS", this->ConfigMocDefines); - OfsWriteMap("AM_MOC_INCLUDES", this->ConfigMocIncludes); - OfsWriteMap("AM_UIC_TARGET_OPTIONS", this->ConfigUicOptions); - // Settings files (only require for multi configuration generators) - if (this->MultiConfig != MultiConfigT::SINGLE) { - std::map settingsFiles; - for (std::string const& cfg : this->ConfigsList) { - settingsFiles[cfg] = - AppendFilenameSuffix(this->AutogenSettingsFile, "_" + cfg); - } - OfsWriteMap("AM_SETTINGS_FILE", settingsFiles); - } - } - } - - // Generate auto RCC info files - if (this->RccEnabled) { - std::string infoFileIn = cmSystemTools::GetCMakeRoot(); - infoFileIn += "/Modules/AutoRccInfo.cmake.in"; - for (Qrc const& qrc : this->Qrcs) { - // Configure info file - makefile->ConfigureFile(infoFileIn.c_str(), qrc.InfoFile.c_str(), false, - true, false); - - // Append custom definitions to info file - // -------------------------------------- - cmsys::ofstream ofs; - if (ReOpenInfoFile(ofs, qrc.InfoFile)) { - { - ofs << "# Job\n"; - auto OfsWrite = [&ofs](const char* key, std::string const& value) { - ofs << "set(" << key << " " - << cmOutputConverter::EscapeForCMake(value) << ")\n"; - - }; - OfsWrite("ARCC_SETTINGS_FILE", qrc.SettingsFile); - OfsWrite("ARCC_SOURCE", qrc.QrcFile); - OfsWrite("ARCC_OUTPUT", qrc.RccFile); - OfsWrite("ARCC_OPTIONS", cmJoin(qrc.Options, ";")); - OfsWrite("ARCC_INPUTS", cmJoin(qrc.Resources, ";")); - } - { - ofs << "# Configurations options\n"; - auto OfsWriteMap = [&ofs]( - const char* key, std::map const& map) { - for (auto const& item : map) { - ofs << "set(" << key << "_" << item.first << " " - << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; - } - }; - OfsWriteMap("ARCC_CONFIG_SUFFIX", configSuffixes); - - // Settings files (only require for multi configuration generators) - if (this->MultiConfig != MultiConfigT::SINGLE) { - std::map settingsFiles; - for (std::string const& cfg : this->ConfigsList) { - settingsFiles[cfg] = - AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg); - } - OfsWriteMap("ARCC_SETTINGS_FILE", settingsFiles); - } - } - } else { - break; - } - } - } -} - -void cmQtAutoGeneratorInitializer::SetupCustomTargetsMoc() -{ - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - cmMakefile* makefile = this->Target->Target->GetMakefile(); - - AddDefinitionEscaped(makefile, "_moc_skip", this->MocSkip); - AddDefinitionEscaped(makefile, "_moc_options", - GetSafeProperty(this->Target, "AUTOMOC_MOC_OPTIONS")); - AddDefinitionEscaped(makefile, "_moc_relaxed_mode", - makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE") ? "TRUE" - : "FALSE"); - AddDefinitionEscaped(makefile, "_moc_macro_names", - GetSafeProperty(this->Target, "AUTOMOC_MACRO_NAMES")); - AddDefinitionEscaped( - makefile, "_moc_depend_filters", - GetSafeProperty(this->Target, "AUTOMOC_DEPEND_FILTERS")); - - // Compiler predefines - if (this->Target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && - this->QtVersionGreaterOrEqual(5, 8)) { - AddDefinitionEscaped( - makefile, "_moc_predefs_cmd", - makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND")); - } - // Moc includes and compile definitions - { - auto GetIncludeDirs = [this, - localGen](std::string const& cfg) -> std::string { - // Get the include dirs for this target, without stripping the implicit - // include dirs off, see - // https://gitlab.kitware.com/cmake/cmake/issues/13667 - std::vector includeDirs; - localGen->GetIncludeDirectories(includeDirs, this->Target, "CXX", cfg, - false); - return cmJoin(includeDirs, ";"); - }; - auto GetCompileDefinitions = - [this, localGen](std::string const& cfg) -> std::string { - std::set defines; - localGen->AddCompileDefinitions(defines, this->Target, cfg, "CXX"); - return cmJoin(defines, ";"); - }; - - // Default configuration settings - std::string const includeDirs = GetIncludeDirs(this->ConfigDefault); - std::string const compileDefs = GetCompileDefinitions(this->ConfigDefault); - // Other configuration settings - for (std::string const& cfg : this->ConfigsList) { - { - std::string const configIncludeDirs = GetIncludeDirs(cfg); - if (configIncludeDirs != includeDirs) { - this->ConfigMocIncludes[cfg] = configIncludeDirs; - } - } - { - std::string const configCompileDefs = GetCompileDefinitions(cfg); - if (configCompileDefs != compileDefs) { - this->ConfigMocDefines[cfg] = configCompileDefs; - } - } - } - AddDefinitionEscaped(makefile, "_moc_include_dirs", includeDirs); - AddDefinitionEscaped(makefile, "_moc_compile_defs", compileDefs); - } - - // Moc executable - { - std::string mocExec; - std::string err; - - if (this->QtVersionMajor == "5") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::moc"); - if (tgt != nullptr) { - mocExec = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTOMOC: Qt5::moc target not found"; - } - } else if (this->QtVersionMajor == "4") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::moc"); - if (tgt != nullptr) { - mocExec = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTOMOC: Qt4::moc target not found"; - } - } else { - err = "The AUTOMOC feature supports only Qt 4 and Qt 5"; - } - - if (err.empty()) { - AddDefinitionEscaped(makefile, "_qt_moc_executable", mocExec); - } else { - err += " ("; - err += this->Target->GetName(); - err += ")"; - cmSystemTools::Error(err.c_str()); - } - } -} - -void cmQtAutoGeneratorInitializer::SetupCustomTargetsUic() -{ - cmMakefile* makefile = this->Target->Target->GetMakefile(); - - // Uic search paths - { - std::vector uicSearchPaths; - { - std::string const usp = - GetSafeProperty(this->Target, "AUTOUIC_SEARCH_PATHS"); - if (!usp.empty()) { - cmSystemTools::ExpandListArgument(usp, uicSearchPaths); - std::string const srcDir = makefile->GetCurrentSourceDirectory(); - for (std::string& path : uicSearchPaths) { - path = cmSystemTools::CollapseFullPath(path, srcDir); - } - } - } - AddDefinitionEscaped(makefile, "_uic_search_paths", uicSearchPaths); - } - // Uic target options - { - auto UicGetOpts = [this](std::string const& cfg) -> std::string { - std::vector opts; - this->Target->GetAutoUicOptions(opts, cfg); - return cmJoin(opts, ";"); - }; - - // Default settings - std::string const uicOpts = UicGetOpts(this->ConfigDefault); - AddDefinitionEscaped(makefile, "_uic_target_options", uicOpts); - - // Configuration specific settings - for (std::string const& cfg : this->ConfigsList) { - std::string const configUicOpts = UicGetOpts(cfg); - if (configUicOpts != uicOpts) { - this->ConfigUicOptions[cfg] = configUicOpts; - } - } - } - // .ui files skip and options - { - std::vector uiFileFiles; - std::vector> uiFileOptions; - { - std::string const uiExt = "ui"; - std::string pathError; - for (cmSourceFile* sf : makefile->GetSourceFiles()) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... - // Since we're iterating over source files that might be not in the - // target we need to check for path errors (not existing files). - std::string const& fPath = sf->GetFullPath(&pathError); - if (!pathError.empty()) { - pathError.clear(); - continue; - } - if (sf->GetExtension() == uiExt) { - std::string const absFile = cmSystemTools::GetRealPath(fPath); - // Check if the .ui file should be skipped - if (sf->GetPropertyAsBool("SKIP_AUTOUIC") || - sf->GetPropertyAsBool("SKIP_AUTOGEN")) { - this->UicSkip.insert(absFile); - } - // Check if the .ui file has uic options - std::string const uicOpts = GetSafeProperty(sf, "AUTOUIC_OPTIONS"); - if (!uicOpts.empty()) { - // Check if file isn't skipped - if (this->UicSkip.count(absFile) == 0) { - uiFileFiles.push_back(absFile); - std::vector optsVec; - cmSystemTools::ExpandListArgument(uicOpts, optsVec); - uiFileOptions.push_back(std::move(optsVec)); - } - } - } - } - } - AddDefinitionEscaped(makefile, "_qt_uic_options_files", uiFileFiles); - AddDefinitionEscaped(makefile, "_qt_uic_options_options", uiFileOptions); - } - - AddDefinitionEscaped(makefile, "_uic_skip", this->UicSkip); - - // Uic executable - { - std::string err; - std::string uicExec; - - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - if (this->QtVersionMajor == "5") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::uic"); - if (tgt != nullptr) { - uicExec = SafeString(tgt->ImportedGetLocation("")); - } else { - // Project does not use Qt5Widgets, but has AUTOUIC ON anyway - } - } else if (this->QtVersionMajor == "4") { - cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::uic"); - if (tgt != nullptr) { - uicExec = SafeString(tgt->ImportedGetLocation("")); - } else { - err = "AUTOUIC: Qt4::uic target not found"; - } - } else { - err = "The AUTOUIC feature supports only Qt 4 and Qt 5"; - } - - if (err.empty()) { - AddDefinitionEscaped(makefile, "_qt_uic_executable", uicExec); - } else { - err += " ("; - err += this->Target->GetName(); - err += ")"; - cmSystemTools::Error(err.c_str()); - } - } -} - -std::vector cmQtAutoGeneratorInitializer::AddGeneratedSource( - std::string const& filename, GeneratorT genType) -{ - std::vector genFiles; - // Register source file in makefile and source group - if (this->MultiConfig != MultiConfigT::MULTI) { - genFiles.push_back(filename); - } else { - for (std::string const& cfg : this->ConfigsList) { - genFiles.push_back(AppendFilenameSuffix(filename, "_" + cfg)); - } - } - { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - for (std::string const& genFile : genFiles) { - { - cmSourceFile* gFile = makefile->GetOrCreateSource(genFile, true); - gFile->SetProperty("GENERATED", "1"); - gFile->SetProperty("SKIP_AUTOGEN", "On"); - } - AddToSourceGroup(makefile, genFile, genType); - } - } - - // Add source file to target - if (this->MultiConfig != MultiConfigT::MULTI) { - this->Target->AddSource(filename); - } else { - for (std::string const& cfg : this->ConfigsList) { - std::string src = "$<$Target->AddSource(src); - } - } - - return genFiles; -} - -std::string cmQtAutoGeneratorInitializer::GetQtMajorVersion( - cmGeneratorTarget const* target) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string qtMajor = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); - if (qtMajor.empty()) { - qtMajor = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); - } - const char* targetQtVersion = - target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""); - if (targetQtVersion != nullptr) { - qtMajor = targetQtVersion; - } - return qtMajor; -} - -std::string cmQtAutoGeneratorInitializer::GetQtMinorVersion( - cmGeneratorTarget const* target, std::string const& qtVersionMajor) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string qtMinor; - if (qtVersionMajor == "5") { - qtMinor = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR"); - } - if (qtMinor.empty()) { - qtMinor = makefile->GetSafeDefinition("QT_VERSION_MINOR"); - } - - const char* targetQtVersion = - target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", ""); - if (targetQtVersion != nullptr) { - qtMinor = targetQtVersion; - } - return qtMinor; -} - -bool cmQtAutoGeneratorInitializer::QtVersionGreaterOrEqual( - unsigned long requestMajor, unsigned long requestMinor) const -{ - unsigned long majorUL(0); - unsigned long minorUL(0); - if (cmSystemTools::StringToULong(this->QtVersionMajor.c_str(), &majorUL) && - cmSystemTools::StringToULong(this->QtVersionMinor.c_str(), &minorUL)) { - return (majorUL > requestMajor) || - (majorUL == requestMajor && minorUL >= requestMinor); - } - return false; -} - -/// @brief Reads the resource files list from from a .qrc file -/// @arg fileName Must be the absolute path of the .qrc file -/// @return True if the rcc file was successfully read -bool cmQtAutoGeneratorInitializer::RccListInputs( - std::string const& fileName, std::vector& files, - std::string& error) -{ - if (!cmSystemTools::FileExists(fileName.c_str())) { - error = "rcc resource file does not exist:\n "; - error += Quoted(fileName); - error += "\n"; - return false; - } - if (!RccListOptions.empty()) { - // Use rcc for file listing - if (RccExecutable.empty()) { - error = "rcc executable not available"; - return false; - } - - // Run rcc list command in the directory of the qrc file with the pathless - // qrc file name argument. This way rcc prints relative paths. - // This avoids issues on Windows when the qrc file is in a path that - // contains non-ASCII characters. - std::string const fileDir = cmSystemTools::GetFilenamePath(fileName); - std::string const fileNameName = cmSystemTools::GetFilenameName(fileName); - - bool result = false; - int retVal = 0; - std::string rccStdOut; - std::string rccStdErr; - { - std::vector cmd; - cmd.push_back(RccExecutable); - cmd.insert(cmd.end(), RccListOptions.begin(), RccListOptions.end()); - cmd.push_back(fileNameName); - result = cmSystemTools::RunSingleCommand( - cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), - cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); - } - if (!result || retVal) { - error = "rcc list process failed for:\n "; - error += Quoted(fileName); - error += "\n"; - error += rccStdOut; - error += "\n"; - error += rccStdErr; - error += "\n"; - return false; - } - if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) { - return false; - } - } else { - // We can't use rcc for the file listing. - // Read the qrc file content into string and parse it. - { - std::string qrcContents; - { - cmsys::ifstream ifs(fileName.c_str()); - if (ifs) { - std::ostringstream osst; - osst << ifs.rdbuf(); - qrcContents = osst.str(); - } else { - error = "rcc file not readable:\n "; - error += Quoted(fileName); - error += "\n"; - return false; - } - } - // Parse string content - RccListParseContent(qrcContents, files); - } - } - - // Convert relative paths to absolute paths - RccListConvertFullPath(cmSystemTools::GetFilenamePath(fileName), files); - return true; -} diff --git a/Source/cmQtAutoGeneratorInitializer.h b/Source/cmQtAutoGeneratorInitializer.h deleted file mode 100644 index 0567437..0000000 --- a/Source/cmQtAutoGeneratorInitializer.h +++ /dev/null @@ -1,102 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmQtAutoGeneratorInitializer_h -#define cmQtAutoGeneratorInitializer_h - -#include "cmConfigure.h" // IWYU pragma: keep -#include "cmQtAutoGen.h" - -#include -#include -#include -#include - -class cmGeneratorTarget; - -/// @brief Initializes the QtAutoGen generators -class cmQtAutoGeneratorInitializer : public cmQtAutoGen -{ -public: - static std::string GetQtMajorVersion(cmGeneratorTarget const* target); - static std::string GetQtMinorVersion(cmGeneratorTarget const* target, - std::string const& qtVersionMajor); - - class Qrc - { - public: - Qrc() - : Generated(false) - , Unique(false) - { - } - - public: - std::string QrcFile; - std::string QrcName; - std::string PathChecksum; - std::string InfoFile; - std::string SettingsFile; - std::string RccFile; - bool Generated; - bool Unique; - std::vector Options; - std::vector Resources; - }; - -public: - cmQtAutoGeneratorInitializer(cmGeneratorTarget* target, bool mocEnabled, - bool uicEnabled, bool rccEnabled, - std::string const& qtVersionMajor); - - void InitCustomTargets(); - void SetupCustomTargets(); - -private: - void SetupCustomTargetsMoc(); - void SetupCustomTargetsUic(); - - std::vector AddGeneratedSource(std::string const& filename, - GeneratorT genType); - - bool QtVersionGreaterOrEqual(unsigned long requestMajor, - unsigned long requestMinor) const; - - bool RccListInputs(std::string const& fileName, - std::vector& files, - std::string& errorMessage); - -private: - cmGeneratorTarget* Target; - bool MocEnabled; - bool UicEnabled; - bool RccEnabled; - // Qt - std::string QtVersionMajor; - std::string QtVersionMinor; - std::string RccExecutable; - std::vector RccListOptions; - // Configurations - std::string ConfigDefault; - std::vector ConfigsList; - MultiConfigT MultiConfig; - // Names - std::string AutogenTargetName; - std::string AutogenFolder; - std::string AutogenInfoFile; - std::string AutogenSettingsFile; - // Directories - std::string DirInfo; - std::string DirBuild; - std::string DirWork; - // Sources - std::vector Headers; - std::vector Sources; - std::set MocSkip; - std::set UicSkip; - std::map ConfigMocIncludes; - std::map ConfigMocDefines; - std::map ConfigUicOptions; - std::vector Qrcs; -}; - -#endif -- cgit v0.12