summaryrefslogtreecommitdiffstats
path: root/Source/cmQtAutoGeneratorInitializer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmQtAutoGeneratorInitializer.cxx')
-rw-r--r--Source/cmQtAutoGeneratorInitializer.cxx2018
1 files changed, 1134 insertions, 884 deletions
diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx
index cecf165..bd692a2 100644
--- a/Source/cmQtAutoGeneratorInitializer.cxx
+++ b/Source/cmQtAutoGeneratorInitializer.cxx
@@ -1,505 +1,1214 @@
/* 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 "cmQtAutoGeneratorCommon.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"
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#include "cmGlobalVisualStudioGenerator.h"
-#endif
-
-#include "cmConfigure.h"
#include "cmsys/FStream.hxx"
+
#include <algorithm>
+#include <array>
+#include <deque>
#include <map>
#include <set>
+#include <sstream>
#include <string>
#include <utility>
#include <vector>
-static void utilCopyTargetProperty(cmTarget* destinationTarget,
- cmTarget* sourceTarget,
- const std::string& propertyName)
+inline static const char* SafeString(const char* value)
{
- const char* propertyValue = sourceTarget->GetProperty(propertyName);
- if (propertyValue) {
- destinationTarget->SetProperty(propertyName, propertyValue);
- }
+ return (value != nullptr) ? value : "";
}
-inline static bool PropertyEnabled(cmSourceFile* sourceFile, const char* key)
+inline static std::string GetSafeProperty(cmGeneratorTarget const* target,
+ const char* key)
{
- return cmSystemTools::IsOn(sourceFile->GetPropertyForUser(key));
+ return std::string(SafeString(target->GetProperty(key)));
}
-static std::string GetSafeProperty(cmGeneratorTarget const* target,
- const char* key)
+inline static std::string GetSafeProperty(cmSourceFile const* sf,
+ const char* key)
{
- const char* tmp = target->GetProperty(key);
- return std::string((tmp != CM_NULLPTR) ? tmp : "");
+ return std::string(SafeString(sf->GetProperty(key)));
}
-static std::string GetAutogenTargetName(cmGeneratorTarget const* target)
+static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
+ std::string const& value)
{
- std::string autogenTargetName = target->GetName();
- autogenTargetName += "_autogen";
- return autogenTargetName;
+ makefile->AddDefinition(key,
+ cmOutputConverter::EscapeForCMake(value).c_str());
}
-static std::string GetAutogenTargetFilesDir(cmGeneratorTarget const* target)
+static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
+ const std::vector<std::string>& values)
{
- cmMakefile* makefile = target->Target->GetMakefile();
- std::string targetDir = makefile->GetCurrentBinaryDirectory();
- targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory();
- targetDir += "/";
- targetDir += GetAutogenTargetName(target);
- targetDir += ".dir";
- return targetDir;
+ makefile->AddDefinition(
+ key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str());
}
-static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target)
+static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
+ const std::set<std::string>& values)
{
- std::string targetDir = GetSafeProperty(target, "AUTOGEN_BUILD_DIR");
- if (targetDir.empty()) {
- cmMakefile* makefile = target->Target->GetMakefile();
- targetDir = makefile->GetCurrentBinaryDirectory();
- targetDir += "/";
- targetDir += GetAutogenTargetName(target);
- }
- return targetDir;
+ makefile->AddDefinition(
+ key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str());
}
-static std::string GetQtMajorVersion(cmGeneratorTarget const* target)
+static void AddDefinitionEscaped(
+ cmMakefile* makefile, const char* key,
+ const std::vector<std::vector<std::string>>& lists)
{
- cmMakefile* makefile = target->Target->GetMakefile();
- std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
- if (qtMajorVersion.empty()) {
- qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
+ std::vector<std::string> seplist;
+ for (const std::vector<std::string>& list : lists) {
+ std::string blist = "{";
+ blist += cmJoin(list, ";");
+ blist += "}";
+ seplist.push_back(std::move(blist));
}
- const char* targetQtVersion =
- target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "");
- if (targetQtVersion != CM_NULLPTR) {
- qtMajorVersion = targetQtVersion;
- }
- return qtMajorVersion;
+ makefile->AddDefinition(key, cmOutputConverter::EscapeForCMake(
+ cmJoin(seplist, cmQtAutoGen::listSep))
+ .c_str());
}
-static std::string GetQtMinorVersion(cmGeneratorTarget const* target,
- const std::string& qtMajorVersion)
+static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName,
+ cmQtAutoGen::Generator genType)
{
- cmMakefile* makefile = target->Target->GetMakefile();
- std::string qtMinorVersion;
- if (qtMajorVersion == "5") {
- qtMinorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR");
- }
- if (qtMinorVersion.empty()) {
- qtMinorVersion = makefile->GetSafeDefinition("QT_VERSION_MINOR");
+ cmSourceGroup* sourceGroup = nullptr;
+ // Acquire source group
+ {
+ std::string property;
+ std::string groupName;
+ {
+ std::array<std::string, 2> props;
+ // Use generator specific group name
+ switch (genType) {
+ case cmQtAutoGen::MOC:
+ props[0] = "AUTOMOC_SOURCE_GROUP";
+ break;
+ case cmQtAutoGen::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;
+ }
+ }
}
-
- const char* targetQtVersion =
- target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", "");
- if (targetQtVersion != CM_NULLPTR) {
- qtMinorVersion = targetQtVersion;
+ if (sourceGroup != nullptr) {
+ sourceGroup->AddGroupFile(fileName);
}
- return qtMinorVersion;
+ return true;
}
-static bool QtVersionGreaterOrEqual(const std::string& major,
- const std::string& minor,
- unsigned long requestMajor,
- unsigned long requestMinor)
+static void AddCleanFile(cmMakefile* makefile, std::string const& fileName)
{
- unsigned long majorUL(0);
- unsigned long minorUL(0);
- if (cmSystemTools::StringToULong(major.c_str(), &majorUL) &&
- cmSystemTools::StringToULong(minor.c_str(), &minorUL)) {
- return (majorUL > requestMajor) ||
- (majorUL == requestMajor && minorUL >= requestMinor);
- }
- return false;
+ makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(),
+ false);
}
-static void GetCompileDefinitionsAndDirectories(
- cmGeneratorTarget const* target, const std::string& config,
- std::string& incs, std::string& defs)
+static std::string FileProjectRelativePath(cmMakefile* makefile,
+ std::string const& fileName)
{
- cmLocalGenerator* localGen = target->GetLocalGenerator();
- {
- std::vector<std::string> includeDirs;
- // Get the include dirs for this target, without stripping the implicit
- // include dirs off, see
- // https://gitlab.kitware.com/cmake/cmake/issues/13667
- localGen->GetIncludeDirectories(includeDirs, target, "CXX", config, false);
- incs = cmJoin(includeDirs, ";");
- }
+ std::string res;
{
- std::set<std::string> defines;
- localGen->AddCompileDefinitions(defines, target, config, "CXX");
- defs += cmJoin(defines, ";");
+ 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;
}
-static bool IsMultiConfig(cmGlobalGenerator* globalGen)
+/* @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)
{
- // FIXME: Xcode does not support per-config sources, yet.
- // (EXCLUDED_SOURCE_FILE_NAMES)
- // Treat it as a single configuration generator meanwhile.
- if (globalGen->GetName().find("Xcode") != std::string::npos) {
- return false;
- }
- // FIXME: Visual Studio does not fully support per-config sources yet.
- if (globalGen->GetName().find("Visual Studio") != std::string::npos) {
- return false;
+ bool cycle = false;
+ if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) &&
+ (targetDepend->GetType() == cmStateEnums::STATIC_LIBRARY)) {
+ std::set<cmGeneratorTarget const*> knownLibs;
+ std::deque<cmGeneratorTarget const*> 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 globalGen->IsMultiConfig();
+ 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(cmQtAutoGen::WRAP)
+{
+ this->QtVersionMinor = cmQtAutoGeneratorInitializer::GetQtMinorVersion(
+ target, this->QtVersionMajor);
}
-static std::vector<std::string> GetConfigurations(
- cmMakefile* makefile, std::string* config = CM_NULLPTR)
+void cmQtAutoGeneratorInitializer::InitCustomTargets()
{
- std::vector<std::string> configs;
+ 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
{
- std::string cfg = makefile->GetConfigurations(configs);
- if (config != CM_NULLPTR) {
- *config = cfg;
+ if (!globalGen->IsMultiConfig()) {
+ this->MultiConfig = cmQtAutoGen::SINGLE;
}
+
+ // FIXME: Xcode does not support per-config sources, yet.
+ // (EXCLUDED_SOURCE_FILE_NAMES)
+ // if (globalGen->GetName().find("Xcode") != std::string::npos) {
+ // return cmQtAutoGen::FULL;
+ //}
+
+ // FIXME: Visual Studio does not support per-config sources, yet.
+ // (EXCLUDED_SOURCE_FILE_NAMES)
+ // if (globalGen->GetName().find("Visual Studio") != std::string::npos) {
+ // return cmQtAutoGen::FULL;
+ //}
}
- // Add empty configuration on demand
- if (configs.empty()) {
- configs.push_back("");
+
+ // 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);
}
- return configs;
-}
-static std::vector<std::string> GetConfigurationSuffixes(cmMakefile* makefile)
-{
- std::vector<std::string> suffixes;
- if (IsMultiConfig(makefile->GetGlobalGenerator())) {
- makefile->GetConfigurations(suffixes);
- for (std::vector<std::string>::iterator it = suffixes.begin();
- it != suffixes.end(); ++it) {
- it->insert(0, "_");
+ // Autogen files
+ {
+ this->AutogenInfoFile = this->DirInfo;
+ this->AutogenInfoFile += "/AutogenInfo.cmake";
+
+ this->AutogenSettingsFile = this->DirInfo;
+ this->AutogenSettingsFile += "/AutogenOldSettings.cmake";
+ }
+
+ // 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;
}
}
- if (suffixes.empty()) {
- suffixes.push_back("");
+
+ std::set<std::string> autogenDependFiles;
+ std::set<cmTarget*> autogenDependTargets;
+ std::vector<std::string> 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 == cmQtAutoGen::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);
+ }
+ }
}
- return suffixes;
-}
-static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
- const std::string& value)
-{
- makefile->AddDefinition(key,
- cmOutputConverter::EscapeForCMake(value).c_str());
-}
+ // Add moc compilation to generated files list
+ if (this->MocEnabled) {
+ std::string const mocsComp = this->DirBuild + "/mocs_compilation.cpp";
+ auto files = this->AddGeneratedSource(mocsComp, cmQtAutoGen::MOC);
+ for (std::string& file : files) {
+ autogenProvides.push_back(std::move(file));
+ }
+ }
-static void AddDefinitionEscaped(cmMakefile* makefile, const char* key,
- const std::vector<std::string>& values)
-{
- makefile->AddDefinition(
- key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str());
-}
+ // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES
+ if (this->MocEnabled || this->UicEnabled) {
+ std::string includeDir = this->DirBuild + "/include";
+ if (this->MultiConfig != cmQtAutoGen::SINGLE) {
+ includeDir += "_$<CONFIG>";
+ }
+ this->Target->AddIncludeDirectory(includeDir, true);
+ }
-static bool AddToSourceGroup(cmMakefile* makefile, const std::string& fileName,
- cmQtAutoGeneratorCommon::GeneratorType genType)
-{
- cmSourceGroup* sourceGroup = CM_NULLPTR;
- // Acquire source group
+ // 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<std::string> 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<std::string> generatedSources;
+ std::vector<std::string> generatedHeaders;
{
- const char* groupName = CM_NULLPTR;
- // Use generator specific group name
- switch (genType) {
- case cmQtAutoGeneratorCommon::MOC:
- groupName =
- makefile->GetState()->GetGlobalProperty("AUTOMOC_SOURCE_GROUP");
- break;
- case cmQtAutoGeneratorCommon::RCC:
- groupName =
- makefile->GetState()->GetGlobalProperty("AUTORCC_SOURCE_GROUP");
+ std::string const qrcExt = "qrc";
+ std::vector<cmSourceFile*> 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) {
+ const std::vector<cmSourceFile*>& allSources = makefile->GetSourceFiles();
+ for (cmSourceFile* sf : allSources) {
+ // sf->GetExtension() is only valid after sf->GetFullPath() ...
+ std::string const& fPath = sf->GetFullPath();
+ 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;
- default:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Process GENERATED file
+ policyAccept = true;
break;
}
- // Use default group name on demand
- if ((groupName == CM_NULLPTR) || (*groupName == 0)) {
- groupName =
- makefile->GetState()->GetGlobalProperty("AUTOGEN_SOURCE_GROUP");
+
+ 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(cmQtAutoGen::Quoted(absFile)).append("\n");
+ }
+ for (const std::string& absFile : generatedSources) {
+ msg.append(" ").append(cmQtAutoGen::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);
+ }
}
- // Generate a source group on demand
- if ((groupName != CM_NULLPTR) && (*groupName != 0)) {
- {
- const char* delimiter =
- makefile->GetDefinition("SOURCE_GROUP_DELIMITER");
- if (delimiter == CM_NULLPTR) {
- delimiter = "\\";
+ // 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<std::string> 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;
}
- std::vector<std::string> folders =
- cmSystemTools::tokenize(groupName, delimiter);
- sourceGroup = makefile->GetSourceGroup(folders);
- if (sourceGroup == CM_NULLPTR) {
- makefile->AddSourceGroup(folders);
- sourceGroup = makefile->GetSourceGroup(folders);
+ }
+ }
+ // 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.cmake";
}
}
- if (sourceGroup == CM_NULLPTR) {
- cmSystemTools::Error(
- "Autogen: Could not create or find source group: ",
- cmQtAutoGeneratorCommon::Quoted(groupName).c_str());
- return false;
+ }
+ // RCC options
+ for (Qrc& qrc : this->Qrcs) {
+ // Target options
+ std::vector<std::string> 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<std::string> nameOpts;
+ nameOpts.emplace_back("-name");
+ nameOpts.emplace_back(std::move(name));
+ cmQtAutoGen::RccMergeOptions(opts, nameOpts, QtV5);
+ }
+ // Merge file option
+ cmQtAutoGen::RccMergeOptions(opts, qrc.Options, QtV5);
+ qrc.Options = std::move(opts);
+ }
+ for (Qrc& qrc : this->Qrcs) {
+ // Register file at target
+ std::vector<std::string> const ccOutput =
+ this->AddGeneratedSource(qrc.RccFile, cmQtAutoGen::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("$<CONFIGURATION>");
+ 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<std::string> ccDepends;
+ // Add the .qrc file to the custom target dependencies
+ ccDepends.push_back(qrc.QrcFile);
+
+ 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<std::string> ccByproducts;
+ std::vector<std::string> ccDepends;
+ // Add the .qrc file to the custom command dependencies
+ ccDepends.push_back(qrc.QrcFile);
+
+ // Add the resource files to the dependencies
+ {
+ std::string error;
+ if (cmQtAutoGen::RccListInputs(this->RccExecutable,
+ this->RccListOptions, 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);
}
}
}
- if (sourceGroup != CM_NULLPTR) {
- sourceGroup->AddGroupFile(fileName);
+
+ // 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<std::string> 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("$<CONFIGURATION>");
+ 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<std::string> no_output;
+ const std::vector<std::string> 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 {
+
+ // Convert file dependencies std::set to std::vector
+ std::vector<std::string> autogenDepends(autogenDependFiles.begin(),
+ autogenDependFiles.end());
+
+ // Add link library target dependencies to the autogen target
+ // dependencies
+ 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)) {
+ std::string util;
+ if (this->ConfigsList.size() > 1) {
+ util += "$<$<CONFIG:";
+ util += config;
+ util += ">:";
+ }
+ util += libTarget->GetName();
+ if (this->ConfigsList.size() > 1) {
+ util += ">";
+ }
+ autogenDepends.push_back(util);
+ }
+ }
+ }
+ }
+
+ // Create autogen target
+ cmTarget* autogenTarget = makefile->AddUtilityCommand(
+ this->AutogenTargetName, cmMakefile::TargetOrigin::Generator, true,
+ this->DirWork.c_str(), /*byproducts=*/autogenProvides, autogenDepends,
+ 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);
+ }
}
- return true;
}
-static void AddGeneratedSource(cmMakefile* makefile,
- const std::string& filename,
- cmQtAutoGeneratorCommon::GeneratorType genType)
+void cmQtAutoGeneratorInitializer::SetupCustomTargets()
{
- cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true);
- gFile->SetProperty("GENERATED", "1");
- gFile->SetProperty("SKIP_AUTOGEN", "On");
+ cmMakefile* makefile = this->Target->Target->GetMakefile();
- AddToSourceGroup(makefile, filename, genType);
-}
+ // forget the variables added here afterwards again:
+ cmMakefile::ScopePushPop varScope(makefile);
+ static_cast<void>(varScope);
-static void AcquireScanFiles(cmGeneratorTarget const* target,
- std::vector<std::string>& mocUicSources,
- std::vector<std::string>& mocUicHeaders,
- std::vector<std::string>& mocSkipList,
- std::vector<std::string>& uicSkipList)
-{
- const bool mocTarget = target->GetPropertyAsBool("AUTOMOC");
- const bool uicTarget = target->GetPropertyAsBool("AUTOUIC");
-
- std::vector<cmSourceFile*> srcFiles;
- target->GetConfigCommonSourceFiles(srcFiles);
- for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
- fileIt != srcFiles.end(); ++fileIt) {
- cmSourceFile* sf = *fileIt;
- const cmSystemTools::FileFormat fileType =
- cmSystemTools::GetFileFormat(sf->GetExtension().c_str());
-
- if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) &&
- !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
- continue;
+ // Configuration suffixes
+ std::map<std::string, std::string> configSuffixes;
+ for (std::string const& cfg : this->ConfigsList) {
+ std::string& suffix = configSuffixes[cfg];
+ suffix = "_";
+ suffix += cfg;
+ }
+
+ // Basic setup
+ AddDefinitionEscaped(makefile, "_multi_config",
+ cmQtAutoGen::MultiConfigName(this->MultiConfig));
+ AddDefinitionEscaped(makefile, "_build_dir", this->DirBuild);
+
+ 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 (PropertyEnabled(sf, "GENERATED") &&
- !target->GetPropertyAsBool("__UNDOCUMENTED_AUTOGEN_GENERATED_FILES")) {
- // FIXME: Add a policy whose NEW behavior allows generated files.
- // The implementation already works. We disable it here to avoid
- // changing behavior for existing projects that do not expect it.
- continue;
+ }
+ 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 += cmQtAutoGen::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);
}
- const std::string absFile =
- cmsys::SystemTools::GetRealPath(sf->GetFullPath());
- // Skip flags
- const bool skipAll = PropertyEnabled(sf, "SKIP_AUTOGEN");
- const bool mocSkip = skipAll || PropertyEnabled(sf, "SKIP_AUTOMOC");
- const bool uicSkip = skipAll || PropertyEnabled(sf, "SKIP_AUTOUIC");
- // Add file name to skip lists.
- // Do this even when the file is not added to the sources/headers lists
- // because the file name may be extracted from an other file when
- // processing
- if (mocSkip) {
- mocSkipList.push_back(absFile);
+
+ 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 += cmQtAutoGen::Quoted(fileName);
+ error += " for writing.";
+ cmSystemTools::Error(error.c_str());
}
- if (uicSkip) {
- uicSkipList.push_back(absFile);
+ return static_cast<bool>(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);
}
- if ((mocTarget && !mocSkip) || (uicTarget && !uicSkip)) {
- // Add file name to sources or headers list
- switch (fileType) {
- case cmSystemTools::CXX_FILE_FORMAT:
- mocUicSources.push_back(absFile);
- break;
- case cmSystemTools::HEADER_FILE_FORMAT:
- mocUicHeaders.push_back(absFile);
- break;
- default:
- break;
+ // Append custom definitions to info file
+ // --------------------------------------
+ cmsys::ofstream ofs;
+ if (ReOpenInfoFile(ofs, this->AutogenInfoFile)) {
+ auto OfsWriteMap = [&ofs](
+ const char* key, std::map<std::string, std::string> 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 != cmQtAutoGen::SINGLE) {
+ std::map<std::string, std::string> settingsFiles;
+ for (std::string const& cfg : this->ConfigsList) {
+ settingsFiles[cfg] = cmQtAutoGen::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<std::string, std::string> 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 != cmQtAutoGen::SINGLE) {
+ std::map<std::string, std::string> settingsFiles;
+ for (std::string const& cfg : this->ConfigsList) {
+ settingsFiles[cfg] =
+ cmQtAutoGen::AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg);
+ }
+ OfsWriteMap("ARCC_SETTINGS_FILE", settingsFiles);
+ }
+ }
+ } else {
+ break;
}
}
}
}
-static void MocSetupAutoTarget(
- cmGeneratorTarget const* target, const std::string& autogenTargetName,
- std::string const& qtMajorVersion, std::string const& config,
- std::vector<std::string> const& configs,
- std::vector<std::string> const& mocSkipList,
- std::map<std::string, std::string>& configMocIncludes,
- std::map<std::string, std::string>& configMocDefines)
+void cmQtAutoGeneratorInitializer::SetupCustomTargetsMoc()
{
- cmLocalGenerator* lg = target->GetLocalGenerator();
- cmMakefile* makefile = target->Target->GetMakefile();
+ cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
+ cmMakefile* makefile = this->Target->Target->GetMakefile();
+ AddDefinitionEscaped(makefile, "_moc_skip", this->MocSkip);
AddDefinitionEscaped(makefile, "_moc_options",
- GetSafeProperty(target, "AUTOMOC_MOC_OPTIONS"));
- AddDefinitionEscaped(makefile, "_moc_skip", mocSkipList);
+ GetSafeProperty(this->Target, "AUTOMOC_MOC_OPTIONS"));
AddDefinitionEscaped(makefile, "_moc_relaxed_mode",
makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE") ? "TRUE"
: "FALSE");
- AddDefinitionEscaped(makefile, "_moc_depend_filters",
- GetSafeProperty(target, "AUTOMOC_DEPEND_FILTERS"));
-
- if (QtVersionGreaterOrEqual(
- qtMajorVersion, GetQtMinorVersion(target, qtMajorVersion), 5, 8)) {
+ 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
{
- // Default settings
- std::string incs;
- std::string compileDefs;
- GetCompileDefinitionsAndDirectories(target, config, incs, compileDefs);
- AddDefinitionEscaped(makefile, "_moc_incs", incs);
- AddDefinitionEscaped(makefile, "_moc_compile_defs", compileDefs);
-
- // Configuration specific settings
- for (std::vector<std::string>::const_iterator li = configs.begin();
- li != configs.end(); ++li) {
- std::string configIncs;
- std::string configCompileDefs;
- GetCompileDefinitionsAndDirectories(target, *li, configIncs,
- configCompileDefs);
- if (configIncs != incs) {
- configMocIncludes[*li] = cmOutputConverter::EscapeForCMake(configIncs);
+ 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<std::string> includeDirs;
+ localGen->GetIncludeDirectories(includeDirs, this->Target, "CXX", cfg,
+ false);
+ return cmJoin(includeDirs, ";");
+ };
+ auto GetCompileDefinitions =
+ [this, localGen](std::string const& cfg) -> std::string {
+ std::set<std::string> 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;
+ }
}
- if (configCompileDefs != compileDefs) {
- configMocDefines[*li] =
- cmOutputConverter::EscapeForCMake(configCompileDefs);
+ {
+ 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;
- const char* mocExec = CM_NULLPTR;
- if (qtMajorVersion == "5") {
- cmGeneratorTarget* qt5Moc = lg->FindGeneratorTargetToUse("Qt5::moc");
- if (qt5Moc != CM_NULLPTR) {
- mocExec = qt5Moc->ImportedGetLocation("");
+
+ if (this->QtVersionMajor == "5") {
+ cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt5::moc");
+ if (tgt != nullptr) {
+ mocExec = SafeString(tgt->ImportedGetLocation(""));
} else {
- err = "Qt5::moc target not found " + autogenTargetName;
+ err = "AUTOMOC: Qt5::moc target not found";
}
- } else if (qtMajorVersion == "4") {
- cmGeneratorTarget* qt4Moc = lg->FindGeneratorTargetToUse("Qt4::moc");
- if (qt4Moc != CM_NULLPTR) {
- mocExec = qt4Moc->ImportedGetLocation("");
+ } else if (this->QtVersionMajor == "4") {
+ cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::moc");
+ if (tgt != nullptr) {
+ mocExec = SafeString(tgt->ImportedGetLocation(""));
} else {
- err = "Qt4::moc target not found " + autogenTargetName;
+ err = "AUTOMOC: Qt4::moc target not found";
}
} else {
- err = "The CMAKE_AUTOMOC feature supports only Qt 4 and Qt 5 ";
- err += autogenTargetName;
+ err = "The AUTOMOC feature supports only Qt 4 and Qt 5";
}
- // Add definition or error
+
if (err.empty()) {
- AddDefinitionEscaped(makefile, "_qt_moc_executable",
- mocExec ? mocExec : "");
+ AddDefinitionEscaped(makefile, "_qt_moc_executable", mocExec);
} else {
+ err += " (";
+ err += this->Target->GetName();
+ err += ")";
cmSystemTools::Error(err.c_str());
}
}
}
-static void UicGetOpts(cmGeneratorTarget const* target,
- const std::string& config, std::string& optString)
+void cmQtAutoGeneratorInitializer::SetupCustomTargetsUic()
{
- std::vector<std::string> opts;
- target->GetAutoUicOptions(opts, config);
- optString = cmJoin(opts, ";");
-}
-
-static void UicSetupAutoTarget(
- cmGeneratorTarget const* target, std::string const& qtMajorVersion,
- std::string const& config, std::vector<std::string> const& configs,
- std::vector<std::string> const& uicSkipList,
- std::map<std::string, std::string>& configUicOptions)
-{
- cmLocalGenerator* lg = target->GetLocalGenerator();
- cmMakefile* makefile = target->Target->GetMakefile();
-
- AddDefinitionEscaped(makefile, "_uic_skip", uicSkipList);
+ cmMakefile* makefile = this->Target->Target->GetMakefile();
// Uic search paths
{
std::vector<std::string> uicSearchPaths;
- cmSystemTools::ExpandListArgument(
- GetSafeProperty(target, "AUTOUIC_SEARCH_PATHS"), uicSearchPaths);
- const std::string srcDir = makefile->GetCurrentSourceDirectory();
- for (std::vector<std::string>::iterator it = uicSearchPaths.begin();
- it != uicSearchPaths.end(); ++it) {
- *it = cmSystemTools::CollapseFullPath(*it, srcDir);
+ {
+ 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<std::string> opts;
+ this->Target->GetAutoUicOptions(opts, cfg);
+ return cmJoin(opts, ";");
+ };
+
// Default settings
- std::string uicOpts;
- UicGetOpts(target, config, uicOpts);
+ std::string const uicOpts = UicGetOpts(this->ConfigDefault);
AddDefinitionEscaped(makefile, "_uic_target_options", uicOpts);
// Configuration specific settings
- for (std::vector<std::string>::const_iterator li = configs.begin();
- li != configs.end(); ++li) {
- std::string configUicOpts;
- UicGetOpts(target, *li, configUicOpts);
+ for (std::string const& cfg : this->ConfigsList) {
+ std::string const configUicOpts = UicGetOpts(cfg);
if (configUicOpts != uicOpts) {
- configUicOptions[*li] =
- cmOutputConverter::EscapeForCMake(configUicOpts);
+ this->ConfigUicOptions[cfg] = configUicOpts;
}
}
}
- // Uic files options
+ // .ui files skip and options
{
std::vector<std::string> uiFileFiles;
- std::vector<std::string> uiFileOptions;
+ std::vector<std::vector<std::string>> uiFileOptions;
{
- std::set<std::string> skipped;
- skipped.insert(uicSkipList.begin(), uicSkipList.end());
-
- const std::vector<cmSourceFile*> uiFilesWithOptions =
- makefile->GetQtUiFilesWithOptions();
- for (std::vector<cmSourceFile*>::const_iterator fileIt =
- uiFilesWithOptions.begin();
- fileIt != uiFilesWithOptions.end(); ++fileIt) {
- cmSourceFile* sf = *fileIt;
- const std::string absFile =
- cmsys::SystemTools::GetRealPath(sf->GetFullPath());
- if (skipped.insert(absFile).second) {
- // The file wasn't skipped
- uiFileFiles.push_back(absFile);
- {
- std::string opts = sf->GetProperty("AUTOUIC_OPTIONS");
- cmSystemTools::ReplaceString(opts, ";",
- cmQtAutoGeneratorCommon::listSep);
- uiFileOptions.push_back(opts);
+ std::string const uiExt = "ui";
+ for (cmSourceFile* sf : makefile->GetSourceFiles()) {
+ // sf->GetExtension() is only valid after sf->GetFullPath() ...
+ std::string const& fPath = sf->GetFullPath();
+ 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<std::string> optsVec;
+ cmSystemTools::ExpandListArgument(uicOpts, optsVec);
+ uiFileOptions.push_back(std::move(optsVec));
+ }
}
}
}
@@ -508,589 +1217,130 @@ static void UicSetupAutoTarget(
AddDefinitionEscaped(makefile, "_qt_uic_options_options", uiFileOptions);
}
+ AddDefinitionEscaped(makefile, "_uic_skip", this->UicSkip);
+
// Uic executable
{
std::string err;
- const char* uicExec = CM_NULLPTR;
- if (qtMajorVersion == "5") {
- cmGeneratorTarget* qt5Uic = lg->FindGeneratorTargetToUse("Qt5::uic");
- if (qt5Uic != CM_NULLPTR) {
- uicExec = qt5Uic->ImportedGetLocation("");
+ 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 (qtMajorVersion == "4") {
- cmGeneratorTarget* qt4Uic = lg->FindGeneratorTargetToUse("Qt4::uic");
- if (qt4Uic != CM_NULLPTR) {
- uicExec = qt4Uic->ImportedGetLocation("");
+ } else if (this->QtVersionMajor == "4") {
+ cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::uic");
+ if (tgt != nullptr) {
+ uicExec = SafeString(tgt->ImportedGetLocation(""));
} else {
- err = "Qt4::uic target not found " + target->GetName();
+ err = "AUTOUIC: Qt4::uic target not found";
}
} else {
- err = "The CMAKE_AUTOUIC feature supports only Qt 4 and Qt 5 ";
- err += target->GetName();
+ err = "The AUTOUIC feature supports only Qt 4 and Qt 5";
}
- // Add definition or error
+
if (err.empty()) {
- AddDefinitionEscaped(makefile, "_qt_uic_executable",
- uicExec ? uicExec : "");
+ AddDefinitionEscaped(makefile, "_qt_uic_executable", uicExec);
} else {
+ err += " (";
+ err += this->Target->GetName();
+ err += ")";
cmSystemTools::Error(err.c_str());
}
}
}
-static std::string RccGetExecutable(cmGeneratorTarget const* target,
- const std::string& qtMajorVersion)
+std::vector<std::string> cmQtAutoGeneratorInitializer::AddGeneratedSource(
+ std::string const& filename, cmQtAutoGen::Generator genType)
{
- std::string rccExec;
- cmLocalGenerator* lg = target->GetLocalGenerator();
- if (qtMajorVersion == "5") {
- cmGeneratorTarget* qt5Rcc = lg->FindGeneratorTargetToUse("Qt5::rcc");
- if (qt5Rcc != CM_NULLPTR) {
- rccExec = qt5Rcc->ImportedGetLocation("");
- } else {
- cmSystemTools::Error("Qt5::rcc target not found ",
- target->GetName().c_str());
- }
- } else if (qtMajorVersion == "4") {
- cmGeneratorTarget* qt4Rcc = lg->FindGeneratorTargetToUse("Qt4::rcc");
- if (qt4Rcc != CM_NULLPTR) {
- rccExec = qt4Rcc->ImportedGetLocation("");
- } else {
- cmSystemTools::Error("Qt4::rcc target not found ",
- target->GetName().c_str());
- }
+ std::vector<std::string> genFiles;
+ // Register source file in makefile and source group
+ if (this->MultiConfig != cmQtAutoGen::FULL) {
+ genFiles.push_back(filename);
} else {
- cmSystemTools::Error(
- "The CMAKE_AUTORCC feature supports only Qt 4 and Qt 5 ",
- target->GetName().c_str());
- }
- return rccExec;
-}
-
-static void RccMergeOptions(std::vector<std::string>& opts,
- const std::vector<std::string>& fileOpts,
- bool isQt5)
-{
- static const char* valueOptions[] = { "name", "root", "compress",
- "threshold" };
- std::vector<std::string> extraOpts;
- for (std::vector<std::string>::const_iterator fit = fileOpts.begin();
- fit != fileOpts.end(); ++fit) {
- std::vector<std::string>::iterator existingIt =
- std::find(opts.begin(), opts.end(), *fit);
- if (existingIt != opts.end()) {
- const char* optName = fit->c_str();
- if (*optName == '-') {
- ++optName;
- if (isQt5 && *optName == '-') {
- ++optName;
- }
- }
- // Test if this is a value option and change the existing value
- if ((optName != fit->c_str()) &&
- std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions),
- cmStrCmp(optName)) != cmArrayEnd(valueOptions)) {
- const std::vector<std::string>::iterator existValueIt(existingIt + 1);
- const std::vector<std::string>::const_iterator fileValueIt(fit + 1);
- if ((existValueIt != opts.end()) && (fileValueIt != fileOpts.end())) {
- *existValueIt = *fileValueIt;
- ++fit;
- }
- }
- } else {
- extraOpts.push_back(*fit);
+ for (std::string const& cfg : this->ConfigsList) {
+ genFiles.push_back(
+ cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg));
}
}
- opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
-}
-
-static void RccSetupAutoTarget(cmGeneratorTarget const* target,
- const std::string& qtMajorVersion)
-{
- cmMakefile* makefile = target->Target->GetMakefile();
- const bool qtMajorVersion5 = (qtMajorVersion == "5");
- const std::string rccCommand = RccGetExecutable(target, qtMajorVersion);
- std::vector<std::string> _rcc_files;
- std::vector<std::string> _rcc_inputs;
- std::vector<std::string> rccFileFiles;
- std::vector<std::string> rccFileOptions;
- std::vector<std::string> rccOptionsTarget;
- if (const char* opts = target->GetProperty("AUTORCC_OPTIONS")) {
- cmSystemTools::ExpandListArgument(opts, rccOptionsTarget);
- }
-
- std::vector<cmSourceFile*> srcFiles;
- target->GetConfigCommonSourceFiles(srcFiles);
- for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
- fileIt != srcFiles.end(); ++fileIt) {
- cmSourceFile* sf = *fileIt;
- if ((sf->GetExtension() == "qrc") &&
- !PropertyEnabled(sf, "SKIP_AUTOGEN") &&
- !PropertyEnabled(sf, "SKIP_AUTORCC")) {
- const std::string absFile =
- cmsys::SystemTools::GetRealPath(sf->GetFullPath());
- // qrc file
- _rcc_files.push_back(absFile);
- // qrc file entries
- {
- std::string entriesList = "{";
- // Read input file list only for non generated .qrc files.
- if (!PropertyEnabled(sf, "GENERATED")) {
- std::string error;
- std::vector<std::string> files;
- if (cmQtAutoGeneratorCommon::RccListInputs(
- qtMajorVersion, rccCommand, absFile, files, &error)) {
- entriesList += cmJoin(files, cmQtAutoGeneratorCommon::listSep);
- } else {
- cmSystemTools::Error(error.c_str());
- }
- }
- entriesList += "}";
- _rcc_inputs.push_back(entriesList);
- }
- // rcc options for this qrc file
+ {
+ cmMakefile* makefile = this->Target->Target->GetMakefile();
+ for (std::string const& genFile : genFiles) {
{
- // Merged target and file options
- std::vector<std::string> rccOptions(rccOptionsTarget);
- if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) {
- std::vector<std::string> optsVec;
- cmSystemTools::ExpandListArgument(prop, optsVec);
- RccMergeOptions(rccOptions, optsVec, qtMajorVersion5);
- }
- // Only store non empty options lists
- if (!rccOptions.empty()) {
- rccFileFiles.push_back(absFile);
- rccFileOptions.push_back(
- cmJoin(rccOptions, cmQtAutoGeneratorCommon::listSep));
- }
+ cmSourceFile* gFile = makefile->GetOrCreateSource(genFile, true);
+ gFile->SetProperty("GENERATED", "1");
+ gFile->SetProperty("SKIP_AUTOGEN", "On");
}
+ AddToSourceGroup(makefile, genFile, genType);
}
}
- AddDefinitionEscaped(makefile, "_qt_rcc_executable", rccCommand);
- AddDefinitionEscaped(makefile, "_rcc_files", _rcc_files);
- AddDefinitionEscaped(makefile, "_rcc_inputs", _rcc_inputs);
- AddDefinitionEscaped(makefile, "_rcc_options_files", rccFileFiles);
- AddDefinitionEscaped(makefile, "_rcc_options_options", rccFileOptions);
-}
-
-void cmQtAutoGeneratorInitializer::InitializeAutogenSources(
- cmGeneratorTarget* target)
-{
- if (target->GetPropertyAsBool("AUTOMOC")) {
- cmMakefile* makefile = target->Target->GetMakefile();
- const std::vector<std::string> suffixes =
- GetConfigurationSuffixes(makefile);
- // Get build directory
- const std::string autogenBuildDir = GetAutogenTargetBuildDir(target);
- // Register all compilation files as generated
- for (std::vector<std::string>::const_iterator it = suffixes.begin();
- it != suffixes.end(); ++it) {
- std::string mcFile = autogenBuildDir + "/mocs_compilation";
- mcFile += *it;
- mcFile += ".cpp";
- AddGeneratedSource(makefile, mcFile, cmQtAutoGeneratorCommon::MOC);
- }
- // Mocs compilation file
- if (IsMultiConfig(target->GetGlobalGenerator())) {
- target->AddSource(autogenBuildDir + "/mocs_compilation_$<CONFIG>.cpp");
- } else {
- target->AddSource(autogenBuildDir + "/mocs_compilation.cpp");
+ // Add source file to target
+ if (this->MultiConfig != cmQtAutoGen::FULL) {
+ this->Target->AddSource(filename);
+ } else {
+ for (std::string const& cfg : this->ConfigsList) {
+ std::string src = "$<$<CONFIG:";
+ src += cfg;
+ src += ">:";
+ src += cmQtAutoGen::AppendFilenameSuffix(filename, "_" + cfg);
+ src += ">";
+ this->Target->AddSource(src);
}
}
+
+ return genFiles;
}
-void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
- cmLocalGenerator* lg, cmGeneratorTarget* target)
+std::string cmQtAutoGeneratorInitializer::GetQtMajorVersion(
+ cmGeneratorTarget const* target)
{
cmMakefile* makefile = target->Target->GetMakefile();
-
- // Create a custom target for running generators at buildtime
- const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC");
- const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC");
- const bool rccEnabled = target->GetPropertyAsBool("AUTORCC");
- const bool multiConfig = IsMultiConfig(target->GetGlobalGenerator());
- const std::string autogenTargetName = GetAutogenTargetName(target);
- const std::string autogenBuildDir = GetAutogenTargetBuildDir(target);
- const std::string workingDirectory =
- cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory());
- const std::string qtMajorVersion = GetQtMajorVersion(target);
- const std::string rccCommand = RccGetExecutable(target, qtMajorVersion);
- const std::vector<std::string> suffixes = GetConfigurationSuffixes(makefile);
- std::vector<std::string> autogenDepends;
- std::vector<std::string> autogenProvides;
-
- // Remove build directories on cleanup
- makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
- autogenBuildDir.c_str(), false);
-
- // Remove old settings on cleanup
- {
- std::string base = GetAutogenTargetFilesDir(target);
- for (std::vector<std::string>::const_iterator it = suffixes.begin();
- it != suffixes.end(); ++it) {
- std::string fname = base + "/AutogenOldSettings" + *it + ".cmake";
- makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fname.c_str(),
- false);
- }
- }
-
- // Compose command lines
- cmCustomCommandLines commandLines;
- {
- cmCustomCommandLine currentLine;
- currentLine.push_back(cmSystemTools::GetCMakeCommand());
- currentLine.push_back("-E");
- currentLine.push_back("cmake_autogen");
- currentLine.push_back(GetAutogenTargetFilesDir(target));
- currentLine.push_back("$<CONFIGURATION>");
- commandLines.push_back(currentLine);
+ std::string qtMajor = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
+ if (qtMajor.empty()) {
+ qtMajor = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
}
-
- // Compose target comment
- std::string autogenComment;
- {
- std::vector<std::string> toolNames;
- if (mocEnabled) {
- toolNames.push_back("MOC");
- }
- if (uicEnabled) {
- toolNames.push_back("UIC");
- }
- if (rccEnabled) {
- toolNames.push_back("RCC");
- }
-
- std::string tools = toolNames[0];
- toolNames.erase(toolNames.begin());
- while (toolNames.size() > 1) {
- tools += ", " + toolNames[0];
- toolNames.erase(toolNames.begin());
- }
- if (toolNames.size() == 1) {
- tools += " and " + toolNames[0];
- }
- autogenComment = "Automatic " + tools + " for target " + target->GetName();
- }
-
- // Add moc compilation to generated files list
- if (mocEnabled) {
- for (std::vector<std::string>::const_iterator it = suffixes.begin();
- it != suffixes.end(); ++it) {
- std::string mcFile = autogenBuildDir + "/mocs_compilation";
- mcFile += *it;
- mcFile += ".cpp";
- autogenProvides.push_back(mcFile);
- }
- }
-
- // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES
- if (mocEnabled || uicEnabled) {
- if (multiConfig) {
- target->AddIncludeDirectory(autogenBuildDir + "/include_$<CONFIG>",
- true);
-
- } else {
- target->AddIncludeDirectory(autogenBuildDir + "/include", true);
- }
- }
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
- bool usePRE_BUILD = false;
- cmGlobalGenerator* gg = lg->GetGlobalGenerator();
- if (gg->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;
- }
-#endif
-
- // Initialize autogen target dependencies
- if (const char* deps = target->GetProperty("AUTOGEN_TARGET_DEPENDS")) {
- cmSystemTools::ExpandListArgument(deps, autogenDepends);
- }
- // Add link library targets to the autogen dependencies
- {
- const cmTarget::LinkLibraryVectorType& libVec =
- target->Target->GetOriginalLinkLibraries();
- for (cmTarget::LinkLibraryVectorType::const_iterator it = libVec.begin();
- it != libVec.end(); ++it) {
- const std::string& libName = it->first;
- if (makefile->FindTargetToUse(libName) != CM_NULLPTR) {
- autogenDepends.push_back(libName);
- }
- }
- }
- {
- cmFilePathChecksum fpathCheckSum(makefile);
- // Iterate over all source files
- std::vector<cmSourceFile*> srcFiles;
- target->GetConfigCommonSourceFiles(srcFiles);
- for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
- fileIt != srcFiles.end(); ++fileIt) {
- cmSourceFile* sf = *fileIt;
- if (!PropertyEnabled(sf, "SKIP_AUTOGEN")) {
- std::string const& ext = sf->GetExtension();
- // Add generated file that will be scanned by moc or uic to
- // the dependencies
- if (mocEnabled || uicEnabled) {
- const cmSystemTools::FileFormat fileType =
- cmSystemTools::GetFileFormat(ext.c_str());
- if ((fileType == cmSystemTools::CXX_FILE_FORMAT) ||
- (fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
- if (PropertyEnabled(sf, "GENERATED")) {
- if ((mocEnabled && !PropertyEnabled(sf, "SKIP_AUTOMOC")) ||
- (uicEnabled && !PropertyEnabled(sf, "SKIP_AUTOUIC"))) {
- autogenDepends.push_back(
- cmsys::SystemTools::GetRealPath(sf->GetFullPath()));
-#if defined(_WIN32) && !defined(__CYGWIN__)
- // Cannot use PRE_BUILD with generated files
- usePRE_BUILD = false;
-#endif
- }
- }
- }
- }
- // Process rcc enabled files
- if (rccEnabled && (ext == "qrc") &&
- !PropertyEnabled(sf, "SKIP_AUTORCC")) {
- const std::string absFile =
- cmsys::SystemTools::GetRealPath(sf->GetFullPath());
-
- // Compose rcc output file name
- {
- std::string rccOutBase = autogenBuildDir + "/";
- rccOutBase += fpathCheckSum.getPart(absFile);
- rccOutBase += "/qrc_";
- rccOutBase +=
- cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile);
-
- // Register rcc ouput file as generated
- for (std::vector<std::string>::const_iterator it =
- suffixes.begin();
- it != suffixes.end(); ++it) {
- std::string rccOutCfg = rccOutBase;
- rccOutCfg += *it;
- rccOutCfg += ".cpp";
- AddGeneratedSource(makefile, rccOutCfg,
- cmQtAutoGeneratorCommon::RCC);
- autogenProvides.push_back(rccOutCfg);
- }
- // Add rcc output file to origin target sources
- if (multiConfig) {
- target->AddSource(rccOutBase + "_$<CONFIG>.cpp");
- } else {
- target->AddSource(rccOutBase + ".cpp");
- }
- }
-
- if (PropertyEnabled(sf, "GENERATED")) {
- // Add generated qrc file to the dependencies
- autogenDepends.push_back(absFile);
- } else {
- // Run cmake again when .qrc file changes
- makefile->AddCMakeDependFile(absFile);
-
- // Add the qrc input files to the dependencies
- std::string error;
- if (!cmQtAutoGeneratorCommon::RccListInputs(
- qtMajorVersion, rccCommand, absFile, autogenDepends,
- &error)) {
- cmSystemTools::Error(error.c_str());
- }
- }
-#if defined(_WIN32) && !defined(__CYGWIN__)
- // Cannot use PRE_BUILD because the resource files themselves
- // may not be sources within the target so VS may not know the
- // target needs to re-build at all.
- usePRE_BUILD = false;
-#endif
- }
- }
- }
- }
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
- if (usePRE_BUILD) {
- // If the autogen target depends on an other target don't use PRE_BUILD
- for (std::vector<std::string>::iterator it = autogenDepends.begin();
- it != autogenDepends.end(); ++it) {
- if (makefile->FindTargetToUse(*it) != CM_NULLPTR) {
- usePRE_BUILD = false;
- break;
- }
- }
- }
- if (usePRE_BUILD) {
- // 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.
- std::vector<std::string> no_output;
- cmCustomCommand cc(makefile, no_output, autogenProvides, autogenDepends,
- commandLines, autogenComment.c_str(),
- workingDirectory.c_str());
- cc.SetEscapeOldStyle(false);
- cc.SetEscapeAllowMakeVars(true);
- target->Target->AddPreBuildCommand(cc);
- } else
-#endif
- {
- cmTarget* autogenTarget = makefile->AddUtilityCommand(
- autogenTargetName, true, workingDirectory.c_str(),
- /*byproducts=*/autogenProvides, autogenDepends, commandLines, false,
- autogenComment.c_str());
-
- cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg);
- lg->AddGeneratorTarget(gt);
-
- // Set target folder
- const char* autogenFolder =
- makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
- if (!autogenFolder) {
- autogenFolder =
- makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
- }
- if (autogenFolder && *autogenFolder) {
- autogenTarget->SetProperty("FOLDER", autogenFolder);
- } else {
- // inherit FOLDER property from target (#13688)
- utilCopyTargetProperty(gt->Target, target->Target, "FOLDER");
- }
-
- target->Target->AddUtility(autogenTargetName);
+ const char* targetQtVersion =
+ target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "");
+ if (targetQtVersion != nullptr) {
+ qtMajor = targetQtVersion;
}
+ return qtMajor;
}
-void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
- cmGeneratorTarget const* target)
+std::string cmQtAutoGeneratorInitializer::GetQtMinorVersion(
+ cmGeneratorTarget const* target, std::string const& qtVersionMajor)
{
cmMakefile* makefile = target->Target->GetMakefile();
-
- // forget the variables added here afterwards again:
- cmMakefile::ScopePushPop varScope(makefile);
- static_cast<void>(varScope);
-
- // Get configurations
- std::string config;
- const std::vector<std::string> configs(GetConfigurations(makefile, &config));
-
- // Configurations settings buffers
- std::map<std::string, std::string> configSuffix;
- std::map<std::string, std::string> configMocIncludes;
- std::map<std::string, std::string> configMocDefines;
- std::map<std::string, std::string> configUicOptions;
-
- // Configuration suffix
- if (IsMultiConfig(target->GetGlobalGenerator())) {
- for (std::vector<std::string>::const_iterator it = configs.begin();
- it != configs.end(); ++it) {
- configSuffix[*it] = "_" + *it;
- }
+ std::string qtMinor;
+ if (qtVersionMajor == "5") {
+ qtMinor = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR");
}
-
- // Basic setup
- {
- const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC");
- const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC");
- const bool rccEnabled = target->GetPropertyAsBool("AUTORCC");
- const std::string autogenTargetName = GetAutogenTargetName(target);
- const std::string qtMajorVersion = GetQtMajorVersion(target);
-
- std::vector<std::string> sources;
- std::vector<std::string> headers;
-
- if (mocEnabled || uicEnabled || rccEnabled) {
- std::vector<std::string> mocSkipList;
- std::vector<std::string> uicSkipList;
- AcquireScanFiles(target, sources, headers, mocSkipList, uicSkipList);
- if (mocEnabled) {
- MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, config,
- configs, mocSkipList, configMocIncludes,
- configMocDefines);
- }
- if (uicEnabled) {
- UicSetupAutoTarget(target, qtMajorVersion, config, configs,
- uicSkipList, configUicOptions);
- }
- if (rccEnabled) {
- RccSetupAutoTarget(target, qtMajorVersion);
- }
- }
-
- AddDefinitionEscaped(makefile, "_autogen_build_dir",
- GetAutogenTargetBuildDir(target));
- AddDefinitionEscaped(makefile, "_qt_version_major", qtMajorVersion);
- AddDefinitionEscaped(makefile, "_sources", sources);
- AddDefinitionEscaped(makefile, "_headers", headers);
+ if (qtMinor.empty()) {
+ qtMinor = makefile->GetSafeDefinition("QT_VERSION_MINOR");
}
- // Generate info file
- std::string infoFile = GetAutogenTargetFilesDir(target);
- infoFile += "/AutogenInfo.cmake";
- {
- std::string inf = cmSystemTools::GetCMakeRoot();
- inf += "/Modules/AutogenInfo.cmake.in";
- makefile->ConfigureFile(inf.c_str(), infoFile.c_str(), false, true, false);
+ const char* targetQtVersion =
+ target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", "");
+ if (targetQtVersion != nullptr) {
+ qtMinor = targetQtVersion;
}
+ return qtMinor;
+}
- // Append custom definitions to info file on demand
- if (!configSuffix.empty() || !configMocDefines.empty() ||
- !configMocIncludes.empty() || !configUicOptions.empty()) {
-
- // Ensure we have write permission in case .in was read-only.
- 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(infoFile, perm);
- if (!(perm & mode_write)) {
- cmSystemTools::SetPermissions(infoFile, perm | mode_write);
- }
-
- // Open and write file
- cmsys::ofstream ofs(infoFile.c_str(), std::ios::app);
- if (ofs) {
- ofs << "# Configuration specific options\n";
- for (std::map<std::string, std::string>::iterator
- it = configSuffix.begin(),
- end = configSuffix.end();
- it != end; ++it) {
- ofs << "set(AM_CONFIG_SUFFIX_" << it->first << " " << it->second
- << ")\n";
- }
- for (std::map<std::string, std::string>::iterator
- it = configMocDefines.begin(),
- end = configMocDefines.end();
- it != end; ++it) {
- ofs << "set(AM_MOC_DEFINITIONS_" << it->first << " " << it->second
- << ")\n";
- }
- for (std::map<std::string, std::string>::iterator
- it = configMocIncludes.begin(),
- end = configMocIncludes.end();
- it != end; ++it) {
- ofs << "set(AM_MOC_INCLUDES_" << it->first << " " << it->second
- << ")\n";
- }
- for (std::map<std::string, std::string>::iterator
- it = configUicOptions.begin(),
- end = configUicOptions.end();
- it != end; ++it) {
- ofs << "set(AM_UIC_TARGET_OPTIONS_" << it->first << " " << it->second
- << ")\n";
- }
- } else {
- // File open error
- std::string error = "Internal CMake error when trying to open file: ";
- error += cmQtAutoGeneratorCommon::Quoted(infoFile);
- error += " for writing.";
- cmSystemTools::Error(error.c_str());
- }
+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;
}