QtSupport: Detect all Qt versions in PATH

There is no reason to limit the number of auto-detected Qt versions to
one, in particular when there's systems (e.g. ArchLinux) where the
plain, version-less qmake executable points to Qt 5 and Qt 6 therefore
did not get auto-detected at all.

Change-Id: I288a964c23ef4319fcfcc31d098c0f385614d369
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2024-09-05 16:43:28 +02:00
parent 828440b0ff
commit c2f24b53c6
2 changed files with 29 additions and 30 deletions

View File

@@ -2,6 +2,8 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "buildablehelperlibrary.h"
#include "algorithm.h"
#include "environment.h"
#include "hostosinfo.h"
#include "qtcprocess.h"
@@ -42,7 +44,7 @@ FilePath BuildableHelperLibrary::qtChooserToQmakePath(const FilePath &qtChooser)
static bool isQmake(FilePath path)
{
if (path.isEmpty())
if (!path.isExecutableFile())
return false;
if (BuildableHelperLibrary::isQtChooser(path))
path = BuildableHelperLibrary::qtChooserToQmakePath(path.symLinkTarget());
@@ -51,37 +53,42 @@ static bool isQmake(FilePath path)
return !BuildableHelperLibrary::qtVersionForQMake(path).isEmpty();
}
static FilePath findQmakeInDir(const FilePath &dir)
static FilePaths findQmakesInDir(const FilePath &dir)
{
if (dir.isEmpty())
return {};
FilePath qmakePath = dir.pathAppended("qmake").withExecutableSuffix();
if (qmakePath.exists()) {
if (isQmake(qmakePath))
return qmakePath;
}
// Prefer qmake-qt5 to qmake-qt4 by sorting the filenames in reverse order.
FilePaths qmakes;
std::set<FilePath> canonicalQmakes;
const FilePaths candidates = dir.dirEntries(
{BuildableHelperLibrary::possibleQMakeCommands(), QDir::Files},
QDir::Name | QDir::Reversed);
const auto probablyMatchesExistingQmake = [&](const FilePath &qmake) {
// This deals with symlinks.
if (!canonicalQmakes.insert(qmake).second)
return true;
// Symlinks have high potential for false positives in file size check, so skip that one.
if (qmake.isSymLink())
return false;
// This deals with the case where copies are shipped instead of symlinks
// (Windows, Qt installer, ...).
return contains(qmakes, [size = qmake.fileSize()](const FilePath &existing) {
return existing.fileSize() == size;
});
};
for (const FilePath &candidate : candidates) {
if (candidate == qmakePath)
continue;
if (isQmake(candidate))
return candidate;
if (isQmake(candidate) && !probablyMatchesExistingQmake(candidate))
qmakes << candidate;
}
return {};
return qmakes;
}
FilePath BuildableHelperLibrary::findSystemQt(const Environment &env)
{
const FilePaths list = findQtsInEnvironment(env, 1);
return list.size() == 1 ? list.first() : FilePath();
}
FilePaths BuildableHelperLibrary::findQtsInEnvironment(const Environment &env, int maxCount)
FilePaths BuildableHelperLibrary::findQtsInEnvironment(const Environment &env)
{
FilePaths qmakeList;
std::set<FilePath> canonicalEnvPaths;
@@ -89,12 +96,7 @@ FilePaths BuildableHelperLibrary::findQtsInEnvironment(const Environment &env, i
for (const FilePath &path : paths) {
if (!canonicalEnvPaths.insert(path.canonicalPath()).second)
continue;
const FilePath qmake = findQmakeInDir(path);
if (qmake.isEmpty())
continue;
qmakeList << qmake;
if (maxCount != -1 && qmakeList.size() == maxCount)
break;
qmakeList << findQmakesInDir(path);
}
return qmakeList;
}

View File

@@ -16,10 +16,7 @@ class Environment;
class QTCREATOR_UTILS_EXPORT BuildableHelperLibrary
{
public:
// returns the full path to the first qmake, qmake-qt4, qmake4 that has
// at least version 2.0.0 and thus is a qt4 qmake
static FilePath findSystemQt(const Environment &env);
static FilePaths findQtsInEnvironment(const Environment &env, int maxCount = -1);
static FilePaths findQtsInEnvironment(const Environment &env);
static bool isQtChooser(const FilePath &filePath);
static FilePath qtChooserToQmakePath(const FilePath &path);
// return true if the qmake at qmakePath is a Qt (used by QtVersion)