AutoGen: Retrieve Qt version from moc as fallback
Consider the case where the find_package call for QtCore is wrapped in a function call. Then AutoGen cannot determine the Qt version, because it only looks at variables and directory properties. The former don't leave the function scope and the latter are not set by default. As a fallback, locate the moc executable via its target and call it with the --version argument to determine the Qt version. Issue: #22028
This commit is contained in:
parent
63ffe21036
commit
5b0ea5874a
@ -114,7 +114,8 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
|
||||
target->GetSafeProperty(this->kw().AUTORCC_EXECUTABLE);
|
||||
|
||||
// We support Qt4, Qt5 and Qt6
|
||||
auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target.get());
|
||||
auto qtVersion =
|
||||
cmQtAutoGenInitializer::GetQtVersion(target.get(), mocExec);
|
||||
bool const validQt = (qtVersion.first.Major == 4) ||
|
||||
(qtVersion.first.Major == 5) || (qtVersion.first.Major == 6);
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
#include <deque>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <sstream> // for basic_ios, istringstream
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
@ -1833,8 +1833,63 @@ void cmQtAutoGenInitializer::ConfigFileClean(ConfigString& configString)
|
||||
}
|
||||
}
|
||||
|
||||
static cmQtAutoGen::IntegerVersion parseMocVersion(std::string str)
|
||||
{
|
||||
cmQtAutoGen::IntegerVersion result;
|
||||
|
||||
static const std::string prelude = "moc ";
|
||||
size_t pos = str.find(prelude);
|
||||
if (pos == std::string::npos) {
|
||||
return result;
|
||||
}
|
||||
|
||||
str.erase(0, prelude.size() + pos);
|
||||
std::istringstream iss(str);
|
||||
std::string major;
|
||||
std::string minor;
|
||||
if (!std::getline(iss, major, '.') || !std::getline(iss, minor, '.')) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Major = static_cast<unsigned int>(std::stoi(major));
|
||||
result.Minor = static_cast<unsigned int>(std::stoi(minor));
|
||||
return result;
|
||||
}
|
||||
|
||||
static cmQtAutoGen::IntegerVersion GetMocVersion(
|
||||
const std::string& mocExecutablePath)
|
||||
{
|
||||
std::string capturedStdOut;
|
||||
int exitCode;
|
||||
if (!cmSystemTools::RunSingleCommand({ mocExecutablePath, "--version" },
|
||||
&capturedStdOut, nullptr, &exitCode,
|
||||
nullptr, cmSystemTools::OUTPUT_NONE)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (exitCode != 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return parseMocVersion(capturedStdOut);
|
||||
}
|
||||
|
||||
static std::string FindMocExecutableFromMocTarget(cmMakefile* makefile,
|
||||
unsigned int qtMajorVersion)
|
||||
{
|
||||
std::string result;
|
||||
const std::string mocTargetName =
|
||||
"Qt" + std::to_string(qtMajorVersion) + "::moc";
|
||||
cmTarget* mocTarget = makefile->FindTargetToUse(mocTargetName);
|
||||
if (mocTarget) {
|
||||
result = mocTarget->GetSafeProperty("IMPORTED_LOCATION");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<cmQtAutoGen::IntegerVersion, unsigned int>
|
||||
cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target)
|
||||
cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target,
|
||||
std::string mocExecutable)
|
||||
{
|
||||
// Converts a char ptr to an unsigned int value
|
||||
auto toUInt = [](const char* const input) -> unsigned int {
|
||||
@ -1909,6 +1964,21 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res.first.Major == 0) {
|
||||
// We could not get the version number from variables or directory
|
||||
// properties. This might happen if the find_package call for Qt is wrapped
|
||||
// in a function. Try to find the moc executable path from the available
|
||||
// targets and call "moc --version" to get the Qt version.
|
||||
if (mocExecutable.empty()) {
|
||||
mocExecutable =
|
||||
FindMocExecutableFromMocTarget(target->Makefile, res.second);
|
||||
}
|
||||
if (!mocExecutable.empty()) {
|
||||
res.first = GetMocVersion(mocExecutable);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -98,9 +98,11 @@ public:
|
||||
, GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen)){};
|
||||
};
|
||||
|
||||
/** @return The detected Qt version and the required Qt major version. */
|
||||
/** @param mocExecutable The file path to the moc executable. Will be used as
|
||||
fallback to query the version
|
||||
@return The detected Qt version and the required Qt major version. */
|
||||
static std::pair<IntegerVersion, unsigned int> GetQtVersion(
|
||||
cmGeneratorTarget const* genTarget);
|
||||
cmGeneratorTarget const* genTarget, std::string mocExecutable);
|
||||
|
||||
cmQtAutoGenInitializer(cmQtAutoGenGlobalInitializer* globalInitializer,
|
||||
cmGeneratorTarget* genTarget,
|
||||
|
@ -49,6 +49,7 @@ if(QT_TEST_VERSION GREATER 4)
|
||||
ADD_AUTOGEN_TEST(MocMacroName mocMacroName)
|
||||
ADD_AUTOGEN_TEST(MocOsMacros)
|
||||
ADD_AUTOGEN_TEST(RerunMocPlugin)
|
||||
ADD_AUTOGEN_TEST(WrappedFindPackage)
|
||||
if(APPLE)
|
||||
ADD_AUTOGEN_TEST(MacOsFW)
|
||||
endif()
|
||||
|
16
Tests/QtAutogen/WrappedFindPackage/CMakeLists.txt
Normal file
16
Tests/QtAutogen/WrappedFindPackage/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(WrappedFindPackage)
|
||||
|
||||
# Wrap the find_package call in a function.
|
||||
# Test whether AutoMoc can retrieve the Qt version from the moc executable.
|
||||
function(find_qt_package)
|
||||
include("../AutogenCoreTest.cmake")
|
||||
set(QT_LIBRARIES "${QT_LIBRARIES}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
find_qt_package()
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
add_executable(wrappedFindPackage main.cpp)
|
||||
target_link_libraries(wrappedFindPackage PRIVATE ${QT_LIBRARIES})
|
19
Tests/QtAutogen/WrappedFindPackage/main.cpp
Normal file
19
Tests/QtAutogen/WrappedFindPackage/main.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include <qobject.h>
|
||||
|
||||
class MyObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MyObject(QObject* parent = 0)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
MyObject obj;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "main.moc"
|
Loading…
Reference in New Issue
Block a user