forked from qt-creator/qt-creator
Improve kit auto-detection
The old code was too simplistic: Basically, we just took a random toolchain, slapped a random Qt onto it and made that the default kit. Instead, we now go through all toolchains, try to find a matching Qt version, debugger etc and create a kit for that combination unless there is a better one. Fixes: QTCREATORBUG-22138 Change-Id: Ib57ca4453a93ee9253c75398328c3bca33087dc6 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -626,8 +626,10 @@ bool Abi::isCompatibleWith(const Abi &other) const
|
|||||||
if (isCompat && (osFlavor() == AndroidLinuxFlavor || other.osFlavor() == AndroidLinuxFlavor))
|
if (isCompat && (osFlavor() == AndroidLinuxFlavor || other.osFlavor() == AndroidLinuxFlavor))
|
||||||
isCompat = (architecture() == other.architecture()) && (osFlavor() == other.osFlavor());
|
isCompat = (architecture() == other.architecture()) && (osFlavor() == other.osFlavor());
|
||||||
|
|
||||||
if (!isCompat && compatibleMSVCFlavors(osFlavor(), other.osFlavor()))
|
if (!isCompat && wordWidth() == other.wordWidth()
|
||||||
|
&& compatibleMSVCFlavors(osFlavor(), other.osFlavor())) {
|
||||||
isCompat = true;
|
isCompat = true;
|
||||||
|
}
|
||||||
|
|
||||||
return isCompat;
|
return isCompat;
|
||||||
}
|
}
|
||||||
|
@@ -46,6 +46,8 @@
|
|||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
@@ -354,6 +356,15 @@ Id Kit::id() const
|
|||||||
return d->m_id;
|
return d->m_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Kit::weight() const
|
||||||
|
{
|
||||||
|
const QList<KitAspect *> &aspects = KitManager::kitAspects();
|
||||||
|
return std::accumulate(aspects.begin(), aspects.end(), 0,
|
||||||
|
[this](int sum, const KitAspect *aspect) {
|
||||||
|
return sum + aspect->weight(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static QIcon iconForDeviceType(Core::Id deviceType)
|
static QIcon iconForDeviceType(Core::Id deviceType)
|
||||||
{
|
{
|
||||||
const IDeviceFactory *factory = Utils::findOrDefault(IDeviceFactory::allDeviceFactories(),
|
const IDeviceFactory *factory = Utils::findOrDefault(IDeviceFactory::allDeviceFactories(),
|
||||||
|
@@ -90,6 +90,12 @@ public:
|
|||||||
bool isSdkProvided() const;
|
bool isSdkProvided() const;
|
||||||
Core::Id id() const;
|
Core::Id id() const;
|
||||||
|
|
||||||
|
// The higher the weight, the more aspects have sensible values for this kit.
|
||||||
|
// For instance, a kit where a matching debugger was found for the toolchain will have a
|
||||||
|
// higher weight than one whose toolchain does not match a known debugger, assuming
|
||||||
|
// all other aspects are equal.
|
||||||
|
int weight() const;
|
||||||
|
|
||||||
QIcon icon() const;
|
QIcon icon() const;
|
||||||
Utils::FileName iconPath() const;
|
Utils::FileName iconPath() const;
|
||||||
void setIconPath(const Utils::FileName &path);
|
void setIconPath(const Utils::FileName &path);
|
||||||
|
@@ -25,12 +25,16 @@
|
|||||||
|
|
||||||
#include "kitmanager.h"
|
#include "kitmanager.h"
|
||||||
|
|
||||||
|
#include "abi.h"
|
||||||
#include "devicesupport/idevicefactory.h"
|
#include "devicesupport/idevicefactory.h"
|
||||||
#include "kit.h"
|
#include "kit.h"
|
||||||
#include "kitfeatureprovider.h"
|
#include "kitfeatureprovider.h"
|
||||||
|
#include "kitinformation.h"
|
||||||
#include "kitmanagerconfigwidget.h"
|
#include "kitmanagerconfigwidget.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
|
#include "projectexplorerconstants.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "toolchainmanager.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
@@ -40,6 +44,7 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
|
|
||||||
@@ -220,16 +225,60 @@ void KitManager::restoreKits()
|
|||||||
// Delete all loaded autodetected kits that were not rediscovered:
|
// Delete all loaded autodetected kits that were not rediscovered:
|
||||||
kitsToCheck.clear();
|
kitsToCheck.clear();
|
||||||
|
|
||||||
if (resultList.size() == 0) {
|
if (resultList.empty()) {
|
||||||
auto defaultKit = std::make_unique<Kit>(); // One kit using default values
|
// No kits exist yet, so let's try to autoconfigure some from the toolchains we know.
|
||||||
defaultKit->setUnexpandedDisplayName(tr("Desktop"));
|
// We consider only host toolchains, because for other ones we lack the knowledge how to
|
||||||
defaultKit->setSdkProvided(false);
|
// map them to their respective device type.
|
||||||
defaultKit->setAutoDetected(false);
|
static const auto isHostToolchain = [](const ToolChain *tc) {
|
||||||
|
static const Abi hostAbi = Abi::hostAbi();
|
||||||
|
const Abi tcAbi = tc->targetAbi();
|
||||||
|
return tcAbi.os() == hostAbi.os() && tcAbi.architecture() == hostAbi.architecture()
|
||||||
|
&& (tcAbi.os() != Abi::LinuxOS || tcAbi.osFlavor() == hostAbi.osFlavor());
|
||||||
|
};
|
||||||
|
const QList<ToolChain *> allToolchains = ToolChainManager::toolChains(isHostToolchain);
|
||||||
|
QHash<Abi, QHash<Core::Id, ToolChain *>> uniqueToolchains;
|
||||||
|
|
||||||
defaultKit->setup();
|
// On Linux systems, we usually detect a plethora of same-ish toolchains. The following
|
||||||
|
// algorithm gives precedence to icecc and ccache and otherwise simply chooses the one with
|
||||||
|
// the shortest path. This should also take care of ensuring matching C/C++ pairs.
|
||||||
|
// TODO: This should not need to be done here. Instead, it should be a convenience
|
||||||
|
// operation on some lower level, e.g. in the toolchain class(es).
|
||||||
|
// Also, we shouldn't detect so many doublets in the first place.
|
||||||
|
for (ToolChain * const tc : allToolchains) {
|
||||||
|
ToolChain *&bestTc = uniqueToolchains[tc->targetAbi()][tc->language()];
|
||||||
|
if (!bestTc) {
|
||||||
|
bestTc = tc;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const QString bestFilePath = bestTc->compilerCommand().toString();
|
||||||
|
const QString currentFilePath = tc->compilerCommand().toString();
|
||||||
|
if ((currentFilePath.contains("icecc") && !bestFilePath.contains("icecc"))
|
||||||
|
|| (currentFilePath.contains("ccache") && !bestFilePath.contains("ccache")
|
||||||
|
&& !bestFilePath.contains("icecc"))
|
||||||
|
|| (bestFilePath.length() > currentFilePath.length())) {
|
||||||
|
bestTc = tc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
completeKit(defaultKit.get()); // Store manual kits
|
int maxWeight = 0;
|
||||||
resultList.emplace_back(std::move(defaultKit));
|
for (auto it = uniqueToolchains.cbegin(); it != uniqueToolchains.cend(); ++it) {
|
||||||
|
auto kit = std::make_unique<Kit>();
|
||||||
|
kit->setSdkProvided(false);
|
||||||
|
kit->setAutoDetected(false); // TODO: Why false? What does autodetected mean here?
|
||||||
|
for (ToolChain * const tc : it.value())
|
||||||
|
ToolChainKitAspect::setToolChain(kit.get(), tc);
|
||||||
|
kit->setUnexpandedDisplayName(tr("Desktop (%1)").arg(it.key().toString()));
|
||||||
|
kit->setup();
|
||||||
|
if (kit->weight() < maxWeight)
|
||||||
|
continue;
|
||||||
|
if (kit->weight() > maxWeight) {
|
||||||
|
maxWeight = kit->weight();
|
||||||
|
resultList.clear();
|
||||||
|
}
|
||||||
|
resultList.emplace_back(std::move(kit));
|
||||||
|
}
|
||||||
|
if (resultList.size() == 1)
|
||||||
|
resultList.front()->setUnexpandedDisplayName(tr("Desktop"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Kit *k = Utils::findOrDefault(resultList, Utils::equal(&Kit::id, defaultUserKit));
|
Kit *k = Utils::findOrDefault(resultList, Utils::equal(&Kit::id, defaultUserKit));
|
||||||
@@ -515,6 +564,11 @@ KitAspect::~KitAspect()
|
|||||||
KitManager::deregisterKitAspect(this);
|
KitManager::deregisterKitAspect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int KitAspect::weight(const Kit *k) const
|
||||||
|
{
|
||||||
|
return k->value(id()).isValid() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
void KitAspect::addToEnvironment(const Kit *k, Environment &env) const
|
void KitAspect::addToEnvironment(const Kit *k, Environment &env) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(k);
|
Q_UNUSED(k);
|
||||||
|
@@ -88,6 +88,8 @@ public:
|
|||||||
// called on initial setup of a kit.
|
// called on initial setup of a kit.
|
||||||
virtual void setup(Kit *) { return; }
|
virtual void setup(Kit *) { return; }
|
||||||
|
|
||||||
|
virtual int weight(const Kit *k) const;
|
||||||
|
|
||||||
virtual ItemList toUserOutput(const Kit *) const = 0;
|
virtual ItemList toUserOutput(const Kit *) const = 0;
|
||||||
|
|
||||||
virtual KitAspectWidget *createConfigWidget(Kit *) const = 0;
|
virtual KitAspectWidget *createConfigWidget(Kit *) const = 0;
|
||||||
|
@@ -163,17 +163,32 @@ QtKitAspect::QtKitAspect()
|
|||||||
|
|
||||||
void QtKitAspect::setup(ProjectExplorer::Kit *k)
|
void QtKitAspect::setup(ProjectExplorer::Kit *k)
|
||||||
{
|
{
|
||||||
Q_UNUSED(k);
|
const Abi tcAbi = ToolChainKitAspect::targetAbi(k);
|
||||||
|
const Core::Id deviceType = DeviceTypeKitAspect::deviceTypeId(k);
|
||||||
|
|
||||||
// find "Qt in PATH":
|
const QList<BaseQtVersion *> matches
|
||||||
BaseQtVersion *result = QtVersionManager::version(equal(&BaseQtVersion::autodetectionSource,
|
= QtVersionManager::versions([&tcAbi, &deviceType](const BaseQtVersion *qt) {
|
||||||
QString::fromLatin1("PATH")));
|
return qt->targetDeviceTypes().contains(deviceType)
|
||||||
if (!result) {
|
&& Utils::contains(qt->qtAbis(), [&tcAbi](const Abi &qtAbi) {
|
||||||
// Use *any* desktop Qt:
|
return qtAbi.isCompatibleWith(tcAbi); });
|
||||||
result = QtVersionManager::version(equal(&BaseQtVersion::type,
|
});
|
||||||
QString::fromLatin1(QtSupport::Constants::DESKTOPQT)));
|
if (matches.empty())
|
||||||
}
|
return;
|
||||||
k->setValue(id(), result ? result->uniqueId() : -1);
|
|
||||||
|
// An MSVC 2015 toolchain is compatible with an MSVC 2017 Qt, but we prefer an
|
||||||
|
// MSVC 2015 Qt if we find one.
|
||||||
|
const QList<BaseQtVersion *> exactMatches = Utils::filtered(matches,
|
||||||
|
[&tcAbi](const BaseQtVersion *qt) {
|
||||||
|
return qt->qtAbis().contains(tcAbi);
|
||||||
|
});
|
||||||
|
const QList<BaseQtVersion *> &candidates = !exactMatches.empty() ? exactMatches : matches;
|
||||||
|
|
||||||
|
BaseQtVersion * const qtFromPath = QtVersionManager::version(
|
||||||
|
equal(&BaseQtVersion::autodetectionSource, QString::fromLatin1("PATH")));
|
||||||
|
if (qtFromPath && candidates.contains(qtFromPath))
|
||||||
|
k->setValue(id(), qtFromPath->uniqueId());
|
||||||
|
else
|
||||||
|
k->setValue(id(), candidates.first()->uniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ProjectExplorer::Task> QtKitAspect::validate(const ProjectExplorer::Kit *k) const
|
QList<ProjectExplorer::Task> QtKitAspect::validate(const ProjectExplorer::Kit *k) const
|
||||||
@@ -370,4 +385,18 @@ QSet<Core::Id> QtKitAspect::availableFeatures(const Kit *k) const
|
|||||||
return version ? version->features() : QSet<Core::Id>();
|
return version ? version->features() : QSet<Core::Id>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int QtKitAspect::weight(const Kit *k) const
|
||||||
|
{
|
||||||
|
const BaseQtVersion * const qt = qtVersion(k);
|
||||||
|
if (!qt)
|
||||||
|
return 0;
|
||||||
|
if (!qt->targetDeviceTypes().contains(DeviceTypeKitAspect::deviceTypeId(k)))
|
||||||
|
return 0;
|
||||||
|
const Abi tcAbi = ToolChainKitAspect::targetAbi(k);
|
||||||
|
if (qt->qtAbis().contains(tcAbi))
|
||||||
|
return 2;
|
||||||
|
return Utils::contains(qt->qtAbis(), [&tcAbi](const Abi &qtAbi) {
|
||||||
|
return qtAbi.isCompatibleWith(tcAbi); }) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QtSupport
|
} // namespace QtSupport
|
||||||
|
@@ -73,6 +73,8 @@ public:
|
|||||||
QSet<Core::Id> availableFeatures(const ProjectExplorer::Kit *k) const override;
|
QSet<Core::Id> availableFeatures(const ProjectExplorer::Kit *k) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int weight(const ProjectExplorer::Kit *k) const override;
|
||||||
|
|
||||||
void qtVersionsChanged(const QList<int> &addedIds,
|
void qtVersionsChanged(const QList<int> &addedIds,
|
||||||
const QList<int> &removedIds,
|
const QList<int> &removedIds,
|
||||||
const QList<int> &changedIds);
|
const QList<int> &changedIds);
|
||||||
|
Reference in New Issue
Block a user