diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index 1e0d19b8d7d..77dcf99e1fd 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -9,6 +9,7 @@ #include "toolchainmanager.h" #include "task.h" +#include #include #include @@ -656,6 +657,12 @@ Id ToolchainFactory::supportedToolchainType() const return m_supportedToolchainType; } +std::optional ToolchainFactory::asyncAutoDetector( + const ToolchainDetector &) const +{ + return {}; +} + void ToolchainFactory::setSupportedToolchainType(const Id &supportedToolchainType) { m_supportedToolchainType = supportedToolchainType; @@ -752,4 +759,35 @@ BadToolchains BadToolchains::fromVariant(const QVariant &v) [](const QVariant &e) { return BadToolchain::fromMap(storeFromVariant(e)); }); } +AsyncToolchainDetector::AsyncToolchainDetector( + const ToolchainDetector &detector, + const std::function &func, + const std::function &alreadyRegistered) + : m_detector(detector) + , m_func(func) + , m_alreadyRegistered(alreadyRegistered) +{ +} + +void AsyncToolchainDetector::run() +{ + auto watcher = new QFutureWatcher(); + QObject::connect(watcher, + &QFutureWatcher::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 diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index 54cc2718c48..9f90a1c84b0 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -241,6 +241,20 @@ public: const Utils::FilePaths searchPaths; // If empty use device path and/or magic. }; +class PROJECTEXPLORER_EXPORT AsyncToolchainDetector +{ +public: + AsyncToolchainDetector( + const ToolchainDetector &detector, + const std::function &func, + const std::function &alreadyRegistered); + void run(); +private: + ToolchainDetector m_detector; + std::function m_func; + std::function m_alreadyRegistered; +}; + class PROJECTEXPLORER_EXPORT ToolchainFactory { ToolchainFactory(const ToolchainFactory &) = delete; @@ -255,6 +269,8 @@ public: QString displayName() const { return m_displayName; } Utils::Id supportedToolchainType() const; + virtual std::optional asyncAutoDetector( + const ToolchainDetector &detector) const; virtual Toolchains autoDetect(const ToolchainDetector &detector) const; virtual Toolchains detectForImport(const ToolchainDescription &tcd) const; diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp index 18c5d33abf7..f04adcb2157 100644 --- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp +++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp @@ -54,16 +54,27 @@ struct ToolChainOperations Toolchains toDelete; }; -static Toolchains autoDetectToolChains(const ToolchainDetector &detector) +static Toolchains autoDetectToolchains(const ToolchainDetector &detector) { Toolchains result; for (ToolchainFactory *f : ToolchainFactory::allToolchainFactories()) { NANOTRACE_SCOPE_ARGS("ProjectExplorer", - "ToolChainSettingsAccessor::autoDetectToolChains", + "ToolchainSettingsAccessor::autoDetectToolchains", {"factory", f->displayName().toStdString()}); QElapsedTimer et; et.start(); - result.append(f->autoDetect(detector)); + if (std::optional 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"; } @@ -201,7 +212,7 @@ Toolchains ToolchainSettingsAccessor::restoreToolChains(QWidget *parent) const // Autodect from system paths on the desktop device. // The restriction is intentional to keep startup and automatic validation a limited effort 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: const ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs);