ProjectExplorer: Collect and remember non-functional toolchains

It's not unusual for the toolchain auto-detection procedure to encounter
binaries that turn out not to be valid toolchains only after running
them, either because they are genuinely broken or because their names
match a compiler name pattern, but they are not actually compilers.
Until now, we would re-run such executables on every start of Qt
Creator, potentially delaying start-up unnecessarily.
Now we store them in the settings and do not try to run them again.
For now, the collection of bad toolchains is done for GCC only. Follow-
up patches will add support for more toolchain types.

Change-Id: Icfa28de523737bdd88af3a2bfa8b947326c1bc70
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2022-01-18 15:42:02 +01:00
parent 5c98d40901
commit 16ef8b6253
6 changed files with 129 additions and 5 deletions

View File

@@ -1023,10 +1023,11 @@ Toolchains GccToolChainFactory::detectForImport(const ToolChainDescription &tcd)
|| fileName == "cc"))
|| (tcd.language == Constants::CXX_LANGUAGE_ID && (fileName.startsWith("g++")
|| fileName.endsWith("g++")
|| fileName == "c++")))
|| fileName == "c++"))) {
return autoDetectToolChain(tcd, [](const ToolChain *tc) {
return tc->targetAbi().osFlavor() != Abi::WindowsMSysFlavor;
});
}
return {};
}
@@ -1164,11 +1165,15 @@ Toolchains GccToolChainFactory::autoDetectToolChain(const ToolChainDescription &
Environment systemEnvironment = Environment::systemEnvironment();
GccToolChain::addCommandPathToEnvironment(tcd.compilerPath, systemEnvironment);
const FilePath localCompilerPath = findLocalCompiler(tcd.compilerPath, systemEnvironment);
if (ToolChainManager::isBadToolchain(localCompilerPath))
return result;
Macros macros
= gccPredefinedMacros(localCompilerPath, gccPredefinedMacrosOptions(tcd.language),
systemEnvironment);
if (macros.isEmpty())
if (macros.isEmpty()) {
ToolChainManager::addBadToolchain(localCompilerPath);
return result;
}
const GccToolChain::DetectedAbisResult detectedAbis = guessGccAbi(localCompilerPath,
systemEnvironment,
macros);
@@ -1640,8 +1645,9 @@ Toolchains ClangToolChainFactory::detectForImport(const ToolChainDescription &tc
{
const QString fileName = tcd.compilerPath.toString();
if ((tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("clang") && !fileName.startsWith("clang++"))
|| (tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("clang++")))
|| (tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("clang++"))) {
return autoDetectToolChain(tcd);
}
return {};
}
@@ -1820,10 +1826,11 @@ Toolchains MingwToolChainFactory::detectForImport(const ToolChainDescription &tc
if ((tcd.language == Constants::C_LANGUAGE_ID && (fileName.startsWith("gcc")
|| fileName.endsWith("gcc")))
|| (tcd.language == Constants::CXX_LANGUAGE_ID && (fileName.startsWith("g++")
|| fileName.endsWith("g++"))))
|| fileName.endsWith("g++")))) {
return autoDetectToolChain(tcd, [](const ToolChain *tc) {
return tc->targetAbi().osFlavor() == Abi::WindowsMSysFlavor;
});
}
return {};
}
@@ -1896,8 +1903,9 @@ Toolchains LinuxIccToolChainFactory::detectForImport(const ToolChainDescription
{
const QString fileName = tcd.compilerPath.toString();
if ((tcd.language == Constants::CXX_LANGUAGE_ID && fileName.startsWith("icpc")) ||
(tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("icc")))
(tcd.language == Constants::C_LANGUAGE_ID && fileName.startsWith("icc"))) {
return autoDetectToolChain(tcd);
}
return {};
}

View File

@@ -39,6 +39,8 @@
#include <QFileInfo>
#include <QUuid>
#include <utility>
using namespace Utils;
static const char ID_KEY[] = "ProjectExplorer.ToolChain.Id";
@@ -652,4 +654,62 @@ ToolchainDetector::ToolchainDetector(const Toolchains &alreadyKnown, const IDevi
: alreadyKnown(alreadyKnown), device(device)
{}
BadToolchain::BadToolchain(const Utils::FilePath &filePath)
: BadToolchain(filePath, filePath.symLinkTarget(), filePath.lastModified())
{}
BadToolchain::BadToolchain(const Utils::FilePath &filePath, const Utils::FilePath &symlinkTarget,
const QDateTime &timestamp)
: filePath(filePath), symlinkTarget(symlinkTarget), timestamp(timestamp)
{}
static QString badToolchainFilePathKey() { return {"FilePath"}; }
static QString badToolchainSymlinkTargetKey() { return {"TargetFilePath"}; }
static QString badToolchainTimestampKey() { return {"Timestamp"}; }
QVariantMap BadToolchain::toMap() const
{
return {
std::make_pair(badToolchainFilePathKey(), filePath.toVariant()),
std::make_pair(badToolchainSymlinkTargetKey(), symlinkTarget.toVariant()),
std::make_pair(badToolchainTimestampKey(), timestamp.toMSecsSinceEpoch()),
};
}
BadToolchain BadToolchain::fromMap(const QVariantMap &map)
{
return {
FilePath::fromVariant(map.value(badToolchainFilePathKey())),
FilePath::fromVariant(map.value(badToolchainSymlinkTargetKey())),
QDateTime::fromMSecsSinceEpoch(map.value(badToolchainTimestampKey()).toLongLong())
};
}
BadToolchains::BadToolchains(const QList<BadToolchain> &toolchains)
: toolchains(Utils::filtered(toolchains, [](const BadToolchain &badTc) {
return badTc.filePath.lastModified() == badTc.timestamp
&& badTc.filePath.symLinkTarget() == badTc.symlinkTarget;
}))
{}
bool BadToolchains::isBadToolchain(const FilePath &toolchain) const
{
return Utils::contains(toolchains, [toolchain](const BadToolchain &badTc) {
return badTc.filePath == toolchain.absoluteFilePath()
|| badTc.symlinkTarget == toolchain.absoluteFilePath();
});
}
QVariant BadToolchains::toVariant() const
{
return Utils::transform<QVariantList>(toolchains, &BadToolchain::toMap);
}
BadToolchains BadToolchains::fromVariant(const QVariant &v)
{
return Utils::transform<QList<BadToolchain>>(v.toList(),
[](const QVariant &e) { return BadToolchain::fromMap(e.toMap()); });
}
} // namespace ProjectExplorer

View File

@@ -39,6 +39,7 @@
#include <utils/fileutils.h>
#include <utils/id.h>
#include <QDateTime>
#include <QObject>
#include <QStringList>
#include <QVariantMap>
@@ -214,11 +215,41 @@ private:
using Toolchains = QList<ToolChain *>;
class PROJECTEXPLORER_EXPORT BadToolchain
{
public:
BadToolchain(const Utils::FilePath &filePath);
BadToolchain(const Utils::FilePath &filePath, const Utils::FilePath &symlinkTarget,
const QDateTime &timestamp);
QVariantMap toMap() const;
static BadToolchain fromMap(const QVariantMap &map);
Utils::FilePath filePath;
Utils::FilePath symlinkTarget;
QDateTime timestamp;
};
class PROJECTEXPLORER_EXPORT BadToolchains
{
public:
BadToolchains(const QList<BadToolchain> &toolchains = {});
bool isBadToolchain(const Utils::FilePath &toolchain) const;
QVariant toVariant() const;
static BadToolchains fromVariant(const QVariant &v);
QList<BadToolchain> toolchains;
};
class PROJECTEXPLORER_EXPORT ToolchainDetector
{
public:
ToolchainDetector(const Toolchains &alreadyKnown, const IDevice::ConstPtr &device);
bool isBadToolchain(const Utils::FilePath &toolchain) const;
void addBadToolchain(const Utils::FilePath &toolchain) const;
const Toolchains alreadyKnown;
const IDevice::ConstPtr device;
};

View File

@@ -63,6 +63,7 @@ public:
std::unique_ptr<ToolChainSettingsAccessor> m_accessor;
Toolchains m_toolChains; // prioritized List
BadToolchains m_badToolchains; // to be skipped when auto-detecting
QVector<LanguageDisplayPair> m_languages;
ToolchainDetectionSettings m_detectionSettings;
bool m_loaded = false;
@@ -83,6 +84,8 @@ using namespace Internal;
const char DETECT_X64_AS_X32_KEY[] = "ProjectExplorer/Toolchains/DetectX64AsX32";
static QString badToolchainsKey() { return {"BadToolChains"}; }
// --------------------------------------------------------------------------
// ToolChainManager
// --------------------------------------------------------------------------
@@ -104,6 +107,7 @@ ToolChainManager::ToolChainManager(QObject *parent) :
QSettings * const s = Core::ICore::settings();
d->m_detectionSettings.detectX64AsX32
= s->value(DETECT_X64_AS_X32_KEY, ToolchainDetectionSettings().detectX64AsX32).toBool();
d->m_badToolchains = BadToolchains::fromVariant(s->value(badToolchainsKey()));
}
ToolChainManager::~ToolChainManager()
@@ -139,6 +143,7 @@ void ToolChainManager::saveToolChains()
s->setValueWithDefault(DETECT_X64_AS_X32_KEY,
d->m_detectionSettings.detectX64AsX32,
ToolchainDetectionSettings().detectX64AsX32);
s->setValue(badToolchainsKey(), d->m_badToolchains.toVariant());
}
const Toolchains &ToolChainManager::toolchains()
@@ -278,4 +283,19 @@ void ToolChainManager::setDetectionSettings(const ToolchainDetectionSettings &se
d->m_detectionSettings = settings;
}
void ToolChainManager::resetBadToolchains()
{
d->m_badToolchains.toolchains.clear();
}
bool ToolChainManager::isBadToolchain(const Utils::FilePath &toolchain)
{
return d->m_badToolchains.isBadToolchain(toolchain);
}
void ToolChainManager::addBadToolchain(const Utils::FilePath &toolchain)
{
d->m_badToolchains.toolchains << toolchain;
}
} // namespace ProjectExplorer

View File

@@ -83,6 +83,10 @@ public:
static ToolchainDetectionSettings detectionSettings();
static void setDetectionSettings(const ToolchainDetectionSettings &settings);
static void resetBadToolchains();
static bool isBadToolchain(const Utils::FilePath &toolchain);
static void addBadToolchain(const Utils::FilePath &toolchain);
void saveToolChains();
signals:

View File

@@ -412,6 +412,7 @@ void ToolChainOptionsWidget::redetectToolchains()
});
Toolchains toAdd;
QSet<ToolChain *> toDelete;
ToolChainManager::resetBadToolchains();
for (ToolChainFactory *f : ToolChainFactory::allToolChainFactories()) {
const ToolchainDetector detector(knownTcs, {}); // FIXME: Pass device.
for (ToolChain * const tc : f->autoDetect(detector)) {