ProjectExplorer: add async toolchain autodetection

Change-Id: I82c6d0b22a9d36674c58561ef654d7ffde8574da
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2024-01-02 09:05:37 +01:00
parent 00ba645fe1
commit 9e73dc1f09
3 changed files with 69 additions and 4 deletions

View File

@@ -9,6 +9,7 @@
#include "toolchainmanager.h" #include "toolchainmanager.h"
#include "task.h" #include "task.h"
#include <utils/async.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QUuid> #include <QUuid>
@@ -656,6 +657,12 @@ Id ToolchainFactory::supportedToolchainType() const
return m_supportedToolchainType; return m_supportedToolchainType;
} }
std::optional<AsyncToolchainDetector> ToolchainFactory::asyncAutoDetector(
const ToolchainDetector &) const
{
return {};
}
void ToolchainFactory::setSupportedToolchainType(const Id &supportedToolchainType) void ToolchainFactory::setSupportedToolchainType(const Id &supportedToolchainType)
{ {
m_supportedToolchainType = supportedToolchainType; m_supportedToolchainType = supportedToolchainType;
@@ -752,4 +759,35 @@ BadToolchains BadToolchains::fromVariant(const QVariant &v)
[](const QVariant &e) { return BadToolchain::fromMap(storeFromVariant(e)); }); [](const QVariant &e) { return BadToolchain::fromMap(storeFromVariant(e)); });
} }
AsyncToolchainDetector::AsyncToolchainDetector(
const ToolchainDetector &detector,
const std::function<Toolchains(const ToolchainDetector &)> &func,
const std::function<bool(const Toolchain *, const Toolchains &)> &alreadyRegistered)
: m_detector(detector)
, m_func(func)
, m_alreadyRegistered(alreadyRegistered)
{
}
void AsyncToolchainDetector::run()
{
auto watcher = new QFutureWatcher<Toolchains>();
QObject::connect(watcher,
&QFutureWatcher<Toolchains>::finished,
[watcher,
alreadyRegistered = m_alreadyRegistered]() {
Toolchains existingTcs = ToolchainManager::toolchains();
for (Toolchain *tc : watcher->result()) {
if (tc->isValid() && !alreadyRegistered(tc, existingTcs)) {
ToolchainManager::registerToolchain(tc);
existingTcs << tc;
} else {
delete tc;
}
}
watcher->deleteLater();
});
watcher->setFuture(Utils::asyncRun(m_func, m_detector));
}
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -241,6 +241,20 @@ public:
const Utils::FilePaths searchPaths; // If empty use device path and/or magic. const Utils::FilePaths searchPaths; // If empty use device path and/or magic.
}; };
class PROJECTEXPLORER_EXPORT AsyncToolchainDetector
{
public:
AsyncToolchainDetector(
const ToolchainDetector &detector,
const std::function<Toolchains(const ToolchainDetector &)> &func,
const std::function<bool(const Toolchain *, const Toolchains &)> &alreadyRegistered);
void run();
private:
ToolchainDetector m_detector;
std::function<Toolchains(const ToolchainDetector &)> m_func;
std::function<bool(Toolchain *, const Toolchains &)> m_alreadyRegistered;
};
class PROJECTEXPLORER_EXPORT ToolchainFactory class PROJECTEXPLORER_EXPORT ToolchainFactory
{ {
ToolchainFactory(const ToolchainFactory &) = delete; ToolchainFactory(const ToolchainFactory &) = delete;
@@ -255,6 +269,8 @@ public:
QString displayName() const { return m_displayName; } QString displayName() const { return m_displayName; }
Utils::Id supportedToolchainType() const; Utils::Id supportedToolchainType() const;
virtual std::optional<AsyncToolchainDetector> asyncAutoDetector(
const ToolchainDetector &detector) const;
virtual Toolchains autoDetect(const ToolchainDetector &detector) const; virtual Toolchains autoDetect(const ToolchainDetector &detector) const;
virtual Toolchains detectForImport(const ToolchainDescription &tcd) const; virtual Toolchains detectForImport(const ToolchainDescription &tcd) const;

View File

@@ -54,16 +54,27 @@ struct ToolChainOperations
Toolchains toDelete; Toolchains toDelete;
}; };
static Toolchains autoDetectToolChains(const ToolchainDetector &detector) static Toolchains autoDetectToolchains(const ToolchainDetector &detector)
{ {
Toolchains result; Toolchains result;
for (ToolchainFactory *f : ToolchainFactory::allToolchainFactories()) { for (ToolchainFactory *f : ToolchainFactory::allToolchainFactories()) {
NANOTRACE_SCOPE_ARGS("ProjectExplorer", NANOTRACE_SCOPE_ARGS("ProjectExplorer",
"ToolChainSettingsAccessor::autoDetectToolChains", "ToolchainSettingsAccessor::autoDetectToolchains",
{"factory", f->displayName().toStdString()}); {"factory", f->displayName().toStdString()});
QElapsedTimer et; QElapsedTimer et;
et.start(); et.start();
result.append(f->autoDetect(detector)); if (std::optional<AsyncToolchainDetector> asyncDetector = f->asyncAutoDetector(detector)) {
Toolchains known = Utils::filtered(detector.alreadyKnown,
[supportedType = f->supportedToolchainType()](
const Toolchain *tc) {
return tc->typeId() == supportedType
&& tc->isValid();
});
result.append(known);
asyncDetector->run();
} else {
result.append(f->autoDetect(detector));
}
qCDebug(Log) << f->displayName() << "auto detection took: " << et.elapsed() << "ms"; qCDebug(Log) << f->displayName() << "auto detection took: " << et.elapsed() << "ms";
} }
@@ -201,7 +212,7 @@ Toolchains ToolchainSettingsAccessor::restoreToolChains(QWidget *parent) const
// Autodect from system paths on the desktop device. // Autodect from system paths on the desktop device.
// The restriction is intentional to keep startup and automatic validation a limited effort // The restriction is intentional to keep startup and automatic validation a limited effort
ToolchainDetector detector(autodetectedUserFileTcs, DeviceManager::defaultDesktopDevice(), {}); ToolchainDetector detector(autodetectedUserFileTcs, DeviceManager::defaultDesktopDevice(), {});
const Toolchains autodetectedTcs = autoDetectToolChains(detector); const Toolchains autodetectedTcs = autoDetectToolchains(detector);
// merge tool chains and register those that we need to keep: // merge tool chains and register those that we need to keep:
const ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs); const ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs);