diff options
author | Brad King <brad.king@kitware.com> | 2017-09-08 13:44:46 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2017-09-08 13:45:07 (GMT) |
commit | e5c1a7dfb3ca419967511ac471c91ebc2c5d76a1 (patch) | |
tree | d77daf590097eba6f265c231cfbb94743c0861b9 /Source | |
parent | 90b6186cbdf4e1deeeaa60eaae00e8461136ea6a (diff) | |
parent | 6739a12571bfa8b97b00740981e9f6eb5195529f (diff) | |
download | CMake-e5c1a7dfb3ca419967511ac471c91ebc2c5d76a1.zip CMake-e5c1a7dfb3ca419967511ac471c91ebc2c5d76a1.tar.gz CMake-e5c1a7dfb3ca419967511ac471c91ebc2c5d76a1.tar.bz2 |
Merge topic 'autogen-digests'
6739a125 Autogen: Doc: Add Visual Studio PRE_BUILD note to cmake-qt.rst
2be0acb7 Autogen: Tests: Add AUTOGEN_TARGET_DEPENDS test to mocDepends tests
734d236c Autogen: Smarter target dependency computation
2e4dab08 Autogen: Set CM_DISABLE_COPY in cmQtAutoGenerators
c330d641 Autogen: Replace CM_AUTO_PTR with std::unique_ptr
9468e926 Autogen: Refactor logging
2ba1b281 Autogen: More use of scoped lambdas
0f9080e2 Autogen: More use of scoped lambdas
...
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !1198
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeLists.txt | 5 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.cxx | 74 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.h | 4 | ||||
-rw-r--r-- | Source/cmQtAutoGen.cxx (renamed from Source/cmQtAutoGeneratorCommon.cxx) | 140 | ||||
-rw-r--r-- | Source/cmQtAutoGen.h (renamed from Source/cmQtAutoGeneratorCommon.h) | 28 | ||||
-rw-r--r-- | Source/cmQtAutoGenDigest.h | 64 | ||||
-rw-r--r-- | Source/cmQtAutoGeneratorInitializer.cxx | 948 | ||||
-rw-r--r-- | Source/cmQtAutoGeneratorInitializer.h | 13 | ||||
-rw-r--r-- | Source/cmQtAutoGenerators.cxx | 1410 | ||||
-rw-r--r-- | Source/cmQtAutoGenerators.h | 92 |
10 files changed, 1458 insertions, 1320 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index bcc3437..9cd7b84 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -307,8 +307,9 @@ set(SRCS cmPropertyDefinitionMap.h cmPropertyMap.cxx cmPropertyMap.h - cmQtAutoGeneratorCommon.cxx - cmQtAutoGeneratorCommon.h + cmQtAutoGen.cxx + cmQtAutoGen.h + cmQtAutoGenDigest.h cmQtAutoGeneratorInitializer.cxx cmQtAutoGeneratorInitializer.h cmQtAutoGenerators.cxx diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index ab35593..39c181a 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1263,8 +1263,7 @@ bool cmGlobalGenerator::Compute() #ifdef CMAKE_BUILD_WITH_CMAKE // Iterate through all targets and set up automoc for those which have // the AUTOMOC, AUTOUIC or AUTORCC property set - std::vector<cmGeneratorTarget const*> autogenTargets = - this->CreateQtAutoGeneratorsTargets(); + cmQtAutoGenDigestUPV autogenDigests = this->CreateQtAutoGeneratorsTargets(); #endif unsigned int i; @@ -1287,11 +1286,10 @@ bool cmGlobalGenerator::Compute() } #ifdef CMAKE_BUILD_WITH_CMAKE - for (std::vector<cmGeneratorTarget const*>::iterator it = - autogenTargets.begin(); - it != autogenTargets.end(); ++it) { - cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(*it); + for (const cmQtAutoGenDigestUP& digest : autogenDigests) { + cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(*digest); } + autogenDigests.clear(); #endif for (i = 0; i < this->LocalGenerators.size(); ++i) { @@ -1427,24 +1425,16 @@ bool cmGlobalGenerator::ComputeTargetDepends() return true; } -std::vector<const cmGeneratorTarget*> -cmGlobalGenerator::CreateQtAutoGeneratorsTargets() +cmQtAutoGenDigestUPV cmGlobalGenerator::CreateQtAutoGeneratorsTargets() { - std::vector<const cmGeneratorTarget*> autogenTargets; + cmQtAutoGenDigestUPV autogenDigests; #ifdef CMAKE_BUILD_WITH_CMAKE - for (std::vector<cmLocalGenerator*>::const_iterator lgit = - this->LocalGenerators.begin(); - lgit != this->LocalGenerators.end(); ++lgit) { - cmLocalGenerator* localGen = *lgit; + for (cmLocalGenerator* localGen : this->LocalGenerators) { const std::vector<cmGeneratorTarget*>& targets = localGen->GetGeneratorTargets(); // Find targets that require AUTOGEN processing - std::vector<cmGeneratorTarget*> filteredTargets; - filteredTargets.reserve(targets.size()); - for (std::vector<cmGeneratorTarget*>::const_iterator ti = targets.begin(); - ti != targets.end(); ++ti) { - cmGeneratorTarget* target = *ti; + for (cmGeneratorTarget* target : targets) { if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { continue; } @@ -1455,33 +1445,43 @@ cmGlobalGenerator::CreateQtAutoGeneratorsTargets() target->GetType() != cmStateEnums::OBJECT_LIBRARY) { continue; } - if ((!target->GetPropertyAsBool("AUTOMOC") && - !target->GetPropertyAsBool("AUTOUIC") && - !target->GetPropertyAsBool("AUTORCC")) || - target->IsImported()) { + if (target->IsImported()) { continue; } - // don't do anything if there is no Qt4 or Qt5Core (which contains moc) - cmMakefile* mf = target->Target->GetMakefile(); - std::string qtMajorVersion = mf->GetSafeDefinition("QT_VERSION_MAJOR"); - if (qtMajorVersion == "") { - qtMajorVersion = mf->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); + + const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); + const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); + const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); + if (!mocEnabled && !uicEnabled && !rccEnabled) { + continue; } - if (qtMajorVersion != "4" && qtMajorVersion != "5") { + + std::string qtVersionMajor = + cmQtAutoGeneratorInitializer::GetQtMajorVersion(target); + // don't do anything if there is no Qt4 or Qt5Core (which contains moc) + if (qtVersionMajor != "4" && qtVersionMajor != "5") { continue; } - filteredTargets.push_back(target); - } - // Initialize AUTOGEN targets - for (std::vector<cmGeneratorTarget*>::iterator ti = - filteredTargets.begin(); - ti != filteredTargets.end(); ++ti) { - cmQtAutoGeneratorInitializer::InitializeAutogenTarget(localGen, *ti); - autogenTargets.push_back(*ti); + + { + cmQtAutoGenDigestUP digest(new cmQtAutoGenDigest(target)); + digest->QtVersionMajor = std::move(qtVersionMajor); + digest->QtVersionMinor = + cmQtAutoGeneratorInitializer::GetQtMinorVersion( + target, digest->QtVersionMajor); + digest->MocEnabled = mocEnabled; + digest->UicEnabled = uicEnabled; + digest->RccEnabled = rccEnabled; + autogenDigests.emplace_back(std::move(digest)); + } } } + // Initialize autogen targets + for (const cmQtAutoGenDigestUP& digest : autogenDigests) { + cmQtAutoGeneratorInitializer::InitializeAutogenTarget(*digest); + } #endif - return autogenTargets; + return autogenDigests; } cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer( diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 3931ab8..18ca682 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -15,6 +15,7 @@ #include "cmCustomCommandLines.h" #include "cmExportSetMap.h" +#include "cmQtAutoGenDigest.h" #include "cmStateSnapshot.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -422,7 +423,8 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; - std::vector<const cmGeneratorTarget*> CreateQtAutoGeneratorsTargets(); + // Qt auto generators + cmQtAutoGenDigestUPV CreateQtAutoGeneratorsTargets(); std::string SelectMakeProgram(const std::string& makeProgram, const std::string& makeDefault = "") const; diff --git a/Source/cmQtAutoGeneratorCommon.cxx b/Source/cmQtAutoGen.cxx index a8e6b96..95cd122 100644 --- a/Source/cmQtAutoGeneratorCommon.cxx +++ b/Source/cmQtAutoGen.cxx @@ -1,17 +1,79 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmQtAutoGeneratorCommon.h" +#include "cmQtAutoGen.h" #include "cmAlgorithms.h" #include "cmSystemTools.h" #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" +#include <algorithm> #include <sstream> #include <stddef.h> +// - Static variables + +const std::string genNameGen = "AutoGen"; +const std::string genNameMoc = "AutoMoc"; +const std::string genNameUic = "AutoUic"; +const std::string genNameRcc = "AutoRcc"; + // - Static functions +/// @brief Merges newOpts into baseOpts +/// @arg valueOpts list of options that accept a value +void MergeOptions(std::vector<std::string>& baseOpts, + const std::vector<std::string>& newOpts, + const std::vector<std::string>& valueOpts, bool isQt5) +{ + typedef std::vector<std::string>::iterator Iter; + typedef std::vector<std::string>::const_iterator CIter; + if (newOpts.empty()) { + return; + } + if (baseOpts.empty()) { + baseOpts = newOpts; + return; + } + + std::vector<std::string> extraOpts; + for (CIter fit = newOpts.begin(), fitEnd = newOpts.end(); fit != fitEnd; + ++fit) { + const std::string& newOpt = *fit; + Iter existIt = std::find(baseOpts.begin(), baseOpts.end(), newOpt); + if (existIt != baseOpts.end()) { + if (newOpt.size() >= 2) { + // Acquire the option name + std::string optName; + { + auto oit = newOpt.begin(); + if (*oit == '-') { + ++oit; + if (isQt5 && (*oit == '-')) { + ++oit; + } + optName.assign(oit, newOpt.end()); + } + } + // Test if this is a value option and change the existing value + if (!optName.empty() && (std::find(valueOpts.begin(), valueOpts.end(), + optName) != valueOpts.end())) { + const Iter existItNext(existIt + 1); + const CIter fitNext(fit + 1); + if ((existItNext != baseOpts.end()) && (fitNext != fitEnd)) { + *existItNext = *fitNext; + ++fit; + } + } + } + } else { + extraOpts.push_back(newOpt); + } + } + // Append options + baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end()); +} + static std::string utilStripCR(std::string const& line) { // Strip CR characters rcc may have printed (possibly more than one!). @@ -40,8 +102,8 @@ static bool RccListInputsQt4(const std::string& fileName, } else { if (errorMessage != nullptr) { std::ostringstream ost; - ost << "AutoRcc: Error: Rcc file not readable:\n" - << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n"; + ost << "rcc file not readable:\n" + << " " << cmQtAutoGen::Quoted(fileName) << "\n"; *errorMessage = ost.str(); } allGood = false; @@ -49,7 +111,7 @@ static bool RccListInputsQt4(const std::string& fileName, } if (allGood) { // qrc file directory - std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName)); + std::string qrcDir(cmSystemTools::GetFilenamePath(fileName)); if (!qrcDir.empty()) { qrcDir += '/'; } @@ -83,7 +145,7 @@ static bool RccListInputsQt5(const std::string& rccCommand, std::string* errorMessage) { if (rccCommand.empty()) { - cmSystemTools::Error("AutoRcc: Error: rcc executable not available\n"); + cmSystemTools::Error("rcc executable not available"); return false; } @@ -122,7 +184,7 @@ static bool RccListInputsQt5(const std::string& rccCommand, if (!result || retVal) { if (errorMessage != nullptr) { std::ostringstream ost; - ost << "AutoRcc: Error: Rcc list process for " << fileName + ost << "rcc list process for " << cmQtAutoGen::Quoted(fileName) << " failed:\n" << rccStdOut << "\n" << rccStdErr << "\n"; @@ -155,8 +217,8 @@ static bool RccListInputsQt5(const std::string& rccCommand, if (pos == std::string::npos) { if (errorMessage != nullptr) { std::ostringstream ost; - ost << "AutoRcc: Error: Rcc lists unparsable output:\n" - << cmQtAutoGeneratorCommon::Quoted(eline) << "\n"; + ost << "rcc lists unparsable output:\n" + << cmQtAutoGen::Quoted(eline) << "\n"; *errorMessage = ost.str(); } return false; @@ -173,9 +235,29 @@ static bool RccListInputsQt5(const std::string& rccCommand, // - Class definitions -const char* cmQtAutoGeneratorCommon::listSep = "@LSEP@"; +const std::string cmQtAutoGen::listSep = "@LSEP@"; + +const std::string& cmQtAutoGen::GeneratorName(GeneratorType type) +{ + switch (type) { + case GeneratorType::GEN: + return genNameGen; + case GeneratorType::MOC: + return genNameMoc; + case GeneratorType::UIC: + return genNameUic; + case GeneratorType::RCC: + return genNameRcc; + } + return genNameGen; +} + +std::string cmQtAutoGen::GeneratorNameUpper(GeneratorType genType) +{ + return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType)); +} -std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text) +std::string cmQtAutoGen::Quoted(const std::string& text) { static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a", "\b", "\\b", "\f", "\\f", "\n", "\\n", @@ -191,14 +273,36 @@ std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text) return res; } -bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion, - const std::string& rccCommand, - const std::string& fileName, - std::vector<std::string>& files, - std::string* errorMessage) +void cmQtAutoGen::UicMergeOptions(std::vector<std::string>& baseOpts, + const std::vector<std::string>& newOpts, + bool isQt5) +{ + static const std::vector<std::string> valueOpts = { + "tr", "translate", "postfix", "generator", + "include", // Since Qt 5.3 + "g" + }; + MergeOptions(baseOpts, newOpts, valueOpts, isQt5); +} + +void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts, + const std::vector<std::string>& newOpts, + bool isQt5) +{ + static const std::vector<std::string> valueOpts = { "name", "root", + "compress", + "threshold" }; + MergeOptions(baseOpts, newOpts, valueOpts, isQt5); +} + +bool cmQtAutoGen::RccListInputs(const std::string& qtMajorVersion, + const std::string& rccCommand, + const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage) { bool allGood = false; - if (cmsys::SystemTools::FileExists(fileName.c_str())) { + if (cmSystemTools::FileExists(fileName.c_str())) { if (qtMajorVersion == "4") { allGood = RccListInputsQt4(fileName, files, errorMessage); } else { @@ -207,8 +311,8 @@ bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion, } else { if (errorMessage != nullptr) { std::ostringstream ost; - ost << "AutoRcc: Error: Rcc file does not exist:\n" - << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n"; + ost << "rcc file does not exist:\n" + << " " << cmQtAutoGen::Quoted(fileName) << "\n"; *errorMessage = ost.str(); } } diff --git a/Source/cmQtAutoGeneratorCommon.h b/Source/cmQtAutoGen.h index 23a882a..4cd5e32 100644 --- a/Source/cmQtAutoGeneratorCommon.h +++ b/Source/cmQtAutoGen.h @@ -1,31 +1,49 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmQtAutoGeneratorCommon_h -#define cmQtAutoGeneratorCommon_h +#ifndef cmQtAutoGen_h +#define cmQtAutoGen_h #include "cmConfigure.h" // IWYU pragma: keep #include <string> #include <vector> -class cmQtAutoGeneratorCommon +/** \class cmQtAutoGen + * \brief Class used as namespace for QtAutogen related types and functions + */ +class cmQtAutoGen { - // - Types and statics public: - static const char* listSep; + static const std::string listSep; enum GeneratorType { + GEN, // General MOC, UIC, RCC }; public: + /// @brief Returns the generator name + static const std::string& GeneratorName(GeneratorType genType); + /// @brief Returns the generator name in upper case + static std::string GeneratorNameUpper(GeneratorType genType); + /// @brief Returns a the string escaped and enclosed in quotes /// static std::string Quoted(const std::string& text); + /// @brief Merges newOpts into baseOpts + static void UicMergeOptions(std::vector<std::string>& baseOpts, + const std::vector<std::string>& newOpts, + bool isQt5); + + /// @brief Merges newOpts into baseOpts + static void RccMergeOptions(std::vector<std::string>& baseOpts, + const std::vector<std::string>& newOpts, + bool isQt5); + /// @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 parsed diff --git a/Source/cmQtAutoGenDigest.h b/Source/cmQtAutoGenDigest.h new file mode 100644 index 0000000..677c397 --- /dev/null +++ b/Source/cmQtAutoGenDigest.h @@ -0,0 +1,64 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGenDigest_h +#define cmQtAutoGenDigest_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <memory> +#include <string> +#include <vector> + +class cmGeneratorTarget; + +class cmQtAutoGenDigestQrc +{ +public: + cmQtAutoGenDigestQrc() + : Generated(false) + , Unique(false) + { + } + +public: + std::string QrcFile; + std::string QrcName; + std::string PathChecksum; + std::string RccFile; + bool Generated; + bool Unique; + std::vector<std::string> Options; + std::vector<std::string> Resources; +}; + +/** \class cmQtAutoGenDigest + * \brief Filtered set of QtAutogen variables for a specific target + */ +class cmQtAutoGenDigest +{ +public: + cmQtAutoGenDigest(cmGeneratorTarget* target) + : Target(target) + , MocEnabled(false) + , UicEnabled(false) + , RccEnabled(false) + { + } + +public: + cmGeneratorTarget* Target; + std::string QtVersionMajor; + std::string QtVersionMinor; + bool MocEnabled; + bool UicEnabled; + bool RccEnabled; + std::vector<std::string> Headers; + std::vector<std::string> Sources; + std::vector<cmQtAutoGenDigestQrc> Qrcs; +}; + +// Utility types +typedef std::unique_ptr<cmQtAutoGenDigest> cmQtAutoGenDigestUP; +typedef std::vector<cmQtAutoGenDigestUP> cmQtAutoGenDigestUPV; + +#endif diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index ebfb6f0..22ac9d2 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -1,7 +1,7 @@ /* 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" @@ -23,6 +23,7 @@ #include "cmsys/FStream.hxx" #include <algorithm> +#include <array> #include <map> #include <set> #include <sstream> @@ -35,12 +36,18 @@ inline static const char* SafeString(const char* value) return (value != nullptr) ? value : ""; } -static std::string GetSafeProperty(cmGeneratorTarget const* target, - const char* key) +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))); +} + inline static bool AutogenMultiConfig(cmGlobalGenerator* globalGen) { return globalGen->IsMultiConfig(); @@ -76,39 +83,40 @@ static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) return targetDir; } -static std::string GetQtMajorVersion(cmGeneratorTarget const* target) +std::string cmQtAutoGeneratorInitializer::GetQtMajorVersion( + cmGeneratorTarget const* target) { cmMakefile* makefile = target->Target->GetMakefile(); - std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); - if (qtMajorVersion.empty()) { - qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); + 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) { - qtMajorVersion = targetQtVersion; + qtMajor = targetQtVersion; } - return qtMajorVersion; + return qtMajor; } -static std::string GetQtMinorVersion(cmGeneratorTarget const* target, - const std::string& qtMajorVersion) +std::string cmQtAutoGeneratorInitializer::GetQtMinorVersion( + cmGeneratorTarget const* target, const std::string& qtVersionMajor) { cmMakefile* makefile = target->Target->GetMakefile(); - std::string qtMinorVersion; - if (qtMajorVersion == "5") { - qtMinorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR"); + std::string qtMinor; + if (qtVersionMajor == "5") { + qtMinor = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR"); } - if (qtMinorVersion.empty()) { - qtMinorVersion = makefile->GetSafeDefinition("QT_VERSION_MINOR"); + if (qtMinor.empty()) { + qtMinor = makefile->GetSafeDefinition("QT_VERSION_MINOR"); } const char* targetQtVersion = target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", ""); if (targetQtVersion != nullptr) { - qtMinorVersion = targetQtVersion; + qtMinor = targetQtVersion; } - return qtMinorVersion; + return qtMinor; } static bool QtVersionGreaterOrEqual(const std::string& major, @@ -126,26 +134,6 @@ static bool QtVersionGreaterOrEqual(const std::string& major, return false; } -static void GetCompileDefinitionsAndDirectories( - cmGeneratorTarget const* target, const std::string& config, - std::string& incs, std::string& defs) -{ - 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::set<std::string> defines; - localGen->AddCompileDefinitions(defines, target, config, "CXX"); - defs += cmJoin(defines, ";"); - } -} - static std::vector<std::string> GetConfigurations( cmMakefile* makefile, std::string* config = nullptr) { @@ -168,9 +156,8 @@ static std::vector<std::string> GetConfigurationSuffixes(cmMakefile* makefile) std::vector<std::string> suffixes; if (AutogenMultiConfig(makefile->GetGlobalGenerator())) { makefile->GetConfigurations(suffixes); - for (std::vector<std::string>::iterator it = suffixes.begin(); - it != suffixes.end(); ++it) { - it->insert(0, "_"); + for (std::string& suffix : suffixes) { + suffix.insert(0, "_"); } } if (suffixes.empty()) { @@ -200,33 +187,56 @@ static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); } +static void AddDefinitionEscaped( + cmMakefile* makefile, const char* key, + const std::vector<std::vector<std::string>>& lists) +{ + 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)); + } + makefile->AddDefinition(key, cmOutputConverter::EscapeForCMake( + cmJoin(seplist, cmQtAutoGen::listSep)) + .c_str()); +} + static bool AddToSourceGroup(cmMakefile* makefile, const std::string& fileName, - cmQtAutoGeneratorCommon::GeneratorType genType) + cmQtAutoGen::GeneratorType genType) { cmSourceGroup* sourceGroup = nullptr; // Acquire source group { - const char* groupName = 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"); - break; - default: - break; - } - // Use default group name on demand - if ((groupName == nullptr) || (*groupName == 0)) { - groupName = - makefile->GetState()->GetGlobalProperty("AUTOGEN_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 != nullptr) && (*groupName != 0)) { + if (!groupName.empty()) { { const char* delimiter = makefile->GetDefinition("SOURCE_GROUP_DELIMITER"); @@ -242,9 +252,12 @@ static bool AddToSourceGroup(cmMakefile* makefile, const std::string& fileName, } } if (sourceGroup == nullptr) { - cmSystemTools::Error( - "Autogen: Could not create or find source group: ", - cmQtAutoGeneratorCommon::Quoted(groupName).c_str()); + 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; } } @@ -263,7 +276,7 @@ static void AddCleanFile(cmMakefile* makefile, const std::string& fileName) static void AddGeneratedSource(cmGeneratorTarget* target, const std::string& filename, - cmQtAutoGeneratorCommon::GeneratorType genType) + cmQtAutoGen::GeneratorType genType) { cmMakefile* makefile = target->Target->GetMakefile(); { @@ -276,32 +289,24 @@ static void AddGeneratedSource(cmGeneratorTarget* target, AddToSourceGroup(makefile, filename, genType); } -struct AutogenSetup +struct cmQtAutoGenSetup { - std::vector<std::string> sources; - std::vector<std::string> headers; + std::set<std::string> MocSkip; + std::set<std::string> UicSkip; - std::set<std::string> mocSkip; - std::set<std::string> uicSkip; - - 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; + std::map<std::string, std::string> ConfigMocIncludes; + std::map<std::string, std::string> ConfigMocDefines; + std::map<std::string, std::string> ConfigUicOptions; }; -static void SetupAcquireScanFiles(cmGeneratorTarget const* target, - bool mocEnabled, bool uicEnabled, - const std::vector<cmSourceFile*>& srcFiles, - AutogenSetup& setup) +static void SetupAcquireSkipFiles(cmQtAutoGenDigest const& digest, + cmQtAutoGenSetup& setup) { // Read skip files from makefile sources { const std::vector<cmSourceFile*>& allSources = - target->Makefile->GetSourceFiles(); - for (std::vector<cmSourceFile*>::const_iterator fit = allSources.begin(); - fit != allSources.end(); ++fit) { - cmSourceFile* sf = *fit; + digest.Target->Makefile->GetSourceFiles(); + for (cmSourceFile* sf : allSources) { // sf->GetExtension() is only valid after sf->GetFullPath() ... const std::string& fPath = sf->GetFullPath(); const cmSystemTools::FileFormat fileType = @@ -311,95 +316,33 @@ static void SetupAcquireScanFiles(cmGeneratorTarget const* target, continue; } const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN"); - const bool mocSkip = - mocEnabled && (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC")); - const bool uicSkip = - uicEnabled && (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC")); + const bool mocSkip = digest.MocEnabled && + (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC")); + const bool uicSkip = digest.UicEnabled && + (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC")); if (mocSkip || uicSkip) { - const std::string absFile = cmsys::SystemTools::GetRealPath(fPath); + const std::string absFile = cmSystemTools::GetRealPath(fPath); if (mocSkip) { - setup.mocSkip.insert(absFile); + setup.MocSkip.insert(absFile); } if (uicSkip) { - setup.uicSkip.insert(absFile); + setup.UicSkip.insert(absFile); } } } } - - const cmPolicies::PolicyStatus CMP0071_status = - target->Makefile->GetPolicyStatus(cmPolicies::CMP0071); - for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); - fileIt != srcFiles.end(); ++fileIt) { - cmSourceFile* sf = *fileIt; - // sf->GetExtension() is only valid after sf->GetFullPath() ... - const std::string& fPath = sf->GetFullPath(); - const cmSystemTools::FileFormat fileType = - cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); - if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && - !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { - continue; - } - // Real file path - const std::string absFile = cmsys::SystemTools::GetRealPath(fPath); - // Skip test - const bool mocSkip = !mocEnabled || (setup.mocSkip.count(absFile) != 0); - const bool uicSkip = !uicEnabled || (setup.uicSkip.count(absFile) != 0); - if (mocSkip && uicSkip) { - continue; - } - - // For GENERATED files check status of policy CMP0071 - if (sf->GetPropertyAsBool("GENERATED")) { - bool policyAccept = false; - switch (CMP0071_status) { - case cmPolicies::WARN: { - std::ostringstream ost; - ost << cmPolicies::GetPolicyWarning(cmPolicies::CMP0071) << "\n"; - ost << "AUTOMOC/AUTOUIC: Ignoring GENERATED source file:\n"; - ost << " " << cmQtAutoGeneratorCommon::Quoted(absFile) << "\n"; - target->Makefile->IssueMessage(cmake::AUTHOR_WARNING, ost.str()); - } - 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) { - continue; - } - } - - // Add file name to sources or headers list - switch (fileType) { - case cmSystemTools::CXX_FILE_FORMAT: - setup.sources.push_back(absFile); - break; - case cmSystemTools::HEADER_FILE_FORMAT: - setup.headers.push_back(absFile); - break; - default: - break; - } - } } -static void SetupAutoTargetMoc(cmGeneratorTarget const* target, - std::string const& qtMajorVersion, +static void SetupAutoTargetMoc(const cmQtAutoGenDigest& digest, std::string const& config, std::vector<std::string> const& configs, - AutogenSetup& setup) + cmQtAutoGenSetup& setup) { + cmGeneratorTarget const* target = digest.Target; cmLocalGenerator* localGen = target->GetLocalGenerator(); cmMakefile* makefile = target->Target->GetMakefile(); - AddDefinitionEscaped(makefile, "_moc_skip", setup.mocSkip); + AddDefinitionEscaped(makefile, "_moc_skip", setup.MocSkip); AddDefinitionEscaped(makefile, "_moc_options", GetSafeProperty(target, "AUTOMOC_MOC_OPTIONS")); AddDefinitionEscaped(makefile, "_moc_relaxed_mode", @@ -410,33 +353,49 @@ static void SetupAutoTargetMoc(cmGeneratorTarget const* target, AddDefinitionEscaped(makefile, "_moc_depend_filters", GetSafeProperty(target, "AUTOMOC_DEPEND_FILTERS")); - if (QtVersionGreaterOrEqual( - qtMajorVersion, GetQtMinorVersion(target, qtMajorVersion), 5, 8)) { + if (QtVersionGreaterOrEqual(digest.QtVersionMajor, digest.QtVersionMinor, 5, + 8)) { AddDefinitionEscaped( makefile, "_moc_predefs_cmd", makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND")); } // Moc includes and compile definitions { + auto GetCompileDefinitionsAndDirectories = [target, localGen]( + const std::string& cfg, std::string& incs, std::string& defs) { + { + 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", cfg, + false); + incs = cmJoin(includeDirs, ";"); + } + { + std::set<std::string> defines; + localGen->AddCompileDefinitions(defines, target, cfg, "CXX"); + defs += cmJoin(defines, ";"); + } + }; + // Default settings std::string incs; std::string compileDefs; - GetCompileDefinitionsAndDirectories(target, config, incs, compileDefs); + GetCompileDefinitionsAndDirectories(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) { + for (const std::string& cfg : configs) { std::string configIncs; std::string configCompileDefs; - GetCompileDefinitionsAndDirectories(target, *li, configIncs, - configCompileDefs); + GetCompileDefinitionsAndDirectories(cfg, configIncs, configCompileDefs); if (configIncs != incs) { - setup.configMocIncludes[*li] = configIncs; + setup.ConfigMocIncludes[cfg] = configIncs; } if (configCompileDefs != compileDefs) { - setup.configMocDefines[*li] = configCompileDefs; + setup.ConfigMocDefines[cfg] = configCompileDefs; } } } @@ -446,14 +405,14 @@ static void SetupAutoTargetMoc(cmGeneratorTarget const* target, std::string mocExec; std::string err; - if (qtMajorVersion == "5") { + if (digest.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 (qtMajorVersion == "4") { + } else if (digest.QtVersionMajor == "4") { cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::moc"); if (tgt != nullptr) { mocExec = SafeString(tgt->ImportedGetLocation("")); @@ -473,24 +432,15 @@ static void SetupAutoTargetMoc(cmGeneratorTarget const* target, } } -static void UicGetOpts(cmGeneratorTarget const* target, - const std::string& config, std::string& optString) -{ - std::vector<std::string> opts; - target->GetAutoUicOptions(opts, config); - optString = cmJoin(opts, ";"); -} - -static void SetupAutoTargetUic(cmGeneratorTarget const* target, - std::string const& qtMajorVersion, +static void SetupAutoTargetUic(const cmQtAutoGenDigest& digest, std::string const& config, std::vector<std::string> const& configs, - AutogenSetup& setup) + cmQtAutoGenSetup& setup) { - cmLocalGenerator* localGen = target->GetLocalGenerator(); + cmGeneratorTarget const* target = digest.Target; cmMakefile* makefile = target->Target->GetMakefile(); - AddDefinitionEscaped(makefile, "_uic_skip", setup.uicSkip); + AddDefinitionEscaped(makefile, "_uic_skip", setup.UicSkip); // Uic search paths { @@ -500,9 +450,8 @@ static void SetupAutoTargetUic(cmGeneratorTarget const* target, if (!usp.empty()) { cmSystemTools::ExpandListArgument(usp, 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); + for (std::string& path : uicSearchPaths) { + path = cmSystemTools::CollapseFullPath(path, srcDir); } } } @@ -510,44 +459,45 @@ static void SetupAutoTargetUic(cmGeneratorTarget const* target, } // Uic target options { + auto UicGetOpts = [target](const std::string& cfg) -> std::string { + std::vector<std::string> opts; + target->GetAutoUicOptions(opts, cfg); + return cmJoin(opts, ";"); + }; + // Default settings - std::string uicOpts; - UicGetOpts(target, config, uicOpts); + const std::string uicOpts = UicGetOpts(config); 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 (const std::string& cfg : configs) { + const std::string configUicOpts = UicGetOpts(cfg); if (configUicOpts != uicOpts) { - setup.configUicOptions[*li] = configUicOpts; + setup.ConfigUicOptions[cfg] = configUicOpts; } } } // Uic files options { std::vector<std::string> uiFileFiles; - std::vector<std::string> uiFileOptions; + std::vector<std::vector<std::string>> uiFileOptions; { const std::string uiExt = "ui"; const std::vector<cmSourceFile*>& srcFiles = makefile->GetSourceFiles(); - for (std::vector<cmSourceFile*>::const_iterator fit = srcFiles.begin(); - fit != srcFiles.end(); ++fit) { - cmSourceFile* sf = *fit; + for (cmSourceFile* sf : srcFiles) { // sf->GetExtension() is only valid after sf->GetFullPath() ... const std::string& fPath = sf->GetFullPath(); if (sf->GetExtension() == uiExt) { // Check if the files has uic options - std::string uicOpts = sf->GetProperty("AUTOUIC_OPTIONS"); + const std::string uicOpts = GetSafeProperty(sf, "AUTOUIC_OPTIONS"); if (!uicOpts.empty()) { - const std::string absFile = cmsys::SystemTools::GetRealPath(fPath); + const std::string absFile = cmSystemTools::GetRealPath(fPath); // Check if file isn't skipped - if (setup.uicSkip.count(absFile) == 0) { + if (setup.UicSkip.count(absFile) == 0) { uiFileFiles.push_back(absFile); - cmSystemTools::ReplaceString(uicOpts, ";", - cmQtAutoGeneratorCommon::listSep); - uiFileOptions.push_back(uicOpts); + std::vector<std::string> optsVec; + cmSystemTools::ExpandListArgument(uicOpts, optsVec); + uiFileOptions.push_back(std::move(optsVec)); } } } @@ -562,14 +512,15 @@ static void SetupAutoTargetUic(cmGeneratorTarget const* target, std::string err; std::string uicExec; - if (qtMajorVersion == "5") { + cmLocalGenerator* localGen = target->GetLocalGenerator(); + if (digest.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") { + } else if (digest.QtVersionMajor == "4") { cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse("Qt4::uic"); if (tgt != nullptr) { uicExec = SafeString(tgt->ImportedGetLocation("")); @@ -621,141 +572,48 @@ static std::string RccGetExecutable(cmGeneratorTarget const* target, return rccExec; } -static void RccMergeOptions(std::vector<std::string>& opts, - const std::vector<std::string>& fileOpts, - bool isQt5) +static void SetupAutoTargetRcc(const cmQtAutoGenDigest& digest) { - 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); - } - } - opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); -} - -static void SetupAutoTargetRcc(cmGeneratorTarget const* target, - const std::string& qtMajorVersion, - const std::vector<cmSourceFile*>& srcFiles) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - const bool qtMajorVersion5 = (qtMajorVersion == "5"); - const std::string rccCommand = RccGetExecutable(target, qtMajorVersion); std::vector<std::string> rccFiles; - std::vector<std::string> rccInputs; - std::vector<std::string> rccFileFiles; - std::vector<std::string> rccFileOptions; - std::vector<std::string> rccOptionsTarget; - - cmSystemTools::ExpandListArgument(GetSafeProperty(target, "AUTORCC_OPTIONS"), - rccOptionsTarget); - - for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); - fileIt != srcFiles.end(); ++fileIt) { - cmSourceFile* sf = *fileIt; - // sf->GetExtension() is only valid after sf->GetFullPath() ... - const std::string& fPath = sf->GetFullPath(); - if ((sf->GetExtension() == "qrc") && - !sf->GetPropertyAsBool("SKIP_AUTOGEN") && - !sf->GetPropertyAsBool("SKIP_AUTORCC")) { - const std::string absFile = cmsys::SystemTools::GetRealPath(fPath); - // qrc file - rccFiles.push_back(absFile); - // qrc file entries - { - std::string entriesList = "{"; - // Read input file list only for non generated .qrc files. - if (!sf->GetPropertyAsBool("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 += "}"; - rccInputs.push_back(entriesList); - } - // rcc options for this qrc file - { - // 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)); - } - } - } + std::vector<std::string> rccBuilds; + std::vector<std::vector<std::string>> rccOptions; + std::vector<std::vector<std::string>> rccInputs; + + for (const cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { + rccFiles.push_back(qrcDigest.QrcFile); + rccBuilds.push_back(qrcDigest.RccFile); + rccOptions.push_back(qrcDigest.Options); + rccInputs.push_back(qrcDigest.Resources); } - AddDefinitionEscaped(makefile, "_qt_rcc_executable", rccCommand); + cmMakefile* makefile = digest.Target->Target->GetMakefile(); + AddDefinitionEscaped(makefile, "_qt_rcc_executable", + RccGetExecutable(digest.Target, digest.QtVersionMajor)); AddDefinitionEscaped(makefile, "_rcc_files", rccFiles); + AddDefinitionEscaped(makefile, "_rcc_builds", rccBuilds); + AddDefinitionEscaped(makefile, "_rcc_options", rccOptions); AddDefinitionEscaped(makefile, "_rcc_inputs", rccInputs); - AddDefinitionEscaped(makefile, "_rcc_options_files", rccFileFiles); - AddDefinitionEscaped(makefile, "_rcc_options_options", rccFileOptions); } void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( - cmLocalGenerator* localGen, cmGeneratorTarget* target) + cmQtAutoGenDigest& digest) { + cmGeneratorTarget* target = digest.Target; cmMakefile* makefile = target->Target->GetMakefile(); + cmLocalGenerator* localGen = target->GetLocalGenerator(); cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); // 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 = AutogenMultiConfig(globalGen); const std::string autogenTargetName = GetAutogenTargetName(target); const std::string autogenBuildDir = GetAutogenTargetBuildDir(target); const std::string workingDirectory = cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); const std::vector<std::string> suffixes = GetConfigurationSuffixes(makefile); - std::set<std::string> autogenDependsSet; + std::set<std::string> autogenDependFiles; + std::set<std::string> autogenDependTargets; std::vector<std::string> autogenProvides; - 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; - } - // Remove build directories on cleanup AddCleanFile(makefile, autogenBuildDir); @@ -763,9 +621,8 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( { std::string base = GetAutogenTargetFilesDir(target); base += "/AutogenOldSettings"; - for (std::vector<std::string>::const_iterator it = suffixes.begin(); - it != suffixes.end(); ++it) { - AddCleanFile(makefile, base + *it + ".cmake"); + for (const std::string& suffix : suffixes) { + AddCleanFile(makefile, (base + suffix).append(".cmake")); } } @@ -785,13 +642,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( std::string autogenComment; { std::vector<std::string> toolNames; - if (mocEnabled) { + if (digest.MocEnabled) { toolNames.push_back("MOC"); } - if (uicEnabled) { + if (digest.UicEnabled) { toolNames.push_back("UIC"); } - if (rccEnabled) { + if (digest.RccEnabled) { toolNames.push_back("RCC"); } @@ -808,14 +665,14 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( } // Add moc compilation to generated files list - if (mocEnabled) { + if (digest.MocEnabled) { const std::string mocsComp = autogenBuildDir + "/mocs_compilation.cpp"; - AddGeneratedSource(target, mocsComp, cmQtAutoGeneratorCommon::MOC); + AddGeneratedSource(target, mocsComp, cmQtAutoGen::MOC); autogenProvides.push_back(mocsComp); } // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES - if (mocEnabled || uicEnabled) { + if (digest.MocEnabled || digest.UicEnabled) { std::string includeDir = autogenBuildDir + "/include"; if (multiConfig) { includeDir += "_$<CONFIG>"; @@ -823,49 +680,14 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( target->AddIncludeDirectory(includeDir, true); } - // Add user defined autogen target dependencies - { - const std::string deps = GetSafeProperty(target, "AUTOGEN_TARGET_DEPENDS"); - if (!deps.empty()) { - std::vector<std::string> extraDepends; - cmSystemTools::ExpandListArgument(deps, extraDepends); - autogenDependsSet.insert(extraDepends.begin(), extraDepends.end()); - } - } - // Add utility target dependencies to the autogen dependencies - { - const std::set<std::string>& utils = target->Target->GetUtilities(); - for (std::set<std::string>::const_iterator it = utils.begin(); - it != utils.end(); ++it) { - const std::string& targetName = *it; - if (makefile->FindTargetToUse(targetName) != nullptr) { - autogenDependsSet.insert(targetName); - } - } - } - // Add link library target dependencies 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) != nullptr) { - autogenDependsSet.insert(libName); - } - } - } - // Extract relevant source files std::vector<std::string> generatedSources; - std::vector<std::pair<std::string, bool>> qrcSources; + std::vector<std::string> generatedHeaders; { const std::string qrcExt = "qrc"; std::vector<cmSourceFile*> srcFiles; target->GetConfigCommonSourceFiles(srcFiles); - for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); - fileIt != srcFiles.end(); ++fileIt) { - cmSourceFile* sf = *fileIt; + for (cmSourceFile* sf : srcFiles) { if (sf->GetPropertyAsBool("SKIP_AUTOGEN")) { continue; } @@ -873,26 +695,51 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( const std::string& fPath = sf->GetFullPath(); const std::string& ext = sf->GetExtension(); // Register generated files that will be scanned by moc or uic - if (mocEnabled || uicEnabled) { + if (digest.MocEnabled || digest.UicEnabled) { const cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat(ext.c_str()); if ((fileType == cmSystemTools::CXX_FILE_FORMAT) || (fileType == cmSystemTools::HEADER_FILE_FORMAT)) { - if (sf->GetPropertyAsBool("GENERATED")) { - if ((mocEnabled && !sf->GetPropertyAsBool("SKIP_AUTOMOC")) || - (uicEnabled && !sf->GetPropertyAsBool("SKIP_AUTOUIC"))) { - generatedSources.push_back( - cmsys::SystemTools::GetRealPath(fPath)); + const std::string absPath = cmSystemTools::GetRealPath(fPath); + if ((digest.MocEnabled && !sf->GetPropertyAsBool("SKIP_AUTOMOC")) || + (digest.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 { + digest.Headers.push_back(absPath); + } + } else { + if (generated) { + generatedSources.push_back(absPath); + } else { + digest.Sources.push_back(absPath); + } } } } } // Register rcc enabled files - if (rccEnabled && (ext == qrcExt) && + if (digest.RccEnabled && (ext == qrcExt) && !sf->GetPropertyAsBool("SKIP_AUTORCC")) { - qrcSources.push_back( - std::pair<std::string, bool>(cmsys::SystemTools::GetRealPath(fPath), - sf->GetPropertyAsBool("GENERATED"))); + // Register qrc file + { + cmQtAutoGenDigestQrc qrcDigest; + qrcDigest.QrcFile = cmSystemTools::GetRealPath(fPath); + qrcDigest.QrcName = + cmSystemTools::GetFilenameWithoutLastExtension(qrcDigest.QrcFile); + qrcDigest.Generated = sf->GetPropertyAsBool("GENERATED"); + // RCC options + { + const std::string opts = GetSafeProperty(sf, "AUTORCC_OPTIONS"); + if (!opts.empty()) { + cmSystemTools::ExpandListArgument(opts, qrcDigest.Options); + } + } + digest.Qrcs.push_back(std::move(qrcDigest)); + } } } // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's @@ -902,104 +749,242 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( target->ClearSourcesCache(); } - if (!generatedSources.empty()) { - for (std::vector<std::string>::const_iterator it = - generatedSources.begin(); - it != generatedSources.end(); ++it) { - autogenDependsSet.insert(*it); + // Process GENERATED sources and headers + if (!generatedSources.empty() || !generatedHeaders.empty()) { + // Check status of policy CMP0071 + bool policyAccept = false; + bool policyWarn = false; + const cmPolicies::PolicyStatus CMP0071_status = + target->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 (!qrcSources.empty()) { - const std::string qtMajorVersion = GetQtMajorVersion(target); - const std::string rccCommand = RccGetExecutable(target, qtMajorVersion); - const cmFilePathChecksum fpathCheckSum(makefile); - for (std::vector<std::pair<std::string, bool>>::const_iterator it = - qrcSources.begin(); - it != qrcSources.end(); ++it) { - const std::string& absFile = it->first; - // Compose rcc output file name + if (policyAccept) { + // Accept GENERATED sources + for (const std::string& absFile : generatedHeaders) { + digest.Headers.push_back(absFile); + autogenDependFiles.insert(absFile); + } + for (const std::string& absFile : generatedSources) { + digest.Sources.push_back(absFile); + autogenDependFiles.insert(absFile); + } + } else { + if (policyWarn) { + std::string msg; + msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071); + msg += "\n"; + std::string tools; + if (digest.MocEnabled) { + tools += "AUTOMOC"; + } + if (digest.UicEnabled) { + if (!tools.empty()) { + tools += ","; + } + tools += "AUTOUIC"; + } + if (!generatedHeaders.empty()) { + msg.append(tools).append(": Ignoring GENERATED header file(s):\n"); + for (const std::string& absFile : generatedHeaders) { + msg.append(" ").append(cmQtAutoGen::Quoted(absFile)).append("\n"); + } + } + if (!generatedSources.empty()) { + msg.append(tools).append(": Ignoring GENERATED source file(s):\n"); + for (const std::string& absFile : generatedSources) { + msg.append(" ").append(cmQtAutoGen::Quoted(absFile)).append("\n"); + } + } + makefile->IssueMessage(cmake::AUTHOR_WARNING, msg); + } + } + } + // Sort headers and sources + std::sort(digest.Headers.begin(), digest.Headers.end()); + std::sort(digest.Sources.begin(), digest.Sources.end()); + + // Process qrc files + if (!digest.Qrcs.empty()) { + const bool QtV5 = (digest.QtVersionMajor == "5"); + const std::string rcc = RccGetExecutable(target, digest.QtVersionMajor); + // Target rcc options + std::vector<std::string> optionsTarget; + cmSystemTools::ExpandListArgument( + GetSafeProperty(target, "AUTORCC_OPTIONS"), optionsTarget); + + // Check if file name is unique + for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { + qrcDigest.Unique = true; + for (const cmQtAutoGenDigestQrc& qrcDig2 : digest.Qrcs) { + if ((&qrcDigest != &qrcDig2) && + (qrcDigest.QrcName == qrcDig2.QrcName)) { + qrcDigest.Unique = false; + break; + } + } + } + // Path checksum + { + const cmFilePathChecksum fpathCheckSum(makefile); + for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { + qrcDigest.PathChecksum = fpathCheckSum.getPart(qrcDigest.QrcFile); + // RCC output file name + std::string rccFile = autogenBuildDir + "/"; + rccFile += qrcDigest.PathChecksum; + rccFile += "/qrc_"; + rccFile += qrcDigest.QrcName; + rccFile += ".cpp"; + qrcDigest.RccFile = std::move(rccFile); + } + } + // RCC options + for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { + // Target options + std::vector<std::string> opts = optionsTarget; + // Merge computed "-name XYZ" option { - std::string rccBuildFile = autogenBuildDir + "/"; - rccBuildFile += fpathCheckSum.getPart(absFile); - rccBuildFile += "/qrc_"; - rccBuildFile += - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - rccBuildFile += ".cpp"; - - // Register rcc ouput file as generated - AddGeneratedSource(target, rccBuildFile, cmQtAutoGeneratorCommon::RCC); - // Register rcc ouput file as generated by the _autogen target - autogenProvides.push_back(rccBuildFile); + std::string name = qrcDigest.QrcName; + // Replace '-' with '_'. The former is not valid for symbol names. + std::replace(name.begin(), name.end(), '-', '_'); + if (!qrcDigest.Unique) { + name += "_"; + name += qrcDigest.PathChecksum; + } + std::vector<std::string> nameOpts; + nameOpts.emplace_back("-name"); + nameOpts.emplace_back(std::move(name)); + cmQtAutoGen::RccMergeOptions(opts, nameOpts, QtV5); } - - if (it->second) { - // Add generated qrc file to the dependencies - autogenDependsSet.insert(absFile); + // Merge file option + cmQtAutoGen::RccMergeOptions(opts, qrcDigest.Options, QtV5); + qrcDigest.Options = std::move(opts); + } + for (cmQtAutoGenDigestQrc& qrcDigest : digest.Qrcs) { + // Register file at target + AddGeneratedSource(target, qrcDigest.RccFile, cmQtAutoGen::RCC); + autogenProvides.push_back(qrcDigest.RccFile); + // Dependencies + if (qrcDigest.Generated) { + // Add the GENERATED .qrc file to the dependencies + autogenDependFiles.insert(qrcDigest.QrcFile); } else { - // Run cmake again when .qrc file changes - makefile->AddCMakeDependFile(absFile); - // Add the qrc input files to the dependencies + // Add the resource files to the dependencies { std::string error; - std::vector<std::string> extraDepends; - if (cmQtAutoGeneratorCommon::RccListInputs( - qtMajorVersion, rccCommand, absFile, extraDepends, &error)) { - autogenDependsSet.insert(extraDepends.begin(), extraDepends.end()); + if (cmQtAutoGen::RccListInputs(digest.QtVersionMajor, rcc, + qrcDigest.QrcFile, + qrcDigest.Resources, &error)) { + for (const std::string& fileName : qrcDigest.Resources) { + autogenDependFiles.insert(fileName); + } } else { cmSystemTools::Error(error.c_str()); } } + // Run cmake again when .qrc file changes + makefile->AddCMakeDependFile(qrcDigest.QrcFile); } } } - // Convert std::set to std::vector - const std::vector<std::string> autogenDepends(autogenDependsSet.begin(), - autogenDependsSet.end()); - // Disable PRE_BUILD on demand - if (usePRE_BUILD) { - if (!generatedSources.empty() || !qrcSources.empty()) { - // - Cannot use PRE_BUILD with generated files - // - 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; - } - if (usePRE_BUILD) { - // If the autogen target depends on an other target don't use PRE_BUILD - for (std::vector<std::string>::const_iterator it = - autogenDepends.begin(); - it != autogenDepends.end(); ++it) { - if (makefile->FindTargetToUse(*it) != nullptr) { - usePRE_BUILD = false; - break; + // Add user defined autogen target dependencies + { + const std::string deps = GetSafeProperty(target, "AUTOGEN_TARGET_DEPENDS"); + if (!deps.empty()) { + std::vector<std::string> extraDeps; + cmSystemTools::ExpandListArgument(deps, extraDeps); + for (const std::string& depName : extraDeps) { + // Allow target and file dependencies + auto* depTarget = makefile->FindTargetToUse(depName); + if (depTarget != nullptr) { + autogenDependTargets.insert(depTarget->GetName()); + } else { + autogenDependFiles.insert(depName); } } } } + + // 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 (const std::string& depTarget : autogenDependTargets) { + target->Target->AddUtility(depTarget, 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. - std::vector<std::string> no_output; - cmCustomCommand cc(makefile, no_output, autogenProvides, autogenDepends, + // + // 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(), workingDirectory.c_str()); cc.SetEscapeOldStyle(false); cc.SetEscapeAllowMakeVars(true); target->Target->AddPreBuildCommand(cc); } else { + + // Add utility target dependencies to the autogen target dependencies + for (const std::string& depTarget : target->Target->GetUtilities()) { + autogenDependTargets.insert(depTarget); + } + // Add link library target dependencies to the autogen target dependencies + for (const auto& item : target->Target->GetOriginalLinkLibraries()) { + if (makefile->FindTargetToUse(item.first) != nullptr) { + autogenDependTargets.insert(item.first); + } + } + + // Convert file dependencies std::set to std::vector + const std::vector<std::string> autogenDepends(autogenDependFiles.begin(), + autogenDependFiles.end()); + // Create autogen target cmTarget* autogenTarget = makefile->AddUtilityCommand( autogenTargetName, true, workingDirectory.c_str(), /*byproducts=*/autogenProvides, autogenDepends, commandLines, false, autogenComment.c_str()); - + // Create autogen generator target localGen->AddGeneratorTarget( new cmGeneratorTarget(autogenTarget, localGen)); - // Set autogen target FOLDER + // Add additional autogen target dependencies to autogen target + for (const std::string& depTarget : autogenDependTargets) { + autogenTarget->AddUtility(depTarget, makefile); + } + + // Set FOLDER property in autogen target { const char* autogenFolder = makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); @@ -1009,7 +994,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( } // Inherit FOLDER property from target (#13688) if (autogenFolder == nullptr) { - autogenFolder = target->Target->GetProperty("FOLDER"); + autogenFolder = SafeString(target->Target->GetProperty("FOLDER")); } if ((autogenFolder != nullptr) && (*autogenFolder != '\0')) { autogenTarget->SetProperty("FOLDER", autogenFolder); @@ -1017,13 +1002,14 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( } // Add autogen target to the origin target dependencies - target->Target->AddUtility(autogenTargetName); + target->Target->AddUtility(autogenTargetName, makefile); } } void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( - cmGeneratorTarget const* target) + const cmQtAutoGenDigest& digest) { + cmGeneratorTarget const* target = digest.Target; cmMakefile* makefile = target->Target->GetMakefile(); // forget the variables added here afterwards again: @@ -1037,43 +1023,34 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( // Configuration suffixes std::map<std::string, std::string> configSuffix; if (AutogenMultiConfig(target->GetGlobalGenerator())) { - for (std::vector<std::string>::const_iterator it = configs.begin(); - it != configs.end(); ++it) { - configSuffix[*it] = "_" + *it; + for (const std::string& cfg : configs) { + configSuffix[cfg] = "_" + cfg; } } // Configurations settings buffers - AutogenSetup setup; + cmQtAutoGenSetup setup; // Basic setup + AddDefinitionEscaped(makefile, "_build_dir", + GetAutogenTargetBuildDir(target)); + AddDefinitionEscaped(makefile, "_qt_version_major", digest.QtVersionMajor); + AddDefinitionEscaped(makefile, "_qt_version_minor", digest.QtVersionMinor); + AddDefinitionEscaped(makefile, "_sources", digest.Sources); + AddDefinitionEscaped(makefile, "_headers", digest.Headers); { - const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); - const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); - const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); - const std::string qtMajorVersion = GetQtMajorVersion(target); - { - std::vector<cmSourceFile*> srcFiles; - target->GetConfigCommonSourceFiles(srcFiles); - if (mocEnabled || uicEnabled) { - SetupAcquireScanFiles(target, mocEnabled, uicEnabled, srcFiles, setup); - if (mocEnabled) { - SetupAutoTargetMoc(target, qtMajorVersion, config, configs, setup); - } - if (uicEnabled) { - SetupAutoTargetUic(target, qtMajorVersion, config, configs, setup); - } + if (digest.MocEnabled || digest.UicEnabled) { + SetupAcquireSkipFiles(digest, setup); + if (digest.MocEnabled) { + SetupAutoTargetMoc(digest, config, configs, setup); } - if (rccEnabled) { - SetupAutoTargetRcc(target, qtMajorVersion, srcFiles); + if (digest.UicEnabled) { + SetupAutoTargetUic(digest, config, configs, setup); } } - - AddDefinitionEscaped(makefile, "_build_dir", - GetAutogenTargetBuildDir(target)); - AddDefinitionEscaped(makefile, "_qt_version_major", qtMajorVersion); - AddDefinitionEscaped(makefile, "_sources", setup.sources); - AddDefinitionEscaped(makefile, "_headers", setup.headers); + if (digest.RccEnabled) { + SetupAutoTargetRcc(digest); + } } // Generate info file @@ -1086,8 +1063,8 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( } // Append custom definitions to info file on demand - if (!configSuffix.empty() || !setup.configMocDefines.empty() || - !setup.configMocIncludes.empty() || !setup.configUicOptions.empty()) { + if (!configSuffix.empty() || !setup.ConfigMocDefines.empty() || + !setup.ConfigMocIncludes.empty() || !setup.ConfigUicOptions.empty()) { // Ensure we have write permission in case .in was read-only. mode_t perm = 0; @@ -1104,39 +1081,22 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( // Open and write file cmsys::ofstream ofs(infoFile.c_str(), std::ios::app); if (ofs) { + auto OfsWriteMap = [&ofs]( + const char* key, const std::map<std::string, std::string>& map) { + for (const auto& item : map) { + ofs << "set(" << key << "_" << item.first << " " + << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; + } + }; 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 << " " - << cmOutputConverter::EscapeForCMake(it->second) << ")\n"; - } - for (std::map<std::string, std::string>::iterator - it = setup.configMocDefines.begin(), - end = setup.configMocDefines.end(); - it != end; ++it) { - ofs << "set(AM_MOC_DEFINITIONS_" << it->first << " " - << cmOutputConverter::EscapeForCMake(it->second) << ")\n"; - } - for (std::map<std::string, std::string>::iterator - it = setup.configMocIncludes.begin(), - end = setup.configMocIncludes.end(); - it != end; ++it) { - ofs << "set(AM_MOC_INCLUDES_" << it->first << " " - << cmOutputConverter::EscapeForCMake(it->second) << ")\n"; - } - for (std::map<std::string, std::string>::iterator - it = setup.configUicOptions.begin(), - end = setup.configUicOptions.end(); - it != end; ++it) { - ofs << "set(AM_UIC_TARGET_OPTIONS_" << it->first << " " - << cmOutputConverter::EscapeForCMake(it->second) << ")\n"; - } + OfsWriteMap("AM_CONFIG_SUFFIX", configSuffix); + OfsWriteMap("AM_MOC_DEFINITIONS", setup.ConfigMocDefines); + OfsWriteMap("AM_MOC_INCLUDES", setup.ConfigMocIncludes); + OfsWriteMap("AM_UIC_TARGET_OPTIONS", setup.ConfigUicOptions); } else { // File open error std::string error = "Internal CMake error when trying to open file: "; - error += cmQtAutoGeneratorCommon::Quoted(infoFile); + error += cmQtAutoGen::Quoted(infoFile); error += " for writing."; cmSystemTools::Error(error.c_str()); } diff --git a/Source/cmQtAutoGeneratorInitializer.h b/Source/cmQtAutoGeneratorInitializer.h index 48ae70e..1264ca5 100644 --- a/Source/cmQtAutoGeneratorInitializer.h +++ b/Source/cmQtAutoGeneratorInitializer.h @@ -4,16 +4,21 @@ #define cmQtAutoGeneratorInitializer_h #include "cmConfigure.h" // IWYU pragma: keep +#include "cmQtAutoGenDigest.h" + +#include <string> class cmGeneratorTarget; -class cmLocalGenerator; class cmQtAutoGeneratorInitializer { public: - static void InitializeAutogenTarget(cmLocalGenerator* localGen, - cmGeneratorTarget* target); - static void SetupAutoGenerateTarget(cmGeneratorTarget const* target); + static std::string GetQtMajorVersion(cmGeneratorTarget const* target); + static std::string GetQtMinorVersion(cmGeneratorTarget const* target, + const std::string& qtVersionMajor); + + static void InitializeAutogenTarget(cmQtAutoGenDigest& digest); + static void SetupAutoGenerateTarget(cmQtAutoGenDigest const& digest); }; #endif diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index d7f1ea7..5ede9d5 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1,15 +1,14 @@ /* 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 "cmQtAutoGenerators.h" -#include "cmQtAutoGeneratorCommon.h" #include "cmsys/FStream.hxx" #include "cmsys/Terminal.h" #include <algorithm> -#include <assert.h> +#include <array> #include <list> #include <sstream> -#include <stdlib.h> #include <string.h> #include <utility> @@ -22,7 +21,6 @@ #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmSystemTools.h" -#include "cm_auto_ptr.hxx" #include "cmake.h" #if defined(__APPLE__) @@ -37,117 +35,33 @@ static const char* SettingsKeyRcc = "AM_RCC_SETTINGS_HASH"; // -- Static functions -inline static std::string Quoted(const std::string& text) -{ - return cmQtAutoGeneratorCommon::Quoted(text); -} - static std::string QuotedCommand(const std::vector<std::string>& command) { std::string res; - for (std::vector<std::string>::const_iterator cit = command.begin(); - cit != command.end(); ++cit) { + for (const std::string& item : command) { if (!res.empty()) { res.push_back(' '); } - const std::string cesc = Quoted(*cit); - if (cit->empty() || (cesc.size() > (cit->size() + 2)) || + const std::string cesc = cmQtAutoGen::Quoted(item); + if (item.empty() || (cesc.size() > (item.size() + 2)) || (cesc.find(' ') != std::string::npos)) { res += cesc; } else { - res += *cit; + res += item; } } return res; } -static void InfoGet(cmMakefile* makefile, const char* key, std::string& value) -{ - value = makefile->GetSafeDefinition(key); -} - -static void InfoGet(cmMakefile* makefile, const char* key, bool& value) -{ - value = makefile->IsOn(key); -} - -static void InfoGet(cmMakefile* makefile, const char* key, - std::vector<std::string>& list) -{ - cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list); -} - -static void InfoGetConfig(cmMakefile* makefile, const char* key, - const std::string& config, std::string& value) -{ - const char* valueConf = nullptr; - { - std::string keyConf = key; - if (!config.empty()) { - keyConf += "_"; - keyConf += config; - } - valueConf = makefile->GetDefinition(keyConf); - } - if (valueConf == nullptr) { - valueConf = makefile->GetSafeDefinition(key); - } - value = valueConf; -} - -static void InfoGetConfig(cmMakefile* makefile, const char* key, - const std::string& config, - std::vector<std::string>& list) -{ - std::string value; - InfoGetConfig(makefile, key, config, value); - cmSystemTools::ExpandListArgument(value, list); -} - -inline static bool SettingsMatch(cmMakefile* makefile, const char* key, - const std::string& value) -{ - return (value == makefile->GetSafeDefinition(key)); -} - -static void SettingAppend(std::string& str, const char* key, - const std::string& value) -{ - if (!value.empty()) { - str += "set("; - str += key; - str += " "; - str += cmOutputConverter::EscapeForCMake(value); - str += ")\n"; - } -} - static std::string SubDirPrefix(const std::string& fileName) { - std::string res(cmsys::SystemTools::GetFilenamePath(fileName)); + std::string res(cmSystemTools::GetFilenamePath(fileName)); if (!res.empty()) { res += '/'; } return res; } -static bool FileNameIsUnique(const std::string& filePath, - const std::map<std::string, std::string>& fileMap) -{ - size_t count(0); - const std::string fileName = cmsys::SystemTools::GetFilenameName(filePath); - for (std::map<std::string, std::string>::const_iterator si = fileMap.begin(); - si != fileMap.end(); ++si) { - if (cmsys::SystemTools::GetFilenameName(si->first) == fileName) { - ++count; - if (count > 1) { - return false; - } - } - } - return true; -} - static bool ReadAll(std::string& content, const std::string& filename) { bool success = false; @@ -172,7 +86,7 @@ static bool FileAbsentOrOlder(const std::string& buildFile, { int result = 0; bool success = - cmsys::SystemTools::FileTimeCompare(buildFile, sourceFile, &result); + cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result); return (!success || (result <= 0)); } @@ -182,82 +96,10 @@ static bool ListContains(const std::vector<std::string>& list, return (std::find(list.begin(), list.end(), entry) != list.end()); } -static std::string JoinOptionsList(const std::vector<std::string>& opts) -{ - return cmOutputConverter::EscapeForCMake(cmJoin(opts, ";")); -} - -static std::string JoinOptionsMap( - const std::map<std::string, std::string>& opts) -{ - std::string result; - for (std::map<std::string, std::string>::const_iterator it = opts.begin(); - it != opts.end(); ++it) { - if (it != opts.begin()) { - result += cmQtAutoGeneratorCommon::listSep; - } - result += it->first; - result += "==="; - result += it->second; - } - return result; -} - -static std::string JoinExts(const std::vector<std::string>& lst) -{ - std::string result; - if (!lst.empty()) { - const std::string separator = ","; - for (std::vector<std::string>::const_iterator it = lst.begin(); - it != lst.end(); ++it) { - if (it != lst.begin()) { - result += separator; - } - result += '.'; - result += *it; - } - } - return result; -} - -static void UicMergeOptions(std::vector<std::string>& opts, - const std::vector<std::string>& fileOpts, - bool isQt5) -{ - static const char* valueOptions[] = { "tr", "translate", - "postfix", "generator", - "include", // Since Qt 5.3 - "g" }; - std::vector<std::string> extraOpts; - for (std::vector<std::string>::const_iterator it = fileOpts.begin(); - it != fileOpts.end(); ++it) { - std::vector<std::string>::iterator existingIt = - std::find(opts.begin(), opts.end(), *it); - if (existingIt != opts.end()) { - const char* o = it->c_str(); - if (*o == '-') { - ++o; - } - if (isQt5 && *o == '-') { - ++o; - } - if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions), - cmStrCmp(*it)) != cmArrayEnd(valueOptions)) { - assert(existingIt + 1 != opts.end()); - *(existingIt + 1) = *(it + 1); - ++it; - } - } else { - extraOpts.push_back(*it); - } - } - opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); -} - // -- Class methods cmQtAutoGenerators::cmQtAutoGenerators() - : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) + : Verbose(cmSystemTools::HasEnv("VERBOSE")) , ColorOutput(true) , MocSettingsChanged(false) , MocPredefsChanged(false) @@ -269,7 +111,7 @@ cmQtAutoGenerators::cmQtAutoGenerators() { std::string colorEnv; - cmsys::SystemTools::GetEnv("COLOR", colorEnv); + cmSystemTools::GetEnv("COLOR", colorEnv); if (!colorEnv.empty()) { if (cmSystemTools::IsOn(colorEnv.c_str())) { this->ColorOutput = true; @@ -279,10 +121,10 @@ cmQtAutoGenerators::cmQtAutoGenerators() } // Moc macro filters - this->MocMacroFilters.push_back( - MocMacroFilter("Q_OBJECT", "[\n][ \t]*{?[ \t]*Q_OBJECT[^a-zA-Z0-9_]")); - this->MocMacroFilters.push_back( - MocMacroFilter("Q_GADGET", "[\n][ \t]*{?[ \t]*Q_GADGET[^a-zA-Z0-9_]")); + this->MocMacroFilters.emplace_back( + "Q_OBJECT", "[\n][ \t]*{?[ \t]*Q_OBJECT[^a-zA-Z0-9_]"); + this->MocMacroFilters.emplace_back( + "Q_GADGET", "[\n][ \t]*{?[ \t]*Q_GADGET[^a-zA-Z0-9_]"); // Precompile regular expressions this->MocRegExpInclude.compile( @@ -305,15 +147,15 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory, snapshot.GetDirectory().SetCurrentBinary(targetDirectory); snapshot.GetDirectory().SetCurrentSource(targetDirectory); - CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, snapshot)); - gg.SetCurrentMakefile(mf.get()); + std::unique_ptr<cmMakefile> makefile(new cmMakefile(&gg, snapshot)); + gg.SetCurrentMakefile(makefile.get()); bool success = false; - if (this->ReadAutogenInfoFile(mf.get(), targetDirectory, config)) { + if (this->ReadAutogenInfoFile(makefile.get(), targetDirectory, config)) { // Read old settings - this->SettingsFileRead(mf.get()); + this->SettingsFileRead(makefile.get()); // Init and run - this->Init(mf.get()); + this->Init(makefile.get()); if (this->RunAutogen()) { // Write current settings if (this->SettingsFileWrite()) { @@ -327,44 +169,114 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory, bool cmQtAutoGenerators::MocDependFilterPush(const std::string& key, const std::string& regExp) { - bool success = false; + std::string error; if (!key.empty()) { if (!regExp.empty()) { - MocDependFilter filter; - filter.key = key; - if (filter.regExp.compile(regExp)) { - this->MocDependFilters.push_back(filter); - success = true; + KeyRegExp filter; + filter.Key = key; + if (filter.RegExp.compile(regExp)) { + this->MocDependFilters.push_back(std::move(filter)); } else { - this->LogError("AutoMoc: Error in AUTOMOC_DEPEND_FILTERS: Compiling " - "regular expression failed.\nKey: " + - Quoted(key) + "\nExp.: " + Quoted(regExp)); + error = "Regular expression compiling failed"; } } else { - this->LogError("AutoMoc: Error in AUTOMOC_DEPEND_FILTERS: Regular " - "expression is empty"); + error = "Regular expression is empty"; } } else { - this->LogError("AutoMoc: Error in AUTOMOC_DEPEND_FILTERS: Key is empty"); + error = "Key is empty"; } - return success; + if (!error.empty()) { + std::string emsg = "AUTOMOC_DEPEND_FILTERS: "; + emsg += error; + emsg += "\n"; + emsg += " Key: "; + emsg += cmQtAutoGen::Quoted(key); + emsg += "\n"; + emsg += " RegExp: "; + emsg += cmQtAutoGen::Quoted(regExp); + emsg += "\n"; + this->LogError(cmQtAutoGen::MOC, emsg); + return false; + } + return true; } bool cmQtAutoGenerators::ReadAutogenInfoFile( cmMakefile* makefile, const std::string& targetDirectory, const std::string& config) { + // Lambdas + auto InfoGet = [makefile](const char* key) { + return makefile->GetSafeDefinition(key); + }; + auto InfoGetBool = [makefile](const char* key) { + return makefile->IsOn(key); + }; + auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> { + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list); + return list; + }; + auto InfoGetLists = + [makefile](const char* key) -> std::vector<std::vector<std::string>> { + std::vector<std::vector<std::string>> lists; + { + const std::string value = makefile->GetSafeDefinition(key); + std::string::size_type pos = 0; + while (pos < value.size()) { + std::string::size_type next = value.find(cmQtAutoGen::listSep, pos); + std::string::size_type length = + (next != std::string::npos) ? next - pos : value.size() - pos; + // Remove enclosing braces + if (length >= 2) { + std::string::const_iterator itBeg = value.begin() + (pos + 1); + std::string::const_iterator itEnd = itBeg + (length - 2); + { + std::string subValue(itBeg, itEnd); + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(subValue, list); + lists.push_back(std::move(list)); + } + } + pos += length; + pos += cmQtAutoGen::listSep.size(); + } + } + return lists; + }; + auto InfoGetConfig = [makefile, &config](const char* key) -> std::string { + const char* valueConf = nullptr; + { + std::string keyConf = key; + if (!config.empty()) { + keyConf += '_'; + keyConf += config; + } + valueConf = makefile->GetDefinition(keyConf); + } + if (valueConf == nullptr) { + valueConf = makefile->GetSafeDefinition(key); + } + return std::string(valueConf); + }; + auto InfoGetConfigList = + [&InfoGetConfig](const char* key) -> std::vector<std::string> { + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(InfoGetConfig(key), list); + return list; + }; + std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); cmSystemTools::ConvertToUnixSlashes(filename); filename += "/AutogenInfo.cmake"; if (!makefile->ReadListFile(filename.c_str())) { - this->LogError("AutoGen: Error processing file: " + filename); + this->LogFileError(cmQtAutoGen::GEN, filename, "File processing failed"); return false; } // -- Meta - InfoGetConfig(makefile, "AM_CONFIG_SUFFIX", config, this->ConfigSuffix); + this->ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX"); // - Old settings file { @@ -376,41 +288,39 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } // - Files and directories - InfoGet(makefile, "AM_CMAKE_SOURCE_DIR", this->ProjectSourceDir); - InfoGet(makefile, "AM_CMAKE_BINARY_DIR", this->ProjectBinaryDir); - InfoGet(makefile, "AM_CMAKE_CURRENT_SOURCE_DIR", this->CurrentSourceDir); - InfoGet(makefile, "AM_CMAKE_CURRENT_BINARY_DIR", this->CurrentBinaryDir); - InfoGet(makefile, "AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", - this->IncludeProjectDirsBefore); - InfoGet(makefile, "AM_BUILD_DIR", this->AutogenBuildDir); + this->ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR"); + this->ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR"); + this->CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR"); + this->CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR"); + this->IncludeProjectDirsBefore = + InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); + this->AutogenBuildDir = InfoGet("AM_BUILD_DIR"); if (this->AutogenBuildDir.empty()) { - this->LogError("AutoGen: Error: Missing autogen build directory "); + this->LogFileError(cmQtAutoGen::GEN, filename, + "Autogen build directory missing"); return false; } - InfoGet(makefile, "AM_SOURCES", this->Sources); - InfoGet(makefile, "AM_HEADERS", this->Headers); + this->Sources = InfoGetList("AM_SOURCES"); + this->Headers = InfoGetList("AM_HEADERS"); // - Qt environment - InfoGet(makefile, "AM_QT_VERSION_MAJOR", this->QtMajorVersion); - if (this->QtMajorVersion.empty()) { - InfoGet(makefile, "AM_Qt5Core_VERSION_MAJOR", this->QtMajorVersion); - } - InfoGet(makefile, "AM_QT_MOC_EXECUTABLE", this->MocExecutable); - InfoGet(makefile, "AM_QT_UIC_EXECUTABLE", this->UicExecutable); - InfoGet(makefile, "AM_QT_RCC_EXECUTABLE", this->RccExecutable); + this->QtMajorVersion = InfoGet("AM_QT_VERSION_MAJOR"); + this->QtMinorVersion = InfoGet("AM_QT_VERSION_MINOR"); + this->MocExecutable = InfoGet("AM_QT_MOC_EXECUTABLE"); + this->UicExecutable = InfoGet("AM_QT_UIC_EXECUTABLE"); + this->RccExecutable = InfoGet("AM_QT_RCC_EXECUTABLE"); // Check Qt version if ((this->QtMajorVersion != "4") && (this->QtMajorVersion != "5")) { - this->LogError("AutoGen: Error: Unsupported Qt version: " + - Quoted(this->QtMajorVersion)); + this->LogFileError(cmQtAutoGen::GEN, filename, "Unsupported Qt version: " + + cmQtAutoGen::Quoted(this->QtMajorVersion)); return false; } // - Moc if (this->MocEnabled()) { - InfoGet(makefile, "AM_MOC_SKIP", this->MocSkipList); - InfoGetConfig(makefile, "AM_MOC_DEFINITIONS", config, - this->MocDefinitions); + this->MocSkipList = InfoGetList("AM_MOC_SKIP"); + this->MocDefinitions = InfoGetConfigList("AM_MOC_DEFINITIONS"); #ifdef _WIN32 { const std::string win32("WIN32"); @@ -419,22 +329,20 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } } #endif - InfoGetConfig(makefile, "AM_MOC_INCLUDES", config, this->MocIncludePaths); - InfoGet(makefile, "AM_MOC_OPTIONS", this->MocOptions); - InfoGet(makefile, "AM_MOC_RELAXED_MODE", this->MocRelaxedMode); + this->MocIncludePaths = InfoGetConfigList("AM_MOC_INCLUDES"); + this->MocOptions = InfoGetList("AM_MOC_OPTIONS"); + this->MocRelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE"); { - std::vector<std::string> MocMacroNames; - InfoGet(makefile, "AM_MOC_MACRO_NAMES", MocMacroNames); - for (std::vector<std::string>::const_iterator dit = - MocMacroNames.begin(); - dit != MocMacroNames.end(); ++dit) { - this->MocMacroFilters.push_back( - MocMacroFilter(*dit, "[^a-zA-Z0-9_]" + *dit + "[^a-zA-Z0-9_]")); + const std::vector<std::string> MocMacroNames = + InfoGetList("AM_MOC_MACRO_NAMES"); + for (const std::string& item : MocMacroNames) { + this->MocMacroFilters.emplace_back( + item, ("[^a-zA-Z0-9_]" + item).append("[^a-zA-Z0-9_]")); } } { - std::vector<std::string> mocDependFilters; - InfoGet(makefile, "AM_MOC_DEPEND_FILTERS", mocDependFilters); + const std::vector<std::string> mocDependFilters = + InfoGetList("AM_MOC_DEPEND_FILTERS"); // Insert Q_PLUGIN_METADATA dependency filter if (this->QtMajorVersion != "4") { this->MocDependFilterPush("Q_PLUGIN_METADATA", @@ -443,49 +351,47 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } // Insert user defined dependency filters if ((mocDependFilters.size() % 2) == 0) { - for (std::vector<std::string>::const_iterator dit = - mocDependFilters.begin(); - dit != mocDependFilters.end(); dit += 2) { + for (std::vector<std::string>::const_iterator + dit = mocDependFilters.begin(), + ditEnd = mocDependFilters.end(); + dit != ditEnd; dit += 2) { if (!this->MocDependFilterPush(*dit, *(dit + 1))) { return false; } } } else { - this->LogError( - "AutoMoc: Error: AUTOMOC_DEPEND_FILTERS list size is not " - "a multiple of 2 in:\n" + - Quoted(filename)); + this->LogFileError( + cmQtAutoGen::MOC, filename, + "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2"); return false; } } - InfoGet(makefile, "AM_MOC_PREDEFS_CMD", this->MocPredefsCmd); + this->MocPredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD"); } // - Uic if (this->UicEnabled()) { - InfoGet(makefile, "AM_UIC_SKIP", this->UicSkipList); - InfoGet(makefile, "AM_UIC_SEARCH_PATHS", this->UicSearchPaths); - InfoGetConfig(makefile, "AM_UIC_TARGET_OPTIONS", config, - this->UicTargetOptions); + this->UicSkipList = InfoGetList("AM_UIC_SKIP"); + this->UicSearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS"); + this->UicTargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS"); { - std::vector<std::string> uicFilesVec; - std::vector<std::string> uicOptionsVec; - InfoGet(makefile, "AM_UIC_OPTIONS_FILES", uicFilesVec); - InfoGet(makefile, "AM_UIC_OPTIONS_OPTIONS", uicOptionsVec); + auto sources = InfoGetList("AM_UIC_OPTIONS_FILES"); + auto options = InfoGetLists("AM_UIC_OPTIONS_OPTIONS"); // Compare list sizes - if (uicFilesVec.size() == uicOptionsVec.size()) { - for (std::vector<std::string>::iterator - fileIt = uicFilesVec.begin(), - optionIt = uicOptionsVec.begin(); - fileIt != uicFilesVec.end(); ++fileIt, ++optionIt) { - cmSystemTools::ReplaceString(*optionIt, - cmQtAutoGeneratorCommon::listSep, ";"); - this->UicOptions[*fileIt] = *optionIt; + if (sources.size() == options.size()) { + auto fitEnd = sources.cend(); + auto fit = sources.begin(); + auto oit = options.begin(); + while (fit != fitEnd) { + this->UicOptions[*fit] = std::move(*oit); + ++fit; + ++oit; } } else { - this->LogError( - "AutoGen: Error: Uic files/options lists size missmatch in:\n" + - Quoted(filename)); + std::ostringstream ost; + ost << "files/options lists sizes missmatch (" << sources.size() << "/" + << options.size() << ")"; + this->LogFileError(cmQtAutoGen::UIC, filename, ost.str()); return false; } } @@ -493,53 +399,48 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( // - Rcc if (this->RccEnabled()) { - InfoGet(makefile, "AM_RCC_SOURCES", this->RccSources); - // File options - { - std::vector<std::string> rccFilesVec; - std::vector<std::string> rccOptionsVec; - InfoGet(makefile, "AM_RCC_OPTIONS_FILES", rccFilesVec); - InfoGet(makefile, "AM_RCC_OPTIONS_OPTIONS", rccOptionsVec); - if (rccFilesVec.size() == rccOptionsVec.size()) { - for (std::vector<std::string>::iterator - fileIt = rccFilesVec.begin(), - optionIt = rccOptionsVec.begin(); - fileIt != rccFilesVec.end(); ++fileIt, ++optionIt) { - // Replace item separator - cmSystemTools::ReplaceString(*optionIt, - cmQtAutoGeneratorCommon::listSep, ";"); - this->RccOptions[*fileIt] = *optionIt; - } - } else { - this->LogError( - "AutoGen: Error: RCC files/options lists size missmatch in:\n" + - Quoted(filename)); - return false; - } - } // File lists + auto sources = InfoGetList("AM_RCC_SOURCES"); + auto builds = InfoGetList("AM_RCC_BUILDS"); + auto options = InfoGetLists("AM_RCC_OPTIONS"); + auto inputs = InfoGetLists("AM_RCC_INPUTS"); + + if (sources.size() != builds.size()) { + std::ostringstream ost; + ost << "sources, builds lists sizes missmatch (" << sources.size() << "/" + << builds.size() << ")"; + this->LogFileError(cmQtAutoGen::RCC, filename, ost.str()); + return false; + } + if (sources.size() != options.size()) { + std::ostringstream ost; + ost << "sources, options lists sizes missmatch (" << sources.size() + << "/" << options.size() << ")"; + this->LogFileError(cmQtAutoGen::RCC, filename, ost.str()); + return false; + } + if (sources.size() != inputs.size()) { + std::ostringstream ost; + ost << "sources, inputs lists sizes missmatch (" << sources.size() << "/" + << inputs.size() << ")"; + this->LogFileError(cmQtAutoGen::RCC, filename, ost.str()); + return false; + } + { - std::vector<std::string> rccInputLists; - InfoGet(makefile, "AM_RCC_INPUTS", rccInputLists); - if (this->RccSources.size() == rccInputLists.size()) { - for (std::vector<std::string>::iterator - fileIt = this->RccSources.begin(), - inputIt = rccInputLists.begin(); - fileIt != this->RccSources.end(); ++fileIt, ++inputIt) { - // Remove braces - *inputIt = inputIt->substr(1, inputIt->size() - 2); - // Replace item separator - cmSystemTools::ReplaceString(*inputIt, - cmQtAutoGeneratorCommon::listSep, ";"); - std::vector<std::string> rccInputFiles; - cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles); - this->RccInputs[*fileIt] = rccInputFiles; - } - } else { - this->LogError( - "AutoGen: Error: RCC sources/inputs lists size missmatch in:\n" + - Quoted(filename)); - return false; + auto srcItEnd = sources.end(); + auto srcIt = sources.begin(); + auto bldIt = builds.begin(); + auto optIt = options.begin(); + auto inpIt = inputs.begin(); + while (srcIt != srcItEnd) { + this->RccJobs.push_back(RccJob{ std::move(*srcIt), std::move(*bldIt), + std::move(*optIt), + std::move(*inpIt) }); + ++srcIt; + ++bldIt; + ++optIt; + ++inpIt; } } } @@ -557,15 +458,15 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) std::string str; str += this->MocExecutable; str += sep; - str += JoinOptionsList(this->MocDefinitions); + str += cmJoin(this->MocDefinitions, ";"); str += sep; - str += JoinOptionsList(this->MocIncludePaths); + str += cmJoin(this->MocIncludePaths, ";"); str += sep; - str += JoinOptionsList(this->MocOptions); + str += cmJoin(this->MocOptions, ";"); str += sep; str += this->IncludeProjectDirsBefore ? "TRUE" : "FALSE"; str += sep; - str += JoinOptionsList(this->MocPredefsCmd); + str += cmJoin(this->MocPredefsCmd, ";"); str += sep; this->SettingsStringMoc = crypt.HashString(str); } @@ -573,17 +474,27 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) std::string str; str += this->UicExecutable; str += sep; - str += JoinOptionsList(this->UicTargetOptions); - str += sep; - str += JoinOptionsMap(this->UicOptions); + str += cmJoin(this->UicTargetOptions, ";"); + for (const auto& item : this->UicOptions) { + str += sep; + str += item.first; + str += sep; + str += cmJoin(item.second, ";"); + } str += sep; this->SettingsStringUic = crypt.HashString(str); } if (this->RccEnabled()) { std::string str; str += this->RccExecutable; - str += sep; - str += JoinOptionsMap(this->RccOptions); + for (const RccJob& rccJob : this->RccJobs) { + str += sep; + str += rccJob.QrcFile; + str += sep; + str += rccJob.RccFile; + str += sep; + str += cmJoin(rccJob.Options, ";"); + } str += sep; this->SettingsStringRcc = crypt.HashString(str); } @@ -591,14 +502,19 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) // Read old settings if (makefile->ReadListFile(this->SettingsFile.c_str())) { - if (!SettingsMatch(makefile, SettingsKeyMoc, this->SettingsStringMoc)) { - this->MocSettingsChanged = true; - } - if (!SettingsMatch(makefile, SettingsKeyUic, this->SettingsStringUic)) { - this->UicSettingsChanged = true; - } - if (!SettingsMatch(makefile, SettingsKeyRcc, this->SettingsStringRcc)) { - this->RccSettingsChanged = true; + { + auto SMatch = [makefile](const char* key, const std::string& value) { + return (value == makefile->GetSafeDefinition(key)); + }; + if (!SMatch(SettingsKeyMoc, this->SettingsStringMoc)) { + this->MocSettingsChanged = true; + } + if (!SMatch(SettingsKeyUic, this->SettingsStringUic)) { + this->UicSettingsChanged = true; + } + if (!SMatch(SettingsKeyRcc, this->SettingsStringRcc)) { + this->RccSettingsChanged = true; + } } // In case any setting changed remove the old settings file. // This triggers a full rebuild on the next run if the current @@ -620,18 +536,28 @@ bool cmQtAutoGenerators::SettingsFileWrite() // Only write if any setting changed if (this->AnySettingsChanged()) { if (this->Verbose) { - this->LogInfo("AutoGen: Writing settings file " + - Quoted(this->SettingsFile)); + this->LogInfo(cmQtAutoGen::GEN, "Writing settings file " + + cmQtAutoGen::Quoted(this->SettingsFile)); } // Compose settings file content std::string settings; - SettingAppend(settings, SettingsKeyMoc, this->SettingsStringMoc); - SettingAppend(settings, SettingsKeyUic, this->SettingsStringUic); - SettingAppend(settings, SettingsKeyRcc, this->SettingsStringRcc); + { + auto SettingAppend = [&settings](const char* key, + const std::string& value) { + settings += "set("; + settings += key; + settings += " "; + settings += cmOutputConverter::EscapeForCMake(value); + settings += ")\n"; + }; + SettingAppend(SettingsKeyMoc, this->SettingsStringMoc); + SettingAppend(SettingsKeyUic, this->SettingsStringUic); + SettingAppend(SettingsKeyRcc, this->SettingsStringRcc); + } // Write settings file - if (!this->FileWrite("AutoGen", this->SettingsFile, settings)) { - this->LogError("AutoGen: Error: Could not write old settings file " + - Quoted(this->SettingsFile)); + if (!this->FileWrite(cmQtAutoGen::GEN, this->SettingsFile, settings)) { + this->LogFileError(cmQtAutoGen::GEN, this->SettingsFile, + "File writing failed"); // Remove old settings file to trigger a full rebuild on the next run cmSystemTools::RemoveFile(this->SettingsFile); success = false; @@ -679,14 +605,14 @@ void cmQtAutoGenerators::Init(cmMakefile* makefile) this->MocIncludePaths.reserve(includes.size()); // Append project directories only { - const char* movePaths[2] = { this->ProjectBinaryDir.c_str(), - this->ProjectSourceDir.c_str() }; - for (const char* const* mpit = cmArrayBegin(movePaths); - mpit != cmArrayEnd(movePaths); ++mpit) { + const std::array<const std::string*, 2> movePaths = { + { &this->ProjectBinaryDir, &this->ProjectSourceDir } + }; + for (const std::string* ppath : movePaths) { std::list<std::string>::iterator it = includes.begin(); while (it != includes.end()) { const std::string& path = *it; - if (cmsys::SystemTools::StringStartsWith(path, *mpit)) { + if (cmSystemTools::StringStartsWith(path, ppath->c_str())) { this->MocIncludePaths.push_back(path); it = includes.erase(it); } else { @@ -702,26 +628,22 @@ void cmQtAutoGenerators::Init(cmMakefile* makefile) // Compose moc includes list { std::set<std::string> frameworkPaths; - for (std::vector<std::string>::const_iterator it = - this->MocIncludePaths.begin(); - it != this->MocIncludePaths.end(); ++it) { - const std::string& path = *it; + for (const std::string& path : this->MocIncludePaths) { this->MocIncludes.push_back("-I" + path); // Extract framework path if (cmHasLiteralSuffix(path, ".framework/Headers")) { // Go up twice to get to the framework root std::vector<std::string> pathComponents; - cmsys::SystemTools::SplitPath(path, pathComponents); - std::string frameworkPath = cmsys::SystemTools::JoinPath( + cmSystemTools::SplitPath(path, pathComponents); + std::string frameworkPath = cmSystemTools::JoinPath( pathComponents.begin(), pathComponents.end() - 2); frameworkPaths.insert(frameworkPath); } } // Append framework includes - for (std::set<std::string>::const_iterator it = frameworkPaths.begin(); - it != frameworkPaths.end(); ++it) { + for (const std::string& path : frameworkPaths) { this->MocIncludes.push_back("-F"); - this->MocIncludes.push_back(*it); + this->MocIncludes.push_back(path); } } } @@ -740,9 +662,9 @@ bool cmQtAutoGenerators::RunAutogen() { const std::string incDirAbs = cmSystemTools::CollapseCombinedPath( this->AutogenBuildDir, this->AutogenIncludeDir); - if (!cmsys::SystemTools::MakeDirectory(incDirAbs)) { - this->LogError("AutoGen: Error: Could not create include directory " + - Quoted(incDirAbs)); + if (!cmSystemTools::MakeDirectory(incDirAbs)) { + this->LogFileError(cmQtAutoGen::GEN, incDirAbs, + "Could not create directory"); return false; } } @@ -757,28 +679,23 @@ bool cmQtAutoGenerators::RunAutogen() std::set<std::string> uicHeaderFiles; // Parse sources - for (std::vector<std::string>::const_iterator it = this->Sources.begin(); - it != this->Sources.end(); ++it) { - const std::string& absFilename = cmsys::SystemTools::GetRealPath(*it); + for (const std::string& src : this->Sources) { // Parse source file for MOC/UIC - if (!this->ParseSourceFile(absFilename, mocsIncluded, mocDepends, - uisIncluded, this->MocRelaxedMode)) { + if (!this->ParseSourceFile(src, mocsIncluded, mocDepends, uisIncluded, + this->MocRelaxedMode)) { return false; } // Find additional headers - this->SearchHeadersForSourceFile(absFilename, mocHeaderFiles, - uicHeaderFiles); + this->SearchHeadersForSourceFile(src, mocHeaderFiles, uicHeaderFiles); } // Parse headers - for (std::vector<std::string>::const_iterator it = this->Headers.begin(); - it != this->Headers.end(); ++it) { - const std::string& headerName = cmsys::SystemTools::GetRealPath(*it); - if (!this->MocSkip(headerName)) { - mocHeaderFiles.insert(headerName); + for (const std::string& hdr : this->Headers) { + if (!this->MocSkip(hdr)) { + mocHeaderFiles.insert(hdr); } - if (!this->UicSkip(headerName)) { - uicHeaderFiles.insert(headerName); + if (!this->UicSkip(hdr)) { + uicHeaderFiles.insert(hdr); } } if (!this->ParseHeaders(mocHeaderFiles, uicHeaderFiles, mocsIncluded, @@ -807,17 +724,14 @@ bool cmQtAutoGenerators::RunAutogen() bool cmQtAutoGenerators::MocRequired(const std::string& contentText, std::string* macroName) { - for (std::vector<MocMacroFilter>::iterator fit = - this->MocMacroFilters.begin(); - fit != this->MocMacroFilters.end(); ++fit) { - MocMacroFilter& filter = *fit; + for (KeyRegExp& filter : this->MocMacroFilters) { // Run a simple find string operation before the expensive // regular expression check - if (contentText.find(filter.first) != std::string::npos) { - if (filter.second.find(contentText)) { + if (contentText.find(filter.Key) != std::string::npos) { + if (filter.RegExp.find(contentText)) { // Return macro name on demand if (macroName != nullptr) { - *macroName = filter.first; + *macroName = filter.Key; } return true; } @@ -830,35 +744,33 @@ void cmQtAutoGenerators::MocFindDepends( const std::string& absFilename, const std::string& contentText, std::map<std::string, std::set<std::string>>& mocDepends) { - for (std::vector<MocDependFilter>::iterator fit = - this->MocDependFilters.begin(); - fit != this->MocDependFilters.end(); ++fit) { - MocDependFilter& filter = *fit; + for (KeyRegExp& filter : this->MocDependFilters) { // Run a simple find string operation before the expensive // regular expression check - if (contentText.find(filter.key) != std::string::npos) { + if (contentText.find(filter.Key) != std::string::npos) { // Run regular expression check loop const std::string sourcePath = SubDirPrefix(absFilename); const char* contentChars = contentText.c_str(); - while (filter.regExp.find(contentChars)) { + while (filter.RegExp.find(contentChars)) { // Evaluate match - const std::string match = filter.regExp.match(1); + const std::string match = filter.RegExp.match(1); if (!match.empty()) { // Find the dependency file std::string incFile; if (this->MocFindIncludedFile(incFile, sourcePath, match)) { mocDepends[absFilename].insert(incFile); if (this->Verbose) { - this->LogInfo("AutoMoc: Found dependency:\n " + - Quoted(absFilename) + "\n " + Quoted(incFile)); + this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n " + + cmQtAutoGen::Quoted(absFilename) + "\n " + + cmQtAutoGen::Quoted(incFile)); } } else { - this->LogWarning("AutoMoc: Warning: " + Quoted(absFilename) + - "\n" + "Could not find dependency file " + - Quoted(match)); + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, + "Could not find dependency file " + + cmQtAutoGen::Quoted(match)); } } - contentChars += filter.regExp.end(); + contentChars += filter.RegExp.end(); } } } @@ -916,15 +828,10 @@ bool cmQtAutoGenerators::ParseSourceFile( this->UicParseContent(absFilename, contentText, uisIncluded); } } else { - std::ostringstream ost; - ost << "AutoGen: Warning: The file is empty:\n" - << Quoted(absFilename) << "\n"; - this->LogWarning(ost.str()); + this->LogFileWarning(cmQtAutoGen::GEN, absFilename, "The file is empty"); } } else { - std::ostringstream ost; - ost << "AutoGen: Error: Could not read file:\n" << Quoted(absFilename); - this->LogError(ost.str()); + this->LogFileError(cmQtAutoGen::GEN, absFilename, "Could not read file"); } return success; } @@ -934,7 +841,7 @@ void cmQtAutoGenerators::UicParseContent( std::map<std::string, std::vector<std::string>>& uisIncluded) { if (this->Verbose) { - this->LogInfo("AutoUic: Checking " + absFilename); + this->LogInfo(cmQtAutoGen::UIC, "Checking " + absFilename); } const char* contentChars = contentText.c_str(); @@ -946,6 +853,36 @@ void cmQtAutoGenerators::UicParseContent( } } +std::string cmQtAutoGenerators::MocMacroNamesString() const +{ + std::string res; + const auto itB = this->MocMacroFilters.cbegin(); + const auto itE = this->MocMacroFilters.cend(); + const auto itL = itE - 1; + auto itC = itB; + for (; itC != itE; ++itC) { + // Separator + if (itC != itB) { + if (itC != itL) { + res += ", "; + } else { + res += " or "; + } + } + // Key + res += itC->Key; + } + return res; +} + +std::string cmQtAutoGenerators::MocHeaderSuffixesString() const +{ + std::string res = ".{"; + res += cmJoin(this->HeaderExtensions, ","); + res += "}"; + return res; +} + /** * @return True on success */ @@ -955,15 +892,15 @@ bool cmQtAutoGenerators::MocParseSourceContent( std::map<std::string, std::set<std::string>>& mocDepends, bool relaxed) { if (this->Verbose) { - this->LogInfo("AutoMoc: Checking " + absFilename); + this->LogInfo(cmQtAutoGen::MOC, "Checking " + absFilename); } - const std::string scannedFileAbsPath = SubDirPrefix(absFilename); - const std::string scannedFileBasename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); + const std::string scanFileDir = SubDirPrefix(absFilename); + const std::string scanFileBase = + cmSystemTools::GetFilenameWithoutLastExtension(absFilename); - std::string macroName; - const bool requiresMoc = this->MocRequired(contentText, ¯oName); + std::string selfMacroName; + const bool selfRequiresMoc = this->MocRequired(contentText, &selfMacroName); bool ownDotMocIncluded = false; std::string ownMocUnderscoreInclude; std::string ownMocUnderscoreHeader; @@ -977,120 +914,132 @@ bool cmQtAutoGenerators::MocParseSourceContent( while (this->MocRegExpInclude.find(contentChars)) { const std::string incString = this->MocRegExpInclude.match(1); // Basename of the moc include - const std::string incSubDir(SubDirPrefix(incString)); - const std::string incBasename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(incString); + const std::string incDir(SubDirPrefix(incString)); + const std::string incBase = + cmSystemTools::GetFilenameWithoutLastExtension(incString); // If the moc include is of the moc_foo.cpp style we expect // the Q_OBJECT class declaration in a header file. // If the moc include is of the foo.moc style we need to look for // a Q_OBJECT macro in the current source file, if it contains the // macro we generate the moc file from the source file. - if (cmHasLiteralPrefix(incBasename, "moc_")) { + if (cmHasLiteralPrefix(incBase, "moc_")) { // Include: moc_FOO.cxx // Remove the moc_ part - const std::string incRealBasename = incBasename.substr(4); + const std::string incRealBase = incBase.substr(4); const std::string headerToMoc = - this->MocFindHeader(scannedFileAbsPath, incSubDir + incRealBasename); + this->MocFindHeader(scanFileDir, incDir + incRealBase); if (!headerToMoc.empty()) { if (!this->MocSkip(headerToMoc)) { // Register moc job mocsIncluded[headerToMoc] = incString; this->MocFindDepends(headerToMoc, contentText, mocDepends); // Store meta information for relaxed mode - if (relaxed && (incRealBasename == scannedFileBasename)) { + if (relaxed && (incRealBase == scanFileBase)) { ownMocUnderscoreInclude = incString; ownMocUnderscoreHeader = headerToMoc; } } } else { std::ostringstream ost; - ost << "AutoMoc: Error: " << Quoted(absFilename) << "\n" - << "The file includes the moc file " << Quoted(incString) - << ", but could not find header " - << Quoted(incRealBasename + "{" + - JoinExts(this->HeaderExtensions) + "}"); - ; - this->LogError(ost.str()); + ost << "The file includes the moc file " + << cmQtAutoGen::Quoted(incString) + << ", but could not find header "; + ost << cmQtAutoGen::Quoted(incRealBase + + this->MocHeaderSuffixesString()); + this->LogFileError(cmQtAutoGen::MOC, absFilename, ost.str()); return false; } } else { // Include: FOO.moc + bool ownDotMoc = (incBase == scanFileBase); std::string fileToMoc; if (relaxed) { // Mode: Relaxed - if (requiresMoc && (incBasename == scannedFileBasename)) { + if (selfRequiresMoc && ownDotMoc) { // Include self fileToMoc = absFilename; ownDotMocIncluded = true; } else { // In relaxed mode try to find a header instead but issue a warning const std::string headerToMoc = - this->MocFindHeader(scannedFileAbsPath, incSubDir + incBasename); + this->MocFindHeader(scanFileDir, incDir + incBase); if (!headerToMoc.empty()) { if (!this->MocSkip(headerToMoc)) { // This is for KDE4 compatibility: fileToMoc = headerToMoc; - if (!requiresMoc && (incBasename == scannedFileBasename)) { - std::ostringstream ost; - ost - << "AutoMoc: Warning: " << Quoted(absFilename) << "\n" - << "The file includes the moc file " << Quoted(incString) - << ", but does not contain a Q_OBJECT or Q_GADGET macro.\n" - << "Running moc on " << Quoted(headerToMoc) << "!\n" - << "Include " << Quoted("moc_" + incBasename + ".cpp") - << " for a compatibility with strict mode (see " - "CMAKE_AUTOMOC_RELAXED_MODE).\n"; - this->LogWarning(ost.str()); + + auto quoted_inc = cmQtAutoGen::Quoted(incString); + auto quoted_header = cmQtAutoGen::Quoted(headerToMoc); + auto quoted_base = + cmQtAutoGen::Quoted("moc_" + incBase + ".cpp"); + if (!selfRequiresMoc) { + if (ownDotMoc) { + std::ostringstream ost; + ost << "The file includes the moc file " << quoted_inc + << ", but does not contain a " + << this->MocMacroNamesString() << " macro.\n" + << "Running moc on\n" + << " " << quoted_header << "!\n" + << "Better include " << quoted_base + << " for a compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, + ost.str()); + } else if (!ownDotMoc) { + std::ostringstream ost; + ost << "The file includes the moc file " << quoted_inc + << " instead of " << quoted_base << ".\n"; + ost << "Running moc on\n" + << " " << quoted_header << "!\n" + << "Better include " << quoted_base + << " for compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, + ost.str()); + } } else { - std::ostringstream ost; - ost << "AutoMoc: Warning: " << Quoted(absFilename) << "\n" - << "The file includes the moc file " << Quoted(incString) - << " instead of " - << Quoted("moc_" + incBasename + ".cpp") << ".\n" - << "Running moc on " << Quoted(headerToMoc) << "!\n" - << "Include " << Quoted("moc_" + incBasename + ".cpp") - << " for compatibility with strict mode (see " - "CMAKE_AUTOMOC_RELAXED_MODE).\n"; - this->LogWarning(ost.str()); + if (!ownDotMoc) { + // Handled further down + } } } } else { std::ostringstream ost; - ost << "AutoMoc: Error: " << Quoted(absFilename) << "\n" - << "The file includes the moc file " << Quoted(incString) + ost << "The file includes the moc file " + << cmQtAutoGen::Quoted(incString) << ", which seems to be the moc file from a different " "source file. CMake also could not find a matching " "header."; - this->LogError(ost.str()); + this->LogFileError(cmQtAutoGen::MOC, absFilename, ost.str()); return false; } } } else { // Mode: Strict - if (incBasename == scannedFileBasename) { + if (ownDotMoc) { // Include self fileToMoc = absFilename; ownDotMocIncluded = true; // Accept but issue a warning if moc isn't required - if (!requiresMoc) { + if (!selfRequiresMoc) { std::ostringstream ost; - ost << "AutoMoc: Warning: " << Quoted(absFilename) << "\n" - << "The file includes the moc file " << Quoted(incString) - << ", but does not contain a Q_OBJECT or Q_GADGET " - "macro."; - this->LogWarning(ost.str()); + ost << "The file includes the moc file " + << cmQtAutoGen::Quoted(incString) + << ", but does not contain a " << this->MocMacroNamesString() + << " macro."; + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, ost.str()); } } else { // Don't allow FOO.moc include other than self in strict mode std::ostringstream ost; - ost << "AutoMoc: Error: " << Quoted(absFilename) << "\n" - << "The file includes the moc file " << Quoted(incString) + ost << "The file includes the moc file " + << cmQtAutoGen::Quoted(incString) << ", which seems to be the moc file from a different " "source file. This is not supported. Include " - << Quoted(scannedFileBasename + ".moc") + << cmQtAutoGen::Quoted(scanFileBase + ".moc") << " to run moc on this source file."; - this->LogError(ost.str()); + this->LogFileError(cmQtAutoGen::MOC, absFilename, ost.str()); return false; } } @@ -1104,24 +1053,26 @@ bool cmQtAutoGenerators::MocParseSourceContent( } } - if (requiresMoc && !ownDotMocIncluded) { - // In this case, check whether the scanned file itself contains a Q_OBJECT. + if (selfRequiresMoc && !ownDotMocIncluded) { + // In this case, check whether the scanned file itself contains a + // Q_OBJECT. // If this is the case, the moc_foo.cpp should probably be generated from // foo.cpp instead of foo.h, because otherwise it won't build. // But warn, since this is not how it is supposed to be used. if (relaxed && !ownMocUnderscoreInclude.empty()) { // This is for KDE4 compatibility: std::ostringstream ost; - ost << "AutoMoc: Warning: " << Quoted(absFilename) << "\n" - << "The file contains a " << macroName + ost << "The file contains a " << selfMacroName << " macro, but does not include " - << Quoted(scannedFileBasename + ".moc") << ", but instead includes " - << Quoted(ownMocUnderscoreInclude) << ".\n" - << "Running moc on " << Quoted(absFilename) << "!\n" - << "Better include " << Quoted(scannedFileBasename + ".moc") - << " for compatibility with strict mode (see " - "CMAKE_AUTOMOC_RELAXED_MODE)."; - this->LogWarning(ost.str()); + << cmQtAutoGen::Quoted(scanFileBase + ".moc") + << ". Instead it includes " + << cmQtAutoGen::Quoted(ownMocUnderscoreInclude) << ".\n" + << "Running moc on\n" + << " " << cmQtAutoGen::Quoted(absFilename) << "!\n" + << "Better include " << cmQtAutoGen::Quoted(scanFileBase + ".moc") + << " for compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)"; + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, ost.str()); // Use scanned source file instead of scanned header file as moc source mocsIncluded[absFilename] = ownMocUnderscoreInclude; @@ -1131,13 +1082,12 @@ bool cmQtAutoGenerators::MocParseSourceContent( } else { // Otherwise always error out since it will not compile: std::ostringstream ost; - ost << "AutoMoc: Error: " << Quoted(absFilename) << "\n" - << "The file contains a " << macroName + ost << "The file contains a " << selfMacroName << " macro, but does not include " - << Quoted(scannedFileBasename + ".moc") << "!\n" + << cmQtAutoGen::Quoted(scanFileBase + ".moc") << "!\n" << "Consider adding the include or enabling SKIP_AUTOMOC for this " "file."; - this->LogError(ost.str()); + this->LogFileError(cmQtAutoGen::MOC, absFilename, ost.str()); return false; } } @@ -1152,7 +1102,7 @@ void cmQtAutoGenerators::MocParseHeaderContent( { // Log if (this->Verbose) { - this->LogInfo("AutoMoc: Checking " + absFilename); + this->LogInfo(cmQtAutoGen::MOC, "Checking " + absFilename); } if (this->MocRequired(contentText)) { // Register moc job @@ -1166,19 +1116,19 @@ void cmQtAutoGenerators::SearchHeadersForSourceFile( const std::string& absFilename, std::set<std::string>& mocHeaderFiles, std::set<std::string>& uicHeaderFiles) const { - std::string basepaths[2]; + std::array<std::string, 2> basepaths; { std::string bpath = SubDirPrefix(absFilename); - bpath += cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); + bpath += cmSystemTools::GetFilenameWithoutLastExtension(absFilename); // search for default header files and private header files basepaths[0] = bpath; - basepaths[1] = bpath + "_p"; + basepaths[1] = bpath; + basepaths[1] += "_p"; } - for (const std::string* bpit = cmArrayBegin(basepaths); - bpit != cmArrayEnd(basepaths); ++bpit) { + for (const std::string& bPath : basepaths) { std::string headerName; - if (this->FindHeader(headerName, *bpit)) { + if (this->FindHeader(headerName, bPath)) { // Moc headers if (!this->MocSkip(absFilename) && !this->MocSkip(headerName)) { mocHeaderFiles.insert(headerName); @@ -1205,9 +1155,7 @@ bool cmQtAutoGenerators::ParseHeaders( headerFiles.insert(mocHeaderFiles.begin(), mocHeaderFiles.end()); headerFiles.insert(uicHeaderFiles.begin(), uicHeaderFiles.end()); - for (std::set<std::string>::const_iterator hIt = headerFiles.begin(); - hIt != headerFiles.end(); ++hIt) { - const std::string& headerName = *hIt; + for (const std::string& headerName : headerFiles) { std::string contentText; if (ReadAll(contentText, headerName)) { // Parse header content for MOC @@ -1221,10 +1169,8 @@ bool cmQtAutoGenerators::ParseHeaders( this->UicParseContent(headerName, contentText, uisIncluded); } } else { - std::ostringstream ost; - ost << "AutoGen: Error: Could not read header file:\n" - << Quoted(headerName); - this->LogError(ost.str()); + this->LogFileError(cmQtAutoGen::GEN, headerName, + "Could not read header file"); success = false; break; } @@ -1248,14 +1194,12 @@ bool cmQtAutoGenerators::MocGenerateAll( std::map<std::string, std::string> mergedMocs(mocsIncluded); mergedMocs.insert(mocsNotIncluded.begin(), mocsNotIncluded.end()); if (this->NameCollisionTest(mergedMocs, collisions)) { - std::ostringstream ost; - ost << "AutoMoc: Error: " - "The same moc file will be generated " - "from different sources.\n" - "To avoid this error either\n" - "- rename the source files or\n" - "- do not include the (moc_NAME.cpp|NAME.moc) file"; - this->LogErrorNameCollision(ost.str(), collisions); + std::string msg = "The same moc file will be generated " + "from different sources.\n" + "To avoid this error either\n" + " - rename the source files or\n" + " - do not include the (moc_NAME.cpp|NAME.moc) file"; + this->LogNameCollisionError(cmQtAutoGen::MOC, msg, collisions); return false; } } @@ -1276,33 +1220,35 @@ bool cmQtAutoGenerators::MocGenerateAll( cmd.insert(cmd.end(), this->MocIncludes.begin(), this->MocIncludes.end()); // Add definitions - for (std::vector<std::string>::const_iterator it = - this->MocDefinitions.begin(); - it != this->MocDefinitions.end(); ++it) { - cmd.push_back("-D" + (*it)); + for (const std::string& def : this->MocDefinitions) { + cmd.push_back("-D" + def); } // Add options cmd.insert(cmd.end(), this->MocOptions.begin(), this->MocOptions.end()); // Execute command - if (!this->RunCommand(cmd, output, false)) { - { - std::ostringstream ost; - ost << "AutoMoc: Error: moc predefs generation command failed\n"; - ost << "AutoMoc: Command:\n" << QuotedCommand(cmd) << "\n"; - ost << "AutoMoc: Command output:\n" << output << "\n"; - this->LogError(ost.str()); - } + if (!this->RunCommand(cmd, output)) { + this->LogCommandError(cmQtAutoGen::MOC, + "moc_predefs generation failed", cmd, output); return false; } } + // (Re)write predefs file only on demand if (this->FileDiffers(this->MocPredefsFileAbs, output)) { - if (this->FileWrite("AutoMoc", this->MocPredefsFileAbs, output)) { + if (this->FileWrite(cmQtAutoGen::MOC, this->MocPredefsFileAbs, + output)) { this->MocPredefsChanged = true; } else { return false; } + } else { + // Touch to update the time stamp + if (this->Verbose) { + this->LogInfo(cmQtAutoGen::MOC, + "Touching moc_predefs " + this->MocPredefsFileRel); + } + cmSystemTools::Touch(this->MocPredefsFileAbs, false); } } } @@ -1356,13 +1302,15 @@ bool cmQtAutoGenerators::MocGenerateAll( if (this->Verbose) { this->LogBold("Generating MOC compilation " + this->MocCompFileRel); } - if (!this->FileWrite("AutoMoc", this->MocCompFileAbs, automocSource)) { + if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, + automocSource)) { return false; } } else if (mocCompFileGenerated) { // Only touch mocs compilation file if (this->Verbose) { - this->LogInfo("Touching MOC compilation " + this->MocCompFileRel); + this->LogInfo(cmQtAutoGen::MOC, + "Touching mocs compilation " + this->MocCompFileRel); } cmSystemTools::Touch(this->MocCompFileAbs, false); } @@ -1411,7 +1359,7 @@ bool cmQtAutoGenerators::MocGenerateFile( } // Make sure the parent directory exists - if (this->MakeParentDirectory("AutoMoc", mocFileAbs)) { + if (this->MakeParentDirectory(cmQtAutoGen::MOC, mocFileAbs)) { // Compose moc command std::vector<std::string> cmd; cmd.push_back(this->MocExecutable); @@ -1419,10 +1367,8 @@ bool cmQtAutoGenerators::MocGenerateFile( cmd.insert(cmd.end(), this->MocIncludes.begin(), this->MocIncludes.end()); // Add definitions - for (std::vector<std::string>::const_iterator it = - this->MocDefinitions.begin(); - it != this->MocDefinitions.end(); ++it) { - cmd.push_back("-D" + (*it)); + for (const std::string& def : this->MocDefinitions) { + cmd.push_back("-D" + def); } // Add options cmd.insert(cmd.end(), this->MocOptions.begin(), this->MocOptions.end()); @@ -1441,15 +1387,9 @@ bool cmQtAutoGenerators::MocGenerateFile( // Success mocGenerated = true; } else { - // Command failed - { - std::ostringstream ost; - ost << "AutoMoc: Error: moc process failed for\n"; - ost << Quoted(mocFileRel) << "\n"; - ost << "AutoMoc: Command:\n" << QuotedCommand(cmd) << "\n"; - ost << "AutoMoc: Command output:\n" << output << "\n"; - this->LogError(ost.str()); - } + this->LogCommandError(cmQtAutoGen::MOC, "moc failed for\n " + + cmQtAutoGen::Quoted(sourceFile), + cmd, output); cmSystemTools::RemoveFile(mocFileAbs); this->MocRunFailed = true; } @@ -1470,7 +1410,11 @@ bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, std::vector<std::string> testFiles; // Collect search paths list { - const std::string searchFileFull = searchPath + searchFile; + std::string searchFileFull; + if (!searchPath.empty()) { + searchFileFull = searchPath; + searchFileFull += searchFile; + } // Vicinity of the source { const std::string sourcePath = SubDirPrefix(sourceFile); @@ -1481,27 +1425,21 @@ bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, } // AUTOUIC search paths if (!this->UicSearchPaths.empty()) { - for (std::vector<std::string>::const_iterator iit = - this->UicSearchPaths.begin(); - iit != this->UicSearchPaths.end(); ++iit) { - testFiles.push_back(*iit + "/" + searchFile); + for (const std::string& sPath : this->UicSearchPaths) { + testFiles.push_back((sPath + "/").append(searchFile)); } if (!searchPath.empty()) { - for (std::vector<std::string>::const_iterator iit = - this->UicSearchPaths.begin(); - iit != this->UicSearchPaths.end(); ++iit) { - testFiles.push_back(*iit + "/" + searchFileFull); + for (const std::string& sPath : this->UicSearchPaths) { + testFiles.push_back((sPath + "/").append(searchFileFull)); } } } } // Search for the .ui file! - for (std::vector<std::string>::const_iterator iit = testFiles.begin(); - iit != testFiles.end(); ++iit) { - const std::string& testFile = *iit; - if (cmsys::SystemTools::FileExists(testFile.c_str())) { - absFile = cmsys::SystemTools::GetRealPath(testFile); + for (const std::string& testFile : testFiles) { + if (cmSystemTools::FileExists(testFile.c_str())) { + absFile = cmSystemTools::GetRealPath(testFile); success = true; break; } @@ -1510,13 +1448,11 @@ bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, // Log error if (!success) { std::ostringstream ost; - ost << "AutoUic: Error: " << Quoted(sourceFile) << "\n"; - ost << "Could not find " << Quoted(searchFile) << " in\n"; - for (std::vector<std::string>::const_iterator iit = testFiles.begin(); - iit != testFiles.end(); ++iit) { - ost << " " << Quoted(*iit) << "\n"; + ost << "Could not find " << cmQtAutoGen::Quoted(searchFile) << " in\n"; + for (const std::string& testFile : testFiles) { + ost << " " << cmQtAutoGen::Quoted(testFile) << "\n"; } - this->LogError(ost.str()); + this->LogFileError(cmQtAutoGen::UIC, sourceFile, ost.str()); } return success; @@ -1542,16 +1478,18 @@ bool cmQtAutoGenerators::UicGenerateAll( const std::vector<std::string>& sourceIncs(sit->second); // insert new source/destination map std::map<std::string, std::string>& uiGenMap = sourceGenMap[source]; - for (std::vector<std::string>::const_iterator uit = sourceIncs.begin(); - uit != sourceIncs.end(); ++uit) { + for (const std::string& inc : sourceIncs) { // Remove ui_ from the begin filename by substr() - const std::string uiBasePath = SubDirPrefix(*uit); + const std::string uiBasePath = SubDirPrefix(inc); const std::string uiBaseName = - cmsys::SystemTools::GetFilenameWithoutLastExtension(*uit).substr(3); + cmSystemTools::GetFilenameWithoutLastExtension(inc).substr(3); const std::string uiFileName = uiBaseName + ".ui"; std::string uiInputFile; if (UicFindIncludedFile(uiInputFile, source, uiBasePath, uiFileName)) { - std::string uiOutputFile = uiBasePath + "ui_" + uiBaseName + ".h"; + std::string uiOutputFile = uiBasePath; + uiOutputFile += "ui_"; + uiOutputFile += uiBaseName; + uiOutputFile += ".h"; cmSystemTools::ReplaceString(uiOutputFile, "..", "__"); uiGenMap[uiInputFile] = uiOutputFile; testMap[uiInputFile] = uiOutputFile; @@ -1564,25 +1502,19 @@ bool cmQtAutoGenerators::UicGenerateAll( { std::multimap<std::string, std::string> collisions; if (this->NameCollisionTest(testMap, collisions)) { - std::ostringstream ost; - ost << "AutoUic: Error: The same ui_NAME.h file will be generated " - "from different sources.\n" - "To avoid this error rename the source files.\n"; - this->LogErrorNameCollision(ost.str(), collisions); + std::string msg = "The same ui_NAME.h file will be generated " + "from different sources.\n" + "To avoid this error rename the source files.\n"; + this->LogNameCollisionError(cmQtAutoGen::UIC, msg, collisions); return false; } } } // generate ui files - for (std::map<std::string, - std::map<std::string, std::string>>::const_iterator it = - sourceGenMap.begin(); - it != sourceGenMap.end(); ++it) { - for (std::map<std::string, std::string>::const_iterator sit = - it->second.begin(); - sit != it->second.end(); ++sit) { - if (!this->UicGenerateFile(it->first, sit->first, sit->second)) { + for (const auto& srcItem : sourceGenMap) { + for (const auto& item : srcItem.second) { + if (!this->UicGenerateFile(srcItem.first, item.first, item.second)) { if (this->UicRunFailed) { return false; } @@ -1618,18 +1550,16 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, } // Make sure the parent directory exists - if (this->MakeParentDirectory("AutoUic", uicFileAbs)) { + if (this->MakeParentDirectory(cmQtAutoGen::UIC, uicFileAbs)) { // Compose uic command std::vector<std::string> cmd; cmd.push_back(this->UicExecutable); { std::vector<std::string> allOpts = this->UicTargetOptions; - std::map<std::string, std::string>::const_iterator optionIt = - this->UicOptions.find(uiInputFile); + auto optionIt = this->UicOptions.find(uiInputFile); if (optionIt != this->UicOptions.end()) { - std::vector<std::string> fileOpts; - cmSystemTools::ExpandListArgument(optionIt->second, fileOpts); - UicMergeOptions(allOpts, fileOpts, (this->QtMajorVersion == "5")); + cmQtAutoGen::UicMergeOptions(allOpts, optionIt->second, + (this->QtMajorVersion == "5")); } cmd.insert(cmd.end(), allOpts.begin(), allOpts.end()); } @@ -1645,12 +1575,11 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, // Command failed { std::ostringstream ost; - ost << "AutoUic: Error: uic process failed for\n"; - ost << Quoted(uicFileRel) << " needed by\n"; - ost << Quoted(realName) << "\n"; - ost << "AutoUic: Command:\n" << QuotedCommand(cmd) << "\n"; - ost << "AutoUic: Command output:\n" << output << "\n"; - this->LogError(ost.str()); + ost << "uic failed for\n" + << " " << cmQtAutoGen::Quoted(uiInputFile) << "\n" + << "needed by\n" + << " " << cmQtAutoGen::Quoted(realName); + this->LogCommandError(cmQtAutoGen::UIC, ost.str(), cmd, output); } cmSystemTools::RemoveFile(uicFileAbs); this->UicRunFailed = true; @@ -1669,41 +1598,9 @@ bool cmQtAutoGenerators::RccGenerateAll() return true; } - // generate single map with input / output names - std::map<std::string, std::string> qrcGenMap; - { - const std::string qrcPrefix = "qrc_"; - const std::string qrcSuffix = this->ConfigSuffix + ".cpp"; - for (std::vector<std::string>::const_iterator si = - this->RccSources.begin(); - si != this->RccSources.end(); ++si) { - const std::string ext = - cmsys::SystemTools::GetFilenameLastExtension(*si); - if (ext == ".qrc") { - qrcGenMap[*si] = this->ChecksumedPath(*si, qrcPrefix, qrcSuffix); - } - } - } - - // look for name collisions - { - std::multimap<std::string, std::string> collisions; - if (this->NameCollisionTest(qrcGenMap, collisions)) { - std::ostringstream ost; - ost << "AutoRcc: Error: The same qrc_NAME.cpp file" - " will be generated from different sources.\n" - "To avoid this error rename the source .qrc files.\n"; - this->LogErrorNameCollision(ost.str(), collisions); - return false; - } - } - - // generate qrc files - for (std::map<std::string, std::string>::const_iterator si = - qrcGenMap.begin(); - si != qrcGenMap.end(); ++si) { - bool unique = FileNameIsUnique(si->first, qrcGenMap); - if (!this->RccGenerateFile(si->first, si->second, unique)) { + // Generate qrc files + for (const RccJob& rccJob : this->RccJobs) { + if (!this->RccGenerateFile(rccJob)) { if (this->RccRunFailed) { return false; } @@ -1715,41 +1612,49 @@ bool cmQtAutoGenerators::RccGenerateAll() /** * @return True if a rcc file was created. False may indicate an error. */ -bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, - const std::string& rccOutputFile, - bool unique_n) +bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) { bool rccGenerated = false; bool generateRcc = this->RccSettingsChanged; - const std::string rccBuildFile = - cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, rccOutputFile); + + std::string rccFileAbs; + if (this->ConfigSuffix.empty()) { + rccFileAbs = rccJob.RccFile; + } else { + rccFileAbs = SubDirPrefix(rccJob.RccFile); + rccFileAbs += + cmSystemTools::GetFilenameWithoutLastExtension(rccJob.RccFile); + rccFileAbs += this->ConfigSuffix; + rccFileAbs += cmSystemTools::GetFilenameLastExtension(rccJob.RccFile); + } + const std::string rccFileRel = cmSystemTools::RelativePath( + this->AutogenBuildDir.c_str(), rccFileAbs.c_str()); // Check if regeneration is required if (!generateRcc) { // Test if the resources list file is newer than build file - generateRcc = FileAbsentOrOlder(rccBuildFile, rccInputFile); + generateRcc = FileAbsentOrOlder(rccFileAbs, rccJob.QrcFile); if (!generateRcc) { // Acquire input file list std::vector<std::string> readFiles; - const std::vector<std::string>* files = &this->RccInputs[rccInputFile]; + const std::vector<std::string>* files = &rccJob.Inputs; if (files->empty()) { // Read input file list from qrc file std::string error; - if (cmQtAutoGeneratorCommon::RccListInputs( - this->QtMajorVersion, this->RccExecutable, rccInputFile, - readFiles, &error)) { + if (cmQtAutoGen::RccListInputs(this->QtMajorVersion, + this->RccExecutable, rccJob.QrcFile, + readFiles, &error)) { files = &readFiles; } else { files = nullptr; - this->LogError(error); + this->LogFileError(cmQtAutoGen::RCC, rccJob.QrcFile, error); this->RccRunFailed = true; } } // Test if any input file is newer than the build file if (files != nullptr) { - for (std::vector<std::string>::const_iterator it = files->begin(); - it != files->end(); ++it) { - if (FileAbsentOrOlder(rccBuildFile, *it)) { + for (const std::string& file : *files) { + if (FileAbsentOrOlder(rccFileAbs, file)) { generateRcc = true; break; } @@ -1761,53 +1666,28 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, if (generateRcc) { // Log if (this->Verbose) { - this->LogBold("Generating RCC source " + rccOutputFile); + this->LogBold("Generating RCC source " + rccFileRel); } // Make sure the parent directory exists - if (this->MakeParentDirectory("AutoRcc", rccBuildFile)) { - // Compose symbol name - std::string symbolName = - cmsys::SystemTools::GetFilenameWithoutLastExtension(rccInputFile); - if (!unique_n) { - symbolName += "_"; - symbolName += FPathChecksum.getPart(rccInputFile); - } - // Replace '-' with '_'. The former is valid for - // file names but not for symbol names. - std::replace(symbolName.begin(), symbolName.end(), '-', '_'); - + if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccFileAbs)) { // Compose rcc command std::vector<std::string> cmd; cmd.push_back(this->RccExecutable); - { - std::map<std::string, std::string>::const_iterator optionIt = - this->RccOptions.find(rccInputFile); - if (optionIt != this->RccOptions.end()) { - cmSystemTools::ExpandListArgument(optionIt->second, cmd); - } - } - cmd.push_back("-name"); - cmd.push_back(symbolName); + cmd.insert(cmd.end(), rccJob.Options.begin(), rccJob.Options.end()); cmd.push_back("-o"); - cmd.push_back(rccBuildFile); - cmd.push_back(rccInputFile); + cmd.push_back(rccFileAbs); + cmd.push_back(rccJob.QrcFile); std::string output; if (this->RunCommand(cmd, output)) { // Success rccGenerated = true; } else { - // Command failed - { - std::ostringstream ost; - ost << "AutoRcc: Error: rcc process failed for\n"; - ost << Quoted(rccOutputFile) << "\n"; - ost << "AutoRcc: Command:\n" << QuotedCommand(cmd) << "\n"; - ost << "AutoRcc: Command output:\n" << output << "\n"; - this->LogError(ost.str()); - } - cmSystemTools::RemoveFile(rccBuildFile); + this->LogCommandError(cmQtAutoGen::RCC, "rcc failed for\n " + + cmQtAutoGen::Quoted(rccJob.QrcFile), + cmd, output); + cmSystemTools::RemoveFile(rccFileAbs); this->RccRunFailed = true; } } else { @@ -1818,17 +1698,14 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, // For a multi configuration generator generate a wrapper file if (!this->ConfigSuffix.empty() && !this->RccRunFailed) { // Wrapper file name - const std::string cppSuffix = ".cpp"; - const size_t suffixLength = this->ConfigSuffix.size() + cppSuffix.size(); - const std::string wrapperFileRel = - rccOutputFile.substr(0, rccOutputFile.size() - suffixLength) + cppSuffix; - const std::string wrapperFileAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, wrapperFileRel); + const std::string& wrapperFileAbs = rccJob.RccFile; + const std::string wrapperFileRel = cmSystemTools::RelativePath( + this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str()); // Wrapper file content - std::string content = - "// This is an autogenerated configuration wrapper file. Do not edit.\n" - "#include \""; - content += cmsys::SystemTools::GetFilenameName(rccBuildFile); + std::string content = "// This is an autogenerated configuration " + "wrapper file. Do not edit.\n" + "#include \""; + content += cmSystemTools::GetFilenameName(rccFileRel); content += "\"\n"; // Write content to file if (this->FileDiffers(wrapperFileAbs, content)) { @@ -1836,7 +1713,7 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, if (this->Verbose) { this->LogBold("Generating RCC wrapper " + wrapperFileRel); } - if (!this->FileWrite("AutoRcc", wrapperFileAbs, content)) { + if (!this->FileWrite(cmQtAutoGen::RCC, wrapperFileAbs, content)) { // Error rccGenerated = false; this->RccRunFailed = true; @@ -1844,7 +1721,8 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, } else if (rccGenerated) { // Only touch wrapper file if the content matches if (this->Verbose) { - this->LogInfo("Touching RCC wrapper " + wrapperFileRel); + this->LogInfo(cmQtAutoGen::RCC, + "Touching RCC wrapper " + wrapperFileRel); } cmSystemTools::Touch(wrapperFileAbs, false); } @@ -1853,69 +1731,144 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, return rccGenerated; } -void cmQtAutoGenerators::LogErrorNameCollision( - const std::string& message, - const std::multimap<std::string, std::string>& collisions) const +void cmQtAutoGenerators::LogBold(const std::string& message) const { - typedef std::multimap<std::string, std::string>::const_iterator Iter; + cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | + cmsysTerminal_Color_ForegroundBold, + message.c_str(), true, this->ColorOutput); +} - std::ostringstream ost; - // Add message - if (!message.empty()) { - ost << message; - if (message[message.size() - 1] != '\n') { - ost << '\n'; - } +void cmQtAutoGenerators::LogInfo(cmQtAutoGen::GeneratorType genType, + const std::string& message) const +{ + std::string msg = cmQtAutoGen::GeneratorName(genType); + msg += ": "; + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); } - // Append collision list - for (Iter it = collisions.begin(); it != collisions.end(); ++it) { - ost << it->first << " : " << it->second << '\n'; + cmSystemTools::Stdout(msg.c_str(), msg.size()); +} + +void cmQtAutoGenerators::LogWarning(cmQtAutoGen::GeneratorType genType, + const std::string& message) const +{ + std::string msg = cmQtAutoGen::GeneratorName(genType); + msg += " warning:"; + if (message.find('\n') == std::string::npos) { + // Single line message + msg.push_back(' '); + } else { + // Multi line message + msg.push_back('\n'); + } + // Message + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); } - this->LogError(ost.str()); + msg += "\n"; + cmSystemTools::Stdout(msg.c_str(), msg.size()); } -void cmQtAutoGenerators::LogBold(const std::string& message) const +void cmQtAutoGenerators::LogFileWarning(cmQtAutoGen::GeneratorType genType, + const std::string& filename, + const std::string& message) const { - cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | - cmsysTerminal_Color_ForegroundBold, - message.c_str(), true, this->ColorOutput); + std::string emsg = " "; + emsg += cmQtAutoGen::Quoted(filename); + emsg += "\n"; + // Message + emsg += message; + this->LogWarning(genType, emsg); } -void cmQtAutoGenerators::LogInfo(const std::string& message) const +void cmQtAutoGenerators::LogError(cmQtAutoGen::GeneratorType genType, + const std::string& message) const { - std::string msg(message); - if (!msg.empty()) { - if (msg[msg.size() - 1] != '\n') { - msg.push_back('\n'); - } - cmSystemTools::Stdout(msg.c_str(), msg.size()); + std::string msg; + msg.push_back('\n'); + msg = cmQtAutoGen::GeneratorName(genType); + msg += " error:"; + if (message.find('\n') == std::string::npos) { + // Single line message + msg.push_back(' '); + } else { + // Multi line message + msg.push_back('\n'); + } + // Message + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); } + msg += "\n"; + cmSystemTools::Stderr(msg.c_str(), msg.size()); } -void cmQtAutoGenerators::LogWarning(const std::string& message) const +void cmQtAutoGenerators::LogFileError(cmQtAutoGen::GeneratorType genType, + const std::string& filename, + const std::string& message) const { - std::string msg(message); - if (!msg.empty()) { - if (msg[msg.size() - 1] != '\n') { - msg.push_back('\n'); + std::string emsg = " "; + emsg += cmQtAutoGen::Quoted(filename); + emsg += "\n"; + // Message + emsg += message; + this->LogError(genType, emsg); +} + +void cmQtAutoGenerators::LogNameCollisionError( + cmQtAutoGen::GeneratorType genType, const std::string& message, + const std::multimap<std::string, std::string>& collisions) const +{ + std::string emsg; + // Add message + if (!message.empty()) { + emsg += message; + if (emsg.back() != '\n') { + emsg.push_back('\n'); } - // Append empty line - msg.push_back('\n'); - cmSystemTools::Stdout(msg.c_str(), msg.size()); } + // Append collision list + for (const auto& item : collisions) { + emsg += " "; + emsg += item.first; + emsg += " -> "; + emsg += item.second; + emsg += "\n"; + } + this->LogError(genType, emsg); } -void cmQtAutoGenerators::LogError(const std::string& message) const +void cmQtAutoGenerators::LogCommandError( + cmQtAutoGen::GeneratorType genType, const std::string& message, + const std::vector<std::string>& command, const std::string& output) const { - std::string msg(message); - if (!msg.empty()) { - if (msg[msg.size() - 1] != '\n') { - msg.push_back('\n'); - } - // Append empty line + std::string msg; + msg.push_back('\n'); + msg += cmQtAutoGen::GeneratorName(genType); + msg += " subprocess error: "; + msg += message; + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + msg += "Command\n"; + msg += "-------\n"; + msg += QuotedCommand(command); + if (msg.back() != '\n') { + msg.push_back('\n'); + } + msg.push_back('\n'); + msg += "Output\n"; + msg += "------\n"; + msg += output; + if (msg.back() != '\n') { msg.push_back('\n'); - cmSystemTools::Stderr(msg.c_str(), msg.size()); } + msg += "\n"; + cmSystemTools::Stderr(msg.c_str(), msg.size()); } /** @@ -1959,7 +1912,7 @@ std::string cmQtAutoGenerators::ChecksumedPath( std::string res = FPathChecksum.getPart(sourceFile); res += "/"; res += basePrefix; - res += cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFile); + res += cmSystemTools::GetFilenameWithoutLastExtension(sourceFile); res += baseSuffix; return res; } @@ -1968,18 +1921,16 @@ std::string cmQtAutoGenerators::ChecksumedPath( * @brief Generates the parent directory of the given file on demand * @return True on success */ -bool cmQtAutoGenerators::MakeParentDirectory(const char* logPrefix, - const std::string& filename) const +bool cmQtAutoGenerators::MakeParentDirectory( + cmQtAutoGen::GeneratorType genType, const std::string& filename) const { bool success = true; const std::string dirName = cmSystemTools::GetFilenamePath(filename); if (!dirName.empty()) { - success = cmsys::SystemTools::MakeDirectory(dirName); + success = cmSystemTools::MakeDirectory(dirName); if (!success) { - std::string error = logPrefix; - error += ": Error: Parent directory creation failed for "; - error += Quoted(filename); - this->LogError(error); + this->LogFileError(genType, filename, + "Could not create parent directory"); } } return success; @@ -1998,31 +1949,27 @@ bool cmQtAutoGenerators::FileDiffers(const std::string& filename, return differs; } -bool cmQtAutoGenerators::FileWrite(const char* logPrefix, +bool cmQtAutoGenerators::FileWrite(cmQtAutoGen::GeneratorType genType, const std::string& filename, const std::string& content) { std::string error; // Make sure the parent directory exists - if (this->MakeParentDirectory(logPrefix, filename)) { + if (this->MakeParentDirectory(genType, filename)) { cmsys::ofstream outfile; outfile.open(filename.c_str(), std::ios::trunc); if (outfile) { outfile << content; // Check for write errors if (!outfile.good()) { - error = logPrefix; - error += ": Error writing "; - error += Quoted(filename); + error = "File writing failed"; } } else { - error = logPrefix; - error = ": Error opening "; - error += Quoted(filename); + error = "Opening file for writing failed"; } } if (!error.empty()) { - this->LogError(error); + this->LogFileError(genType, filename, error); return false; } return true; @@ -2033,17 +1980,18 @@ bool cmQtAutoGenerators::FileWrite(const char* logPrefix, * @return True on success */ bool cmQtAutoGenerators::RunCommand(const std::vector<std::string>& command, - std::string& output, bool verbose) const + std::string& output) const { // Log command if (this->Verbose) { - this->LogInfo(QuotedCommand(command)); + std::string qcmd = QuotedCommand(command); + qcmd.push_back('\n'); + cmSystemTools::Stdout(qcmd.c_str(), qcmd.size()); } // Execute command int retVal = 0; bool res = cmSystemTools::RunSingleCommand( - command, &output, &output, &retVal, nullptr, - verbose ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE); + command, &output, &output, &retVal, nullptr, cmSystemTools::OUTPUT_NONE); return (res && (retVal == 0)); } @@ -2055,13 +2003,11 @@ bool cmQtAutoGenerators::RunCommand(const std::vector<std::string>& command, bool cmQtAutoGenerators::FindHeader(std::string& header, const std::string& testBasePath) const { - for (std::vector<std::string>::const_iterator ext = - this->HeaderExtensions.begin(); - ext != this->HeaderExtensions.end(); ++ext) { + for (const std::string& ext : this->HeaderExtensions) { std::string testFilePath(testBasePath); - testFilePath += '.'; - testFilePath += (*ext); - if (cmsys::SystemTools::FileExists(testFilePath.c_str())) { + testFilePath.push_back('.'); + testFilePath += ext; + if (cmSystemTools::FileExists(testFilePath.c_str())) { header = testFilePath; return true; } @@ -2076,10 +2022,10 @@ std::string cmQtAutoGenerators::MocFindHeader( // Search in vicinity of the source if (!this->FindHeader(header, sourcePath + includeBase)) { // Search in include directories - for (std::vector<std::string>::const_iterator iit = - this->MocIncludePaths.begin(); - iit != this->MocIncludePaths.end(); ++iit) { - const std::string fullPath = ((*iit) + '/' + includeBase); + for (const std::string& path : this->MocIncludePaths) { + std::string fullPath = path; + fullPath.push_back('/'); + fullPath += includeBase; if (FindHeader(header, fullPath)) { break; } @@ -2087,7 +2033,7 @@ std::string cmQtAutoGenerators::MocFindHeader( } // Sanitize if (!header.empty()) { - header = cmsys::SystemTools::GetRealPath(header); + header = cmSystemTools::GetRealPath(header); } return header; } @@ -2101,19 +2047,19 @@ bool cmQtAutoGenerators::MocFindIncludedFile( { std::string testPath = sourcePath; testPath += includeString; - if (cmsys::SystemTools::FileExists(testPath.c_str())) { - absFile = cmsys::SystemTools::GetRealPath(testPath); + if (cmSystemTools::FileExists(testPath.c_str())) { + absFile = cmSystemTools::GetRealPath(testPath); success = true; } } // Search in include directories if (!success) { - for (std::vector<std::string>::const_iterator iit = - this->MocIncludePaths.begin(); - iit != this->MocIncludePaths.end(); ++iit) { - const std::string fullPath = ((*iit) + '/' + includeString); - if (cmsys::SystemTools::FileExists(fullPath.c_str())) { - absFile = cmsys::SystemTools::GetRealPath(fullPath); + for (const std::string& path : this->MocIncludePaths) { + std::string fullPath = path; + fullPath.push_back('/'); + fullPath += includeString; + if (cmSystemTools::FileExists(fullPath.c_str())) { + absFile = cmSystemTools::GetRealPath(fullPath); success = true; break; } diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 5cb3d9f..5d3ad74 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -6,18 +6,19 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmFilePathChecksum.h" +#include "cmQtAutoGen.h" #include "cmsys/RegularExpression.hxx" #include <map> #include <set> #include <string> -#include <utility> #include <vector> class cmMakefile; class cmQtAutoGenerators { + CM_DISABLE_COPY(cmQtAutoGenerators) public: cmQtAutoGenerators(); bool Run(const std::string& targetDirectory, const std::string& config); @@ -25,13 +26,35 @@ public: private: // -- Types - /// @brief Used to extract additional dependencies from content text - struct MocDependFilter + /// @brief Search key plus regular expression pair + struct KeyRegExp { - std::string key; - cmsys::RegularExpression regExp; + KeyRegExp() = default; + + KeyRegExp(const char* key, const char* regExp) + : Key(key) + , RegExp(regExp) + { + } + + KeyRegExp(const std::string& key, const std::string& regExp) + : Key(key) + , RegExp(regExp) + { + } + + std::string Key; + cmsys::RegularExpression RegExp; + }; + + /// @brief RCC job + struct RccJob + { + std::string QrcFile; + std::string RccFile; + std::vector<std::string> Options; + std::vector<std::string> Inputs; }; - typedef std::pair<std::string, cmsys::RegularExpression> MocMacroFilter; // -- Configuration bool MocDependFilterPush(const std::string& key, const std::string& regExp); @@ -90,6 +113,9 @@ private: const std::string& fileName, const std::string& contentText, std::map<std::string, std::vector<std::string>>& includedUis); + std::string MocMacroNamesString() const; + std::string MocHeaderSuffixesString() const; + bool MocParseSourceContent( const std::string& absFilename, const std::string& contentText, std::map<std::string, std::string>& mocsIncluded, @@ -122,18 +148,31 @@ private: // -- Rcc file generation bool RccGenerateAll(); - bool RccGenerateFile(const std::string& qrcInputFile, - const std::string& qrcOutputFile, bool unique_n); + bool RccGenerateFile(const RccJob& rccJob); - // -- Logging - void LogErrorNameCollision( - const std::string& message, - const std::multimap<std::string, std::string>& collisions) const; + // -- Log info void LogBold(const std::string& message) const; - void LogInfo(const std::string& message) const; - void LogWarning(const std::string& message) const; - void LogError(const std::string& message) const; - void LogCommand(const std::vector<std::string>& command) const; + void LogInfo(cmQtAutoGen::GeneratorType genType, + const std::string& message) const; + // -- Log warning + void LogWarning(cmQtAutoGen::GeneratorType genType, + const std::string& message) const; + void LogFileWarning(cmQtAutoGen::GeneratorType genType, + const std::string& filename, + const std::string& message) const; + // -- Log error + void LogError(cmQtAutoGen::GeneratorType genType, + const std::string& message) const; + void LogFileError(cmQtAutoGen::GeneratorType genType, + const std::string& filename, + const std::string& message) const; + void LogCommandError(cmQtAutoGen::GeneratorType genType, + const std::string& message, + const std::vector<std::string>& command, + const std::string& output) const; + void LogNameCollisionError( + cmQtAutoGen::GeneratorType genType, const std::string& message, + const std::multimap<std::string, std::string>& collisions) const; // -- Utility bool NameCollisionTest( @@ -142,14 +181,14 @@ private: std::string ChecksumedPath(const std::string& sourceFile, const std::string& basePrefix, const std::string& baseSuffix) const; - bool MakeParentDirectory(const char* logPrefix, + bool MakeParentDirectory(cmQtAutoGen::GeneratorType genType, const std::string& filename) const; bool FileDiffers(const std::string& filename, const std::string& content); - bool FileWrite(const char* logPrefix, const std::string& filename, - const std::string& content); + bool FileWrite(cmQtAutoGen::GeneratorType genType, + const std::string& filename, const std::string& content); - bool RunCommand(const std::vector<std::string>& command, std::string& output, - bool verbose = true) const; + bool RunCommand(const std::vector<std::string>& command, + std::string& output) const; bool FindHeader(std::string& header, const std::string& testBasePath) const; @@ -169,6 +208,7 @@ private: std::string AutogenIncludeDir; // -- Qt environment std::string QtMajorVersion; + std::string QtMinorVersion; std::string MocExecutable; std::string UicExecutable; std::string RccExecutable; @@ -200,23 +240,21 @@ private: std::vector<std::string> MocDefinitions; std::vector<std::string> MocOptions; std::vector<std::string> MocPredefsCmd; - std::vector<MocDependFilter> MocDependFilters; - std::vector<MocMacroFilter> MocMacroFilters; + std::vector<KeyRegExp> MocDependFilters; + std::vector<KeyRegExp> MocMacroFilters; cmsys::RegularExpression MocRegExpInclude; // -- Uic bool UicSettingsChanged; bool UicRunFailed; std::vector<std::string> UicSkipList; std::vector<std::string> UicTargetOptions; - std::map<std::string, std::string> UicOptions; + std::map<std::string, std::vector<std::string>> UicOptions; std::vector<std::string> UicSearchPaths; cmsys::RegularExpression UicRegExpInclude; // -- Rcc bool RccSettingsChanged; bool RccRunFailed; - std::vector<std::string> RccSources; - std::map<std::string, std::string> RccOptions; - std::map<std::string, std::vector<std::string>> RccInputs; + std::vector<RccJob> RccJobs; }; #endif |