From 9045f6a30fc8ce21d2b2298c27ba1da41c23bbf3 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Wed, 28 Nov 2018 15:07:31 +0100 Subject: Autogen: Prepare for Qt 6 Handle Qt version > 5 in Qt AutoGen. This patch does *NOT* include tests and documentation: There is no Qt 6 yet. I still need this patch to work on a cmake based build system for Qt 6. --- Source/cmQtAutoGenGlobalInitializer.cxx | 3 ++- Source/cmQtAutoGenInitializer.cxx | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx index 5470ec3..0ed8af4 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -77,7 +77,8 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( if (moc || uic || rcc) { // We support Qt4 and Qt5 auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target); - if ((qtVersion.Major == 4) || (qtVersion.Major == 5)) { + if ((qtVersion.Major == 4) || (qtVersion.Major == 5) || + (qtVersion.Major == 6)) { // Create autogen target initializer Initializers_.emplace_back(cm::make_unique( this, target, qtVersion, moc, uic, rcc, globalAutoGenTarget, diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 6a2a951..ffa6a35 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -42,6 +42,9 @@ std::string GetQtExecutableTargetName( const cmQtAutoGen::IntegerVersion& qtVersion, std::string const& executable) { + if (qtVersion.Major == 6) { + return ("Qt6::" + executable); + } if (qtVersion.Major == 5) { return ("Qt5::" + executable); } @@ -504,7 +507,7 @@ bool cmQtAutoGenInitializer::InitMoc() { // We need to disable this until we have all implicit includes available. // See issue #18669. - // bool const appendImplicit = (this->QtVersion.Major == 5); + // bool const appendImplicit = (this->QtVersion.Major >= 5); auto GetIncludeDirs = [this, localGen](std::string const& cfg) -> std::vector { @@ -839,7 +842,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() // Process qrc files if (!this->Rcc.Qrcs.empty()) { - const bool QtV5 = (this->QtVersion.Major == 5); + const bool modernQt = (this->QtVersion.Major >= 5); // Target rcc options std::vector optionsTarget; cmSystemTools::ExpandListArgument( @@ -911,10 +914,10 @@ bool cmQtAutoGenInitializer::InitScanFiles() std::vector nameOpts; nameOpts.emplace_back("-name"); nameOpts.emplace_back(std::move(name)); - RccMergeOptions(opts, nameOpts, QtV5); + RccMergeOptions(opts, nameOpts, modernQt); } // Merge file option - RccMergeOptions(opts, qrc.Options, QtV5); + RccMergeOptions(opts, qrc.Options, modernQt); qrc.Options = std::move(opts); } // RCC resources @@ -1374,7 +1377,7 @@ static std::vector GetKnownQtVersions( std::vector result; for (const std::string& prefix : - std::vector({ "Qt5Core", "QT" })) { + std::vector({ "Qt6Core", "Qt5Core", "QT" })) { auto tmp = cmQtAutoGenInitializer::IntegerVersion( StringToInt(makefile->GetSafeDefinition(prefix + "_VERSION_MAJOR")), StringToInt(makefile->GetSafeDefinition(prefix + "_VERSION_MINOR"))); @@ -1427,7 +1430,7 @@ std::pair GetQtExecutable( GetQtExecutableTargetName(qtVersion, executable); if (targetName.empty()) { err = "The AUTOMOC, AUTOUIC and AUTORCC feature "; - err += "supports only Qt 4 and Qt 5"; + err += "supports only Qt 4, Qt 5 and Qt 6."; } else { cmLocalGenerator* localGen = target->GetLocalGenerator(); cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName); @@ -1510,7 +1513,7 @@ bool cmQtAutoGenInitializer::GetRccExecutable() return false; } - if (this->QtVersion.Major == 5) { + if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) { if (stdOut.find("--list") != std::string::npos) { this->Rcc.ListOptions.push_back("--list"); } else { -- cgit v0.12 From cd32886b2f5c8f6bdcc9185274a934102c821a20 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Wed, 28 Nov 2018 16:00:50 +0100 Subject: Autogen: Add AUTO(MOC|RCC|UIC)_EXECUTABLE target properties Allow to force moc/rcc/uic compiler used for AUTO(MOC|RCC|UIC). Setting these properties is only necessary if you are going to do strange things like build these tools as part of your own build system. Setting these properties will also prevent cmake from testing the binary: It is user-provided and assumed to be valid. --- Help/manual/cmake-properties.7.rst | 3 ++ Help/prop_tgt/AUTOMOC.rst | 3 ++ Help/prop_tgt/AUTOMOC_EXECUTABLE.rst | 15 ++++++++ Help/prop_tgt/AUTORCC.rst | 3 ++ Help/prop_tgt/AUTORCC_EXECUTABLE.rst | 15 ++++++++ Help/prop_tgt/AUTOUIC.rst | 3 ++ Help/prop_tgt/AUTOUIC_EXECUTABLE.rst | 15 ++++++++ Help/release/dev/autogen_executables.rst | 9 +++++ Source/cmQtAutoGenGlobalInitializer.cxx | 22 +++++++++--- Source/cmQtAutoGenInitializer.cxx | 61 +++++++++++++++++++++++++------- 10 files changed, 131 insertions(+), 18 deletions(-) create mode 100644 Help/prop_tgt/AUTOMOC_EXECUTABLE.rst create mode 100644 Help/prop_tgt/AUTORCC_EXECUTABLE.rst create mode 100644 Help/prop_tgt/AUTOUIC_EXECUTABLE.rst create mode 100644 Help/release/dev/autogen_executables.rst diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 047859d..df8f12c 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -129,13 +129,16 @@ Properties on Targets /prop_tgt/AUTOGEN_TARGET_DEPENDS /prop_tgt/AUTOMOC_COMPILER_PREDEFINES /prop_tgt/AUTOMOC_DEPEND_FILTERS + /prop_tgt/AUTOMOC_EXECUTABLE /prop_tgt/AUTOMOC_MACRO_NAMES /prop_tgt/AUTOMOC_MOC_OPTIONS /prop_tgt/AUTOMOC /prop_tgt/AUTOUIC + /prop_tgt/AUTOUIC_EXECUTABLE /prop_tgt/AUTOUIC_OPTIONS /prop_tgt/AUTOUIC_SEARCH_PATHS /prop_tgt/AUTORCC + /prop_tgt/AUTORCC_EXECUTABLE /prop_tgt/AUTORCC_OPTIONS /prop_tgt/BINARY_DIR /prop_tgt/BUILD_RPATH diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst index 7a3fd48..3e6d560 100644 --- a/Help/prop_tgt/AUTOMOC.rst +++ b/Help/prop_tgt/AUTOMOC.rst @@ -58,6 +58,9 @@ source files at build time and invoke moc accordingly. This property is initialized by the value of the :variable:`CMAKE_AUTOMOC` variable if it is set when a target is created. +The ``moc`` executable will be detected automatically, but can be forced to +a certain binary using the :prop_tgt:`AUTOMOC_EXECUTABLE` property. + Additional command line options for ``moc`` can be set via the :prop_tgt:`AUTOMOC_MOC_OPTIONS` property. diff --git a/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst b/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst new file mode 100644 index 0000000..6b66ce8 --- /dev/null +++ b/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst @@ -0,0 +1,15 @@ +AUTOMOC_EXECUTABLE +------------------ + +:prop_tgt:`AUTOMOC_EXECUTABLE` is file path pointing to the ``moc`` +executable to use for :prop_tgt:`AUTOMOC` enabled files. Setting +this property will make CMake skip the automatic detection of the +``moc`` binary as well as the sanity-tests normally run to ensure +that the binary is available and working as expected. + +Usually this property does not need to be set. Only consider this +property if auto-detection of ``moc`` can not work -- e.g. because +you are building the ``moc`` binary as part of your project. + +See the :manual:`cmake-qt(7)` manual for more information on using CMake +with Qt. diff --git a/Help/prop_tgt/AUTORCC.rst b/Help/prop_tgt/AUTORCC.rst index 27fb149..5db6ed0 100644 --- a/Help/prop_tgt/AUTORCC.rst +++ b/Help/prop_tgt/AUTORCC.rst @@ -21,6 +21,9 @@ If the ``.qrc`` file is :prop_sf:`GENERATED` though, a Additional command line options for rcc can be set via the :prop_sf:`AUTORCC_OPTIONS` source file property on the ``.qrc`` file. +The ``rcc`` executable will be detected automatically, but can be forced to +a certain binary using the :prop_tgt:`AUTORCC_EXECUTABLE` property. + The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the autorcc targets together in an IDE, e.g. in MSVS. diff --git a/Help/prop_tgt/AUTORCC_EXECUTABLE.rst b/Help/prop_tgt/AUTORCC_EXECUTABLE.rst new file mode 100644 index 0000000..ca0fbd7 --- /dev/null +++ b/Help/prop_tgt/AUTORCC_EXECUTABLE.rst @@ -0,0 +1,15 @@ +AUTORCC_EXECUTABLE +------------------ + +:prop_tgt:`AUTORCC_EXECUTABLE` is file path pointing to the ``rcc`` +executable to use for :prop_tgt:`AUTORCC` enabled files. Setting +this property will make CMake skip the automatic detection of the +``rcc`` binary as well as the sanity-tests normally run to ensure +that the binary is available and working as expected. + +Usually this property does not need to be set. Only consider this +property if auto-detection of ``rcc`` can not work -- e.g. because +you are building the ``rcc`` binary as part of your project. + +See the :manual:`cmake-qt(7)` manual for more information on using CMake +with Qt. diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst index 4f58b35..85226c1 100644 --- a/Help/prop_tgt/AUTOUIC.rst +++ b/Help/prop_tgt/AUTOUIC.rst @@ -30,6 +30,9 @@ Additional command line options for ``uic`` can be set via the The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the autouic targets together in an IDE, e.g. in MSVS. +The ``uic`` executable will be detected automatically, but can be forced to +a certain binary using the :prop_tgt:`AUTOUIC_EXECUTABLE` property. + Source files can be excluded from :prop_tgt:`AUTOUIC` processing by enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`. diff --git a/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst b/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst new file mode 100644 index 0000000..03bd554 --- /dev/null +++ b/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst @@ -0,0 +1,15 @@ +AUTOUIC_EXECUTABLE +------------------ + +:prop_tgt:`AUTOUIC_EXECUTABLE` is file path pointing to the ``uic`` +executable to use for :prop_tgt:`AUTOUIC` enabled files. Setting +this property will make CMake skip the automatic detection of the +``uic`` binary as well as the sanity-tests normally run to ensure +that the binary is available and working as expected. + +Usually this property does not need to be set. Only consider this +property if auto-detection of ``uic`` can not work -- e.g. because +you are building the ``uic`` binary as part of your project. + +See the :manual:`cmake-qt(7)` manual for more information on using CMake +with Qt. diff --git a/Help/release/dev/autogen_executables.rst b/Help/release/dev/autogen_executables.rst new file mode 100644 index 0000000..5e967ea --- /dev/null +++ b/Help/release/dev/autogen_executables.rst @@ -0,0 +1,9 @@ +AUTO*_EXECUTABLE +---------------- + +* The :prop_tgt:`AUTOMOC_EXECUTABLE`, :prop_tgt:`AUTORCC_EXECUTABLE` and + :prop_tgt:`AUTOUIC_EXECUTABLE` target properties all take a path to an + executable and force automoc/autorcc/autouic to use this executable. + + Setting these will also prevent the configure time testing for these + executables. This is mainly useful when you build these tools yourself. diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx index 0ed8af4..678ff14 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -75,14 +75,26 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( bool const uic = target->GetPropertyAsBool("AUTOUIC"); bool const rcc = target->GetPropertyAsBool("AUTORCC"); if (moc || uic || rcc) { - // We support Qt4 and Qt5 + std::string const mocExec = + target->GetSafeProperty("AUTOMOC_EXECUTABLE"); + std::string const uicExec = + target->GetSafeProperty("AUTOUIC_EXECUTABLE"); + std::string const rccExec = + target->GetSafeProperty("AUTORCC_EXECUTABLE"); + + // We support Qt4, Qt5 and Qt6 auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target); - if ((qtVersion.Major == 4) || (qtVersion.Major == 5) || - (qtVersion.Major == 6)) { + bool const validQt = (qtVersion.Major == 4) || + (qtVersion.Major == 5) || (qtVersion.Major == 6); + bool const mocIsValid = moc && (validQt || !mocExec.empty()); + bool const uicIsValid = uic && (validQt || !uicExec.empty()); + bool const rccIsValid = rcc && (validQt || !rccExec.empty()); + + if (mocIsValid || uicIsValid || rccIsValid) { // Create autogen target initializer Initializers_.emplace_back(cm::make_unique( - this, target, qtVersion, moc, uic, rcc, globalAutoGenTarget, - globalAutoRccTarget)); + this, target, qtVersion, mocIsValid, uicIsValid, rccIsValid, + globalAutoGenTarget, globalAutoRccTarget)); } } } diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index ffa6a35..e4d2c82 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -9,6 +9,7 @@ #include "cmCustomCommandLines.h" #include "cmDuration.h" #include "cmFilePathChecksum.h" +#include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLinkItem.h" @@ -398,8 +399,16 @@ bool cmQtAutoGenInitializer::InitCustomTargets() } // Init uic specific settings - if (this->Uic.Enabled && !InitUic()) { - return false; + if (this->Uic.Enabled) { + if (InitUic()) { + auto* uicTarget = makefile->FindTargetToUse( + GetQtExecutableTargetName(this->QtVersion, "uic")); + if (uicTarget != nullptr) { + this->AutogenTarget.DependTargets.insert(uicTarget); + } + } else { + return false; + } } // Autogen target name @@ -440,6 +449,12 @@ bool cmQtAutoGenInitializer::InitCustomTargets() this->AutogenTarget.DependOrigin = this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS"); + auto* mocTarget = makefile->FindTargetToUse( + GetQtExecutableTargetName(this->QtVersion, "moc")); + if (mocTarget != nullptr) { + this->AutogenTarget.DependTargets.insert(mocTarget); + } + std::string const deps = this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS"); if (!deps.empty()) { @@ -1095,6 +1110,7 @@ bool cmQtAutoGenInitializer::InitRccTargets() { cmMakefile* makefile = this->Target->Target->GetMakefile(); cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + auto rccTargetName = GetQtExecutableTargetName(this->QtVersion, "rcc"); for (Qrc const& qrc : this->Rcc.Qrcs) { // Register info file as generated by CMake @@ -1105,6 +1121,11 @@ bool cmQtAutoGenInitializer::InitRccTargets() std::vector ccOutput; ccOutput.push_back(qrc.RccFile); + std::vector ccDepends; + // Add the .qrc and info file to the custom command dependencies + ccDepends.push_back(qrc.QrcFile); + ccDepends.push_back(qrc.InfoFile); + cmCustomCommandLines commandLines; if (this->MultiConfig) { // Build for all configurations @@ -1140,15 +1161,12 @@ bool cmQtAutoGenInitializer::InitRccTargets() ccName += "_"; ccName += qrc.PathChecksum; } - std::vector ccDepends; - // Add the .qrc and info file to the custom target dependencies - ccDepends.push_back(qrc.QrcFile); - ccDepends.push_back(qrc.InfoFile); cmTarget* autoRccTarget = makefile->AddUtilityCommand( ccName, cmMakefile::TargetOrigin::Generator, true, this->Dir.Work.c_str(), ccOutput, ccDepends, commandLines, false, ccComment.c_str()); + // Create autogen generator target localGen->AddGeneratorTarget( new cmGeneratorTarget(autoRccTarget, localGen)); @@ -1157,6 +1175,9 @@ bool cmQtAutoGenInitializer::InitRccTargets() if (!this->TargetsFolder.empty()) { autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str()); } + if (!rccTargetName.empty()) { + autoRccTarget->AddUtility(rccTargetName, makefile); + } } // Add autogen target to the origin target dependencies this->Target->Target->AddUtility(ccName, makefile); @@ -1169,16 +1190,15 @@ bool cmQtAutoGenInitializer::InitRccTargets() // Create custom rcc command { std::vector ccByproducts; - std::vector ccDepends; - // Add the .qrc and info file to the custom command dependencies - ccDepends.push_back(qrc.QrcFile); - ccDepends.push_back(qrc.InfoFile); // Add the resource files to the dependencies for (std::string const& fileName : qrc.Resources) { // Add resource file to the custom command dependencies ccDepends.push_back(fileName); } + if (!rccTargetName.empty()) { + ccDepends.push_back(rccTargetName); + } makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends, /*main_dependency*/ std::string(), commandLines, ccComment.c_str(), @@ -1421,21 +1441,36 @@ std::pair GetQtExecutable( const cmQtAutoGen::IntegerVersion& qtVersion, cmGeneratorTarget* target, const std::string& executable, bool ignoreMissingTarget, std::string* output) { + const std::string upperExecutable = cmSystemTools::UpperCase(executable); + std::string result = + target->Target->GetSafeProperty("AUTO" + upperExecutable + "_EXECUTABLE"); + if (!result.empty()) { + cmListFileBacktrace lfbt = target->Target->GetMakefile()->GetBacktrace(); + cmGeneratorExpression ge(lfbt); + std::unique_ptr cge = ge.Parse(result); + result = cge->Evaluate(target->GetLocalGenerator(), ""); + + return std::make_pair(true, result); + } + std::string err; - std::string result; // Find executable { const std::string targetName = GetQtExecutableTargetName(qtVersion, executable); if (targetName.empty()) { - err = "The AUTOMOC, AUTOUIC and AUTORCC feature "; + err = "The AUTO" + upperExecutable + " feature "; err += "supports only Qt 4, Qt 5 and Qt 6."; } else { cmLocalGenerator* localGen = target->GetLocalGenerator(); cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName); if (tgt != nullptr) { - result = tgt->ImportedGetLocation(""); + if (tgt->IsImported()) { + result = tgt->ImportedGetLocation(""); + } else { + result = tgt->GetLocation(""); + } } else { if (ignoreMissingTarget) { return std::make_pair(true, ""); -- cgit v0.12