diff --git a/src/plugins/qnx/CMakeLists.txt b/src/plugins/qnx/CMakeLists.txt index 7d842aa61ac..8d0c6751b3f 100644 --- a/src/plugins/qnx/CMakeLists.txt +++ b/src/plugins/qnx/CMakeLists.txt @@ -4,8 +4,6 @@ add_qtc_plugin(Qnx SOURCES qnx.qrc qnxanalyzesupport.cpp qnxanalyzesupport.h - qnxconfiguration.cpp qnxconfiguration.h - qnxconfigurationmanager.cpp qnxconfigurationmanager.h qnxconstants.h qnxdebugsupport.cpp qnxdebugsupport.h qnxdeployqtlibrariesdialog.cpp qnxdeployqtlibrariesdialog.h diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index ee1752f816f..ad4eae91c83 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -20,8 +20,6 @@ QtcPlugin { "qnxtoolchain.h", "qnx.qrc", "qnxconstants.h", - "qnxconfiguration.cpp", - "qnxconfiguration.h", "qnxanalyzesupport.cpp", "qnxanalyzesupport.h", "qnxdebugsupport.cpp", @@ -30,8 +28,6 @@ QtcPlugin { "qnxdevice.h", "qnxdevicetester.cpp", "qnxdevicetester.h", - "qnxconfigurationmanager.cpp", - "qnxconfigurationmanager.h", "qnxsettingspage.cpp", "qnxsettingspage.h", "qnxtr.h", diff --git a/src/plugins/qnx/qnxconfiguration.cpp b/src/plugins/qnx/qnxconfiguration.cpp deleted file mode 100644 index 0ca024248a8..00000000000 --- a/src/plugins/qnx/qnxconfiguration.cpp +++ /dev/null @@ -1,466 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qnxconfiguration.h" - -#include "qnxqtversion.h" -#include "qnxutils.h" -#include "qnxtoolchain.h" -#include "qnxtr.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include -#include -#include - -using namespace ProjectExplorer; -using namespace QtSupport; -using namespace Utils; -using namespace Debugger; - -namespace Qnx::Internal { - -const QLatin1String QNXEnvFileKey("EnvFile"); -const QLatin1String QNXVersionKey("QNXVersion"); -// For backward compatibility -const QLatin1String SdpEnvFileKey("NDKEnvFile"); - -const QLatin1String QNXConfiguration("QNX_CONFIGURATION"); -const QLatin1String QNXTarget("QNX_TARGET"); -const QLatin1String QNXHost("QNX_HOST"); - -QnxConfiguration::QnxConfiguration() = default; - -QnxConfiguration::QnxConfiguration(const FilePath &sdpEnvFile) -{ - setDefaultConfiguration(sdpEnvFile); - readInformation(); -} - -QnxConfiguration::QnxConfiguration(const QVariantMap &data) -{ - QString envFilePath = data.value(QNXEnvFileKey).toString(); - if (envFilePath.isEmpty()) - envFilePath = data.value(SdpEnvFileKey).toString(); - - m_version = QnxVersionNumber(data.value(QNXVersionKey).toString()); - - setDefaultConfiguration(FilePath::fromString(envFilePath)); - readInformation(); -} - -FilePath QnxConfiguration::envFile() const -{ - return m_envFile; -} - -FilePath QnxConfiguration::qnxTarget() const -{ - return m_qnxTarget; -} - -FilePath QnxConfiguration::qnxHost() const -{ - return m_qnxHost; -} - -FilePath QnxConfiguration::qccCompilerPath() const -{ - return m_qccCompiler; -} - -EnvironmentItems QnxConfiguration::qnxEnv() const -{ - return m_qnxEnv; -} - -QnxVersionNumber QnxConfiguration::version() const -{ - return m_version; -} - -QVariantMap QnxConfiguration::toMap() const -{ - QVariantMap data; - data.insert(QLatin1String(QNXEnvFileKey), m_envFile.toString()); - data.insert(QLatin1String(QNXVersionKey), m_version.toString()); - return data; -} - -bool QnxConfiguration::isValid() const -{ - return !m_qccCompiler.isEmpty() && !m_targets.isEmpty(); -} - -QString QnxConfiguration::displayName() const -{ - return m_configName; -} - -bool QnxConfiguration::activate() -{ - if (isActive()) - return true; - - if (!isValid()) { - QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Cannot Set Up QNX Configuration"), - validationErrorMessage(), QMessageBox::Ok); - return false; - } - - for (const Target &target : std::as_const(m_targets)) - createTools(target); - - return true; -} - -void QnxConfiguration::deactivate() -{ - if (!isActive()) - return; - - const Toolchains toolChainsToRemove = - ToolChainManager::toolchains(Utils::equal(&ToolChain::compilerCommand, qccCompilerPath())); - - QList debuggersToRemove; - const QList debuggerItems = DebuggerItemManager::debuggers(); - for (const DebuggerItem &debuggerItem : debuggerItems) { - if (findTargetByDebuggerPath(debuggerItem.command())) - debuggersToRemove.append(debuggerItem); - } - - const QList kits = KitManager::kits(); - for (Kit *kit : kits) { - if (kit->isAutoDetected() - && DeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE - && toolChainsToRemove.contains(ToolChainKitAspect::cxxToolChain(kit))) { - KitManager::deregisterKit(kit); - } - } - - for (ToolChain *tc : toolChainsToRemove) - ToolChainManager::deregisterToolChain(tc); - - for (const DebuggerItem &debuggerItem : std::as_const(debuggersToRemove)) - DebuggerItemManager::deregisterDebugger(debuggerItem.id()); -} - -bool QnxConfiguration::isActive() const -{ - const bool hasToolChain = ToolChainManager::toolChain(Utils::equal(&ToolChain::compilerCommand, - qccCompilerPath())); - const bool hasDebugger = Utils::contains(DebuggerItemManager::debuggers(), [this](const DebuggerItem &di) { - return findTargetByDebuggerPath(di.command()); - }); - - return hasToolChain && hasDebugger; -} - -FilePath QnxConfiguration::sdpPath() const -{ - return envFile().parentDir(); -} - -QnxQtVersion *QnxConfiguration::qnxQtVersion(const Target &target) const -{ - const QtVersions versions = QtVersionManager::versions( - Utils::equal(&QtVersion::type, QString::fromLatin1(Constants::QNX_QNX_QT))); - for (QtVersion *version : versions) { - auto qnxQt = dynamic_cast(version); - if (qnxQt && qnxQt->sdpPath() == sdpPath()) { - const Abis abis = version->qtAbis(); - for (const Abi &qtAbi : abis) { - if ((qtAbi == target.m_abi) && (qnxQt->cpuDir() == target.cpuDir())) - return qnxQt; - } - } - } - return nullptr; -} - -QList QnxConfiguration::autoDetect(const QList &alreadyKnown) -{ - QList result; - - for (const Target &target : std::as_const(m_targets)) - result += findToolChain(alreadyKnown, target.m_abi); - - return result; -} - -void QnxConfiguration::createTools(const Target &target) -{ - QnxToolChainMap toolchainMap = createToolChain(target); - QVariant debuggerId = createDebugger(target); - createKit(target, toolchainMap, debuggerId); -} - -QVariant QnxConfiguration::createDebugger(const Target &target) -{ - Environment sysEnv = m_qnxHost.deviceEnvironment(); - sysEnv.modify(qnxEnvironmentItems()); - - Debugger::DebuggerItem debugger; - debugger.setCommand(target.m_debuggerPath); - debugger.reinitializeFromFile(nullptr, &sysEnv); - debugger.setUnexpandedDisplayName(Tr::tr("Debugger for %1 (%2)") - .arg(displayName()) - .arg(target.shortDescription())); - return Debugger::DebuggerItemManager::registerDebugger(debugger); -} - -QnxConfiguration::QnxToolChainMap QnxConfiguration::createToolChain(const Target &target) -{ - QnxToolChainMap toolChainMap; - - for (auto language : { ProjectExplorer::Constants::C_LANGUAGE_ID, - ProjectExplorer::Constants::CXX_LANGUAGE_ID}) { - auto toolChain = new QnxToolChain; - toolChain->setDetection(ToolChain::AutoDetection); - toolChain->setLanguage(language); - toolChain->setTargetAbi(target.m_abi); - toolChain->setDisplayName(Tr::tr("QCC for %1 (%2)") - .arg(displayName()) - .arg(target.shortDescription())); - toolChain->setSdpPath(sdpPath()); - toolChain->setCpuDir(target.cpuDir()); - toolChain->resetToolChain(qccCompilerPath()); - ToolChainManager::registerToolChain(toolChain); - - toolChainMap.insert({language, toolChain}); - } - - return toolChainMap; -} - -QList QnxConfiguration::findToolChain(const QList &alreadyKnown, - const Abi &abi) -{ - return Utils::filtered(alreadyKnown, [this, abi](ToolChain *tc) { - return tc->typeId() == Constants::QNX_TOOLCHAIN_ID - && tc->targetAbi() == abi - && tc->compilerCommand() == m_qccCompiler; - }); -} - -void QnxConfiguration::createKit(const Target &target, const QnxToolChainMap &toolChainMap, - const QVariant &debugger) -{ - QnxQtVersion *qnxQt = qnxQtVersion(target); // nullptr is ok. - - const auto init = [&](Kit *k) { - QtKitAspect::setQtVersion(k, qnxQt); - ToolChainKitAspect::setToolChain(k, toolChainMap.at(ProjectExplorer::Constants::C_LANGUAGE_ID)); - ToolChainKitAspect::setToolChain(k, toolChainMap.at(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); - - if (debugger.isValid()) - DebuggerKitAspect::setDebugger(k, debugger); - - DeviceTypeKitAspect::setDeviceTypeId(k, Constants::QNX_QNX_OS_TYPE); - // TODO: Add sysroot? - - k->setUnexpandedDisplayName(Tr::tr("Kit for %1 (%2)") - .arg(displayName()) - .arg(target.shortDescription())); - - k->setAutoDetected(false); - k->setAutoDetectionSource(envFile().toString()); - k->setMutable(DeviceKitAspect::id(), true); - - k->setSticky(ToolChainKitAspect::id(), true); - k->setSticky(DeviceTypeKitAspect::id(), true); - k->setSticky(SysRootKitAspect::id(), true); - k->setSticky(DebuggerKitAspect::id(), true); - k->setSticky(QmakeProjectManager::Constants::KIT_INFORMATION_ID, true); - - EnvironmentKitAspect::setEnvironmentChanges(k, qnxEnvironmentItems()); - }; - - // add kit with device and qt version not sticky - KitManager::registerKit(init); -} - -QString QnxConfiguration::validationErrorMessage() const -{ - if (isValid()) - return {}; - - QStringList errorStrings - = {Tr::tr("The following errors occurred while activating the QNX configuration:")}; - if (m_qccCompiler.isEmpty()) - errorStrings << Tr::tr("- No GCC compiler found."); - if (m_targets.isEmpty()) - errorStrings << Tr::tr("- No targets found."); - return errorStrings.join('\n'); -} - -void QnxConfiguration::setVersion(const QnxVersionNumber &version) -{ - m_version = version; -} - -void QnxConfiguration::readInformation() -{ - const FilePath configPath = m_qnxConfiguration / "qconfig"; - if (!configPath.isDir()) - return; - - configPath.iterateDirectory([this, configPath](const FilePath &sdpFile) { - QFile xmlFile(sdpFile.toFSPathString()); - if (!xmlFile.open(QIODevice::ReadOnly)) - return IterationPolicy::Continue; - - QDomDocument doc; - if (!doc.setContent(&xmlFile)) // Skip error message - return IterationPolicy::Continue; - - QDomElement docElt = doc.documentElement(); - if (docElt.tagName() != QLatin1String("qnxSystemDefinition")) - return IterationPolicy::Continue; - - QDomElement childElt = docElt.firstChildElement(QLatin1String("installation")); - // The file contains only one installation node - if (childElt.isNull()) // The file contains only one base node - return IterationPolicy::Continue; - - FilePath host = configPath.withNewPath( - childElt.firstChildElement(QLatin1String("host")).text()).canonicalPath(); - if (m_qnxHost != host) - return IterationPolicy::Continue; - - FilePath target = configPath.withNewPath( - childElt.firstChildElement(QLatin1String("target")).text()).canonicalPath(); - if (m_qnxTarget != target) - return IterationPolicy::Continue; - - m_configName = childElt.firstChildElement(QLatin1String("name")).text(); - QString version = childElt.firstChildElement(QLatin1String("version")).text(); - setVersion(QnxVersionNumber(version)); - return IterationPolicy::Stop; - }, {{"*.xml"}, QDir::Files}); -} - -void QnxConfiguration::setDefaultConfiguration(const FilePath &envScript) -{ - QTC_ASSERT(!envScript.isEmpty(), return); - m_envFile = envScript; - m_qnxEnv = QnxUtils::qnxEnvironmentFromEnvFile(m_envFile); - for (const EnvironmentItem &item : std::as_const(m_qnxEnv)) { - if (item.name == QNXConfiguration) - m_qnxConfiguration = envScript.withNewPath(item.value).canonicalPath(); - else if (item.name == QNXTarget) - m_qnxTarget = envScript.withNewPath(item.value).canonicalPath(); - else if (item.name == QNXHost) - m_qnxHost = envScript.withNewPath(item.value).canonicalPath(); - } - - const FilePath qccPath = m_qnxHost.pathAppended("usr/bin/qcc").withExecutableSuffix(); - if (qccPath.exists()) - m_qccCompiler = qccPath; - - // Some fall back in case the qconfig dir with .xml files is not found later - if (m_configName.isEmpty()) - m_configName = QString("%1 - %2").arg(m_qnxHost.fileName(), m_qnxTarget.fileName()); - - updateTargets(); - assignDebuggersToTargets(); - - // Remove debuggerless targets. - Utils::erase(m_targets, [](const Target &target) { - if (target.m_debuggerPath.isEmpty()) - qWarning() << "No debugger found for" << target.m_path << "... discarded"; - return target.m_debuggerPath.isEmpty(); - }); -} - -EnvironmentItems QnxConfiguration::qnxEnvironmentItems() const -{ - Utils::EnvironmentItems envList; - envList.push_back(EnvironmentItem(QNXConfiguration, m_qnxConfiguration.path())); - envList.push_back(EnvironmentItem(QNXTarget, m_qnxTarget.path())); - envList.push_back(EnvironmentItem(QNXHost, m_qnxHost.path())); - - return envList; -} - -const QnxConfiguration::Target *QnxConfiguration::findTargetByDebuggerPath( - const FilePath &path) const -{ - const auto it = std::find_if(m_targets.begin(), m_targets.end(), - [path](const Target &target) { return target.m_debuggerPath == path; }); - return it == m_targets.end() ? nullptr : &(*it); -} - -void QnxConfiguration::updateTargets() -{ - m_targets.clear(); - const QList targets = QnxUtils::findTargets(m_qnxTarget); - for (const QnxTarget &target : targets) - m_targets.append(Target(target.m_abi, target.m_path)); -} - -void QnxConfiguration::assignDebuggersToTargets() -{ - const FilePath hostUsrBinDir = m_qnxHost.pathAppended("usr/bin"); - QString pattern = "nto*-gdb"; - if (m_qnxHost.osType() == Utils::OsTypeWindows) - pattern += ".exe"; - - const FilePaths debuggerNames = hostUsrBinDir.dirEntries({{pattern}, QDir::Files}); - Environment sysEnv = m_qnxHost.deviceEnvironment(); - sysEnv.modify(qnxEnvironmentItems()); - - for (const FilePath &debuggerPath : debuggerNames) { - DebuggerItem item; - item.setCommand(debuggerPath); - item.reinitializeFromFile(nullptr, &sysEnv); - bool found = false; - for (const Abi &abi : item.abis()) { - for (Target &target : m_targets) { - if (target.m_abi.isCompatibleWith(abi)) { - found = true; - - if (target.m_debuggerPath.isEmpty()) { - target.m_debuggerPath = debuggerPath; - } else { - qWarning() << debuggerPath << "has the same ABI as" << target.m_debuggerPath - << "... discarded"; - break; - } - } - } - } - if (!found) - qWarning() << "No target found for" << debuggerPath.toUserOutput() << "... discarded"; - } -} - -QString QnxConfiguration::Target::shortDescription() const -{ - return QnxUtils::cpuDirShortDescription(cpuDir()); -} - -QString QnxConfiguration::Target::cpuDir() const -{ - return m_path.fileName(); -} - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxconfiguration.h b/src/plugins/qnx/qnxconfiguration.h deleted file mode 100644 index 34056536c35..00000000000 --- a/src/plugins/qnx/qnxconfiguration.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "qnxconstants.h" -#include "qnxversionnumber.h" - -#include -#include - -#include - -#include - -#include - -namespace ProjectExplorer -{ - class Kit; - class ToolChain; -} - -namespace Qnx::Internal { - -class QnxToolChain; -class QnxQtVersion; - -class QnxConfiguration -{ -public: - QnxConfiguration(); - QnxConfiguration(const Utils::FilePath &sdpEnvFile); - QnxConfiguration(const QVariantMap &data); - - Utils::FilePath envFile() const; - Utils::FilePath qnxTarget() const; - Utils::FilePath qnxHost() const; - Utils::FilePath qccCompilerPath() const; - Utils::EnvironmentItems qnxEnv() const; - QnxVersionNumber version() const; - QVariantMap toMap() const; - - bool isValid() const; - - QString displayName() const; - bool activate(); - void deactivate(); - bool isActive() const; - Utils::FilePath sdpPath() const; - - QList autoDetect( - const QList &alreadyKnown); - -private: - QList findToolChain( - const QList &alreadyKnown, - const ProjectExplorer::Abi &abi); - - QString validationErrorMessage() const; - - void setVersion(const QnxVersionNumber& version); - - void readInformation(); - - void setDefaultConfiguration(const Utils::FilePath &envScript); - - Utils::EnvironmentItems qnxEnvironmentItems() const; - - QString m_configName; - - Utils::FilePath m_envFile; - Utils::FilePath m_qnxConfiguration; - Utils::FilePath m_qnxTarget; - Utils::FilePath m_qnxHost; - Utils::FilePath m_qccCompiler; - Utils::EnvironmentItems m_qnxEnv; - QnxVersionNumber m_version; - - class Target - { - public: - Target(const ProjectExplorer::Abi &abi, const Utils::FilePath &path) - : m_abi(abi), m_path(path) - { - } - - QString shortDescription() const; - QString cpuDir() const; - - ProjectExplorer::Abi m_abi; - Utils::FilePath m_path; - Utils::FilePath m_debuggerPath; - }; - - QList m_targets; - - QnxQtVersion *qnxQtVersion(const Target &target) const; - - void createTools(const Target &target); - QVariant createDebugger(const Target &target); - - using QnxToolChainMap = std::map; - - QnxToolChainMap createToolChain(const Target &target); - void createKit(const Target &target, const QnxToolChainMap &toolChain, const QVariant &debugger); - - const Target *findTargetByDebuggerPath(const Utils::FilePath &path) const; - - void updateTargets(); - void assignDebuggersToTargets(); -}; - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxconfigurationmanager.cpp b/src/plugins/qnx/qnxconfigurationmanager.cpp deleted file mode 100644 index da585b69cf2..00000000000 --- a/src/plugins/qnx/qnxconfigurationmanager.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qnxconfigurationmanager.h" - -#include "qnxconfiguration.h" - -#include - -#include -#include - -using namespace Utils; - -namespace Qnx::Internal { - -const QLatin1String QNXConfigDataKey("QNXConfiguration."); -const QLatin1String QNXConfigCountKey("QNXConfiguration.Count"); -const QLatin1String QNXConfigsFileVersionKey("Version"); - -static FilePath qnxConfigSettingsFileName() -{ - return Core::ICore::userResourcePath("qnx/qnxconfigurations.xml"); -} - -static QnxConfigurationManager *m_instance = nullptr; - -QnxConfigurationManager::QnxConfigurationManager() -{ - m_instance = this; - m_writer = new PersistentSettingsWriter(qnxConfigSettingsFileName(), "QnxConfigurations"); - connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, - this, &QnxConfigurationManager::saveConfigs); -} - -QnxConfigurationManager *QnxConfigurationManager::instance() -{ - return m_instance; -} - -QnxConfigurationManager::~QnxConfigurationManager() -{ - m_instance = nullptr; - qDeleteAll(m_configurations); - delete m_writer; -} - -QList QnxConfigurationManager::configurations() const -{ - return m_configurations; -} - -void QnxConfigurationManager::removeConfiguration(QnxConfiguration *config) -{ - if (m_configurations.removeAll(config)) { - delete config; - emit configurationsListUpdated(); - } -} - -bool QnxConfigurationManager::addConfiguration(QnxConfiguration *config) -{ - if (!config || !config->isValid()) - return false; - - for (QnxConfiguration *c : std::as_const(m_configurations)) { - if (c->envFile() == config->envFile()) - return false; - } - - m_configurations.append(config); - emit configurationsListUpdated(); - return true; -} - -QnxConfiguration *QnxConfigurationManager::configurationFromEnvFile(const FilePath &envFile) const -{ - for (QnxConfiguration *c : m_configurations) { - if (c->envFile() == envFile) - return c; - } - - return nullptr; -} - -void QnxConfigurationManager::saveConfigs() -{ - QTC_ASSERT(m_writer, return); - QVariantMap data; - data.insert(QLatin1String(QNXConfigsFileVersionKey), 1); - int count = 0; - for (QnxConfiguration *config : std::as_const(m_configurations)) { - QVariantMap tmp = config->toMap(); - if (tmp.isEmpty()) - continue; - - data.insert(QNXConfigDataKey + QString::number(count), tmp); - ++count; - } - - data.insert(QLatin1String(QNXConfigCountKey), count); - m_writer->save(data, Core::ICore::dialogParent()); -} - -void QnxConfigurationManager::restoreConfigurations() -{ - PersistentSettingsReader reader; - if (!reader.load(qnxConfigSettingsFileName())) - return; - - QVariantMap data = reader.restoreValues(); - int count = data.value(QNXConfigCountKey, 0).toInt(); - for (int i = 0; i < count; ++i) { - const QString key = QNXConfigDataKey + QString::number(i); - if (!data.contains(key)) - continue; - - const QVariantMap dMap = data.value(key).toMap(); - auto configuration = new QnxConfiguration(dMap); - addConfiguration(configuration); - } -} - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxconfigurationmanager.h b/src/plugins/qnx/qnxconfigurationmanager.h deleted file mode 100644 index bc0d02dd988..00000000000 --- a/src/plugins/qnx/qnxconfigurationmanager.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Utils { class PersistentSettingsWriter; } - -namespace Qnx::Internal { - -class QnxConfiguration; -class QnxPlugin; - -class QnxConfigurationManager: public QObject -{ - Q_OBJECT -public: - QnxConfigurationManager(); - ~QnxConfigurationManager() override; - - void restoreConfigurations(); - - static QnxConfigurationManager *instance(); - QList configurations() const; - void removeConfiguration(QnxConfiguration *config); - bool addConfiguration(QnxConfiguration *config); - QnxConfiguration* configurationFromEnvFile(const Utils::FilePath &envFile) const; - -protected slots: - void saveConfigs(); - -signals: - void configurationsListUpdated(); - -private: - QList m_configurations; - Utils::PersistentSettingsWriter *m_writer; -}; - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index ef09b0b7b46..09fd528086c 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qnxanalyzesupport.h" -#include "qnxconfigurationmanager.h" #include "qnxconstants.h" #include "qnxdebugsupport.h" #include "qnxdevice.h" @@ -80,7 +79,7 @@ public: QAction *m_debugSeparator = nullptr; QAction m_attachToQnxApplication{Tr::tr("Attach to remote QNX application..."), nullptr}; - QnxConfigurationManager configurationManager; + QnxSettingsPage settingsPage; QnxQtVersionFactory qtVersionFactory; QnxDeviceFactory deviceFactory; QnxDeployConfigurationFactory deployConfigFactory; @@ -88,7 +87,6 @@ public: Constants::QNX_DIRECT_UPLOAD_STEP_ID}; QnxDeployStepFactory makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId}; QnxRunConfigurationFactory runConfigFactory; - QnxSettingsPage settingsPage; QnxToolChainFactory toolChainFactory; SimpleTargetRunnerFactory runWorkerFactory{{runConfigFactory.runConfigurationId()}}; QnxDebugWorkerFactory debugWorkerFactory; @@ -112,10 +110,6 @@ private: void QnxPlugin::extensionsInitialized() { - // Can't do yet as not all devices are around. - connect(DeviceManager::instance(), &DeviceManager::devicesLoaded, - &d->configurationManager, &QnxConfigurationManager::restoreConfigurations); - // Attach support connect(&d->m_attachToQnxApplication, &QAction::triggered, this, &showAttachToProcessDialog); diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 0d354037735..119c7a3e2a0 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -3,29 +3,481 @@ #include "qnxsettingspage.h" -#include "qnxconfiguration.h" -#include "qnxconfigurationmanager.h" +#include "qnxqtversion.h" +#include "qnxtoolchain.h" #include "qnxtr.h" +#include "qnxutils.h" +#include "qnxversionnumber.h" #include +#include +#include +#include + +#include #include +#include +#include +#include +#include +#include #include +#include +#include + +#include #include +#include +#include #include #include +#include +#include #include #include #include #include +using namespace ProjectExplorer; +using namespace QtSupport; using namespace Utils; +using namespace Debugger; namespace Qnx::Internal { +const QLatin1String QNXEnvFileKey("EnvFile"); +const QLatin1String QNXVersionKey("QNXVersion"); +// For backward compatibility +const QLatin1String SdpEnvFileKey("NDKEnvFile"); + +const QLatin1String QNXConfiguration("QNX_CONFIGURATION"); +const QLatin1String QNXTarget("QNX_TARGET"); +const QLatin1String QNXHost("QNX_HOST"); + +const QLatin1String QNXConfigDataKey("QNXConfiguration."); +const QLatin1String QNXConfigCountKey("QNXConfiguration.Count"); +const QLatin1String QNXConfigsFileVersionKey("Version"); + +static FilePath qnxConfigSettingsFileName() +{ + return Core::ICore::userResourcePath("qnx/qnxconfigurations.xml"); +} + +class QnxConfiguration +{ +public: + QnxConfiguration() = default; + explicit QnxConfiguration(const FilePath &envFile) { m_envFile = envFile; } + + void fromMap(const QVariantMap &data) + { + QString envFilePath = data.value(QNXEnvFileKey).toString(); + if (envFilePath.isEmpty()) + envFilePath = data.value(SdpEnvFileKey).toString(); + + m_version = QnxVersionNumber(data.value(QNXVersionKey).toString()); + m_envFile = FilePath::fromString(envFilePath); + } + + QVariantMap toMap() const + { + QVariantMap data; + data.insert(QLatin1String(QNXEnvFileKey), m_envFile.toString()); + data.insert(QLatin1String(QNXVersionKey), m_version.toString()); + return data; + } + + bool isValid() const + { + return !m_qccCompiler.isEmpty() && !m_targets.isEmpty(); + } + + bool isActive() const + { + const bool hasToolChain = ToolChainManager::toolChain(Utils::equal(&ToolChain::compilerCommand, + m_qccCompiler)); + const bool hasDebugger = Utils::contains(DebuggerItemManager::debuggers(), [this](const DebuggerItem &di) { + return findTargetByDebuggerPath(di.command()); + }); + return hasToolChain && hasDebugger; + } + + void activate(); + void deactivate(); + + void ensureContents() const; + void mutableEnsureContents(); + + EnvironmentItems qnxEnvironmentItems() const; + + QnxQtVersion *qnxQtVersion(const QnxTarget &target) const; + + void createKit(const QnxTarget &target); + QVariant createDebugger(const QnxTarget &target); + Toolchains createToolChains(const QnxTarget &target); + + const QnxTarget *findTargetByDebuggerPath(const Utils::FilePath &path) const; + + bool m_hasContents = false; + QString m_configName; + + FilePath m_envFile; + FilePath m_qnxConfiguration; + FilePath m_qnxTarget; + FilePath m_qnxHost; + FilePath m_qccCompiler; + EnvironmentItems m_qnxEnv; + QnxVersionNumber m_version; + + QList m_targets; +}; + +void QnxConfiguration::activate() +{ + ensureContents(); + + if (!isValid()) { + QStringList errorStrings + = {Tr::tr("The following errors occurred while activating the QNX configuration:")}; + if (m_qccCompiler.isEmpty()) + errorStrings << Tr::tr("- No GCC compiler found."); + if (m_targets.isEmpty()) + errorStrings << Tr::tr("- No targets found."); + const QString msg = errorStrings.join('\n'); + + QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Cannot Set Up QNX Configuration"), + msg, QMessageBox::Ok); + return; + } + + for (const QnxTarget &target : std::as_const(m_targets)) + createKit(target); +} + +void QnxConfiguration::deactivate() +{ + QTC_ASSERT(isActive(), return); + + const Toolchains toolChainsToRemove = + ToolChainManager::toolchains(Utils::equal(&ToolChain::compilerCommand, m_qccCompiler)); + + QList debuggersToRemove; + const QList debuggerItems = DebuggerItemManager::debuggers(); + for (const DebuggerItem &debuggerItem : debuggerItems) { + if (findTargetByDebuggerPath(debuggerItem.command())) + debuggersToRemove.append(debuggerItem); + } + + const QList kits = KitManager::kits(); + for (Kit *kit : kits) { + if (kit->isAutoDetected() + && DeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE + && toolChainsToRemove.contains(ToolChainKitAspect::cxxToolChain(kit))) { + KitManager::deregisterKit(kit); + } + } + + for (ToolChain *tc : toolChainsToRemove) + ToolChainManager::deregisterToolChain(tc); + + for (const DebuggerItem &debuggerItem : std::as_const(debuggersToRemove)) + DebuggerItemManager::deregisterDebugger(debuggerItem.id()); +} + +QnxQtVersion *QnxConfiguration::qnxQtVersion(const QnxTarget &target) const +{ + const QtVersions versions = QtVersionManager::versions( + Utils::equal(&QtVersion::type, QString::fromLatin1(Constants::QNX_QNX_QT))); + for (QtVersion *version : versions) { + auto qnxQt = dynamic_cast(version); + if (qnxQt && qnxQt->sdpPath() == m_envFile.parentDir()) { + const Abis abis = version->qtAbis(); + for (const Abi &qtAbi : abis) { + if (qtAbi == target.m_abi && qnxQt->cpuDir() == target.cpuDir()) + return qnxQt; + } + } + } + return nullptr; +} + +QVariant QnxConfiguration::createDebugger(const QnxTarget &target) +{ + Environment sysEnv = m_qnxHost.deviceEnvironment(); + sysEnv.modify(qnxEnvironmentItems()); + + Debugger::DebuggerItem debugger; + debugger.setCommand(target.m_debuggerPath); + debugger.reinitializeFromFile(nullptr, &sysEnv); + debugger.setUnexpandedDisplayName(Tr::tr("Debugger for %1 (%2)") + .arg(m_configName) + .arg(target.shortDescription())); + return Debugger::DebuggerItemManager::registerDebugger(debugger); +} + +Toolchains QnxConfiguration::createToolChains(const QnxTarget &target) +{ + Toolchains toolChains; + + for (const Id language : {ProjectExplorer::Constants::C_LANGUAGE_ID, + ProjectExplorer::Constants::CXX_LANGUAGE_ID}) { + auto toolChain = new QnxToolChain; + toolChain->setDetection(ToolChain::AutoDetection); + toolChain->setLanguage(language); + toolChain->setTargetAbi(target.m_abi); + toolChain->setDisplayName(Tr::tr("QCC for %1 (%2)") + .arg(m_configName) + .arg(target.shortDescription())); + toolChain->setSdpPath(m_envFile.parentDir()); + toolChain->setCpuDir(target.cpuDir()); + toolChain->resetToolChain(m_qccCompiler); + ToolChainManager::registerToolChain(toolChain); + + toolChains.append(toolChain); + } + + return toolChains; +} + +void QnxConfiguration::createKit(const QnxTarget &target) +{ + Toolchains toolChains = createToolChains(target); + QVariant debugger = createDebugger(target); + + QnxQtVersion *qnxQt = qnxQtVersion(target); // nullptr is ok. + + const auto init = [&](Kit *k) { + QtKitAspect::setQtVersion(k, qnxQt); + ToolChainKitAspect::setToolChain(k, toolChains[0]); + ToolChainKitAspect::setToolChain(k, toolChains[1]); + + if (debugger.isValid()) + DebuggerKitAspect::setDebugger(k, debugger); + + DeviceTypeKitAspect::setDeviceTypeId(k, Constants::QNX_QNX_OS_TYPE); + // TODO: Add sysroot? + + k->setUnexpandedDisplayName(Tr::tr("Kit for %1 (%2)") + .arg(m_configName) + .arg(target.shortDescription())); + + k->setAutoDetected(false); + k->setAutoDetectionSource(m_envFile.toString()); + k->setMutable(DeviceKitAspect::id(), true); + + k->setSticky(ToolChainKitAspect::id(), true); + k->setSticky(DeviceTypeKitAspect::id(), true); + k->setSticky(SysRootKitAspect::id(), true); + k->setSticky(DebuggerKitAspect::id(), true); + k->setSticky(QmakeProjectManager::Constants::KIT_INFORMATION_ID, true); + + EnvironmentKitAspect::setEnvironmentChanges(k, qnxEnvironmentItems()); + }; + + // add kit with device and qt version not sticky + KitManager::registerKit(init); +} + +void QnxConfiguration::ensureContents() const +{ + if (!m_hasContents) + const_cast(this)->mutableEnsureContents(); +} + +void QnxConfiguration::mutableEnsureContents() +{ + QTC_ASSERT(!m_envFile.isEmpty(), return); + m_hasContents = true; + + m_qnxEnv = QnxUtils::qnxEnvironmentFromEnvFile(m_envFile); + for (const EnvironmentItem &item : std::as_const(m_qnxEnv)) { + if (item.name == QNXConfiguration) + m_qnxConfiguration = m_envFile.withNewPath(item.value).canonicalPath(); + else if (item.name == QNXTarget) + m_qnxTarget = m_envFile.withNewPath(item.value).canonicalPath(); + else if (item.name == QNXHost) + m_qnxHost = m_envFile.withNewPath(item.value).canonicalPath(); + } + + const FilePath qccPath = m_qnxHost.pathAppended("usr/bin/qcc").withExecutableSuffix(); + if (qccPath.exists()) + m_qccCompiler = qccPath; + + // Some fallback in case the qconfig dir with .xml files is not found later. + if (m_configName.isEmpty()) + m_configName = QString("%1 - %2").arg(m_qnxHost.fileName(), m_qnxTarget.fileName()); + + m_targets = QnxUtils::findTargets(m_qnxTarget); + + // Assign debuggers. + const FilePath hostUsrBinDir = m_qnxHost.pathAppended("usr/bin"); + QString pattern = "nto*-gdb"; + if (m_qnxHost.osType() == Utils::OsTypeWindows) + pattern += ".exe"; + + const FilePaths debuggerNames = hostUsrBinDir.dirEntries({{pattern}, QDir::Files}); + Environment sysEnv = m_qnxHost.deviceEnvironment(); + sysEnv.modify(qnxEnvironmentItems()); + + for (const FilePath &debuggerPath : debuggerNames) { + DebuggerItem item; + item.setCommand(debuggerPath); + item.reinitializeFromFile(nullptr, &sysEnv); + bool found = false; + for (const Abi &abi : item.abis()) { + for (QnxTarget &target : m_targets) { + if (target.m_abi.isCompatibleWith(abi)) { + found = true; + + if (target.m_debuggerPath.isEmpty()) { + target.m_debuggerPath = debuggerPath; + } else { + qWarning() << debuggerPath << "has the same ABI as" << target.m_debuggerPath + << "... discarded"; + break; + } + } + } + } + if (!found) + qWarning() << "No target found for" << debuggerPath.toUserOutput() << "... discarded"; + } + + // Remove debuggerless targets. + Utils::erase(m_targets, [](const QnxTarget &target) { + if (target.m_debuggerPath.isEmpty()) + qWarning() << "No debugger found for" << target.m_path << "... discarded"; + return target.m_debuggerPath.isEmpty(); + }); + + const FilePath configPath = m_qnxConfiguration / "qconfig"; + if (!configPath.isDir()) + return; + + configPath.iterateDirectory([this, configPath](const FilePath &sdpFile) { + QFile xmlFile(sdpFile.toFSPathString()); + if (!xmlFile.open(QIODevice::ReadOnly)) + return IterationPolicy::Continue; + + QDomDocument doc; + if (!doc.setContent(&xmlFile)) // Skip error message + return IterationPolicy::Continue; + + QDomElement docElt = doc.documentElement(); + if (docElt.tagName() != QLatin1String("qnxSystemDefinition")) + return IterationPolicy::Continue; + + QDomElement childElt = docElt.firstChildElement(QLatin1String("installation")); + // The file contains only one installation node + if (childElt.isNull()) // The file contains only one base node + return IterationPolicy::Continue; + + FilePath host = configPath.withNewPath( + childElt.firstChildElement(QLatin1String("host")).text()).canonicalPath(); + if (m_qnxHost != host) + return IterationPolicy::Continue; + + FilePath target = configPath.withNewPath( + childElt.firstChildElement(QLatin1String("target")).text()).canonicalPath(); + if (m_qnxTarget != target) + return IterationPolicy::Continue; + + m_configName = childElt.firstChildElement(QLatin1String("name")).text(); + QString version = childElt.firstChildElement(QLatin1String("version")).text(); + m_version = QnxVersionNumber(version); + return IterationPolicy::Stop; + }, {{"*.xml"}, QDir::Files}); +} + +EnvironmentItems QnxConfiguration::qnxEnvironmentItems() const +{ + ensureContents(); + return { + {QNXConfiguration, m_qnxConfiguration.path()}, + {QNXTarget, m_qnxTarget.path()}, + {QNXHost, m_qnxHost.path()} + }; +} + +const QnxTarget *QnxConfiguration::findTargetByDebuggerPath( + const FilePath &path) const +{ + const auto it = std::find_if(m_targets.begin(), m_targets.end(), + [path](const QnxTarget &target) { return target.m_debuggerPath == path; }); + return it == m_targets.end() ? nullptr : &(*it); +} + + +// QnxSettingsPagePrivate + +class QnxSettingsPagePrivate : public QObject +{ +public: + QnxSettingsPagePrivate() + { + connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, + this, &QnxSettingsPagePrivate::saveConfigs); + // Can't do yet as not all devices are around. + connect(DeviceManager::instance(), &DeviceManager::devicesLoaded, + this, &QnxSettingsPagePrivate::restoreConfigurations); + } + + void saveConfigs() + { + QVariantMap data; + data.insert(QLatin1String(QNXConfigsFileVersionKey), 1); + int count = 0; + for (const QnxConfiguration &config : std::as_const(m_configurations)) { + QVariantMap tmp = config.toMap(); + if (tmp.isEmpty()) + continue; + + data.insert(QNXConfigDataKey + QString::number(count), tmp); + ++count; + } + + data.insert(QLatin1String(QNXConfigCountKey), count); + m_writer.save(data, Core::ICore::dialogParent()); + } + + void restoreConfigurations() + { + PersistentSettingsReader reader; + if (!reader.load(qnxConfigSettingsFileName())) + return; + + QVariantMap data = reader.restoreValues(); + int count = data.value(QNXConfigCountKey, 0).toInt(); + for (int i = 0; i < count; ++i) { + const QString key = QNXConfigDataKey + QString::number(i); + if (!data.contains(key)) + continue; + + QnxConfiguration config; + config.fromMap(data.value(key).toMap()); + m_configurations[config.m_envFile] = config; + } + } + + QnxConfiguration *configurationFromEnvFile(const FilePath &envFile) + { + auto it = m_configurations.find(envFile); + return it == m_configurations.end() ? nullptr : &*it; + } + + QHash m_configurations; + PersistentSettingsWriter m_writer{qnxConfigSettingsFileName(), "QnxConfigurations"}; +}; + +static QnxSettingsPagePrivate *dd = nullptr; + + +// QnxSettingsWidget + class QnxSettingsWidget final : public Core::IOptionsPageWidget { public: @@ -42,10 +494,10 @@ public: public: bool operator ==(const ConfigState &cs) const { - return config == cs.config && state == cs.state; + return envFile == cs.envFile && state == cs.state; } - QnxConfiguration *config; + FilePath envFile; State state; }; @@ -57,7 +509,7 @@ public: void updateInformation(); void populateConfigsCombo(); - void setConfigState(QnxConfiguration *config, State state); + void setConfigState(const FilePath &envFile, State state); private: QComboBox *m_configsCombo = new QComboBox; @@ -67,7 +519,6 @@ private: QLabel *m_configHost = new QLabel; QLabel *m_configTarget = new QLabel; - QnxConfigurationManager *m_qnxConfigManager = QnxConfigurationManager::instance(); QList m_changedConfigs; }; @@ -101,6 +552,7 @@ QnxSettingsWidget::QnxSettingsWidget() }.attachTo(this); populateConfigsCombo(); + connect(addButton, &QAbstractButton::clicked, this, &QnxSettingsWidget::addConfiguration); connect(removeButton, &QAbstractButton::clicked, @@ -109,17 +561,14 @@ QnxSettingsWidget::QnxSettingsWidget() this, &QnxSettingsWidget::updateInformation); connect(m_generateKitsCheckBox, &QAbstractButton::toggled, this, &QnxSettingsWidget::generateKits); - connect(m_qnxConfigManager, &QnxConfigurationManager::configurationsListUpdated, - this, &QnxSettingsWidget::populateConfigsCombo); - connect(QtSupport::QtVersionManager::instance(), - &QtSupport::QtVersionManager::qtVersionsChanged, + connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged, this, &QnxSettingsWidget::updateInformation); } void QnxSettingsWidget::addConfiguration() { QString filter; - if (Utils::HostOsInfo::isWindowsHost()) + if (HostOsInfo::isWindowsHost()) filter = "*.bat file"; else filter = "*.sh file"; @@ -129,82 +578,88 @@ void QnxSettingsWidget::addConfiguration() if (envFile.isEmpty()) return; - QnxConfiguration *config = new QnxConfiguration(envFile); - if (m_qnxConfigManager->configurations().contains(config) || !config->isValid()) { + if (dd->m_configurations.contains(envFile)) { QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Warning"), - Tr::tr("Configuration already exists or is invalid.")); - delete config; + Tr::tr("Configuration already exists.")); return; } - setConfigState(config, Added); - m_configsCombo->addItem(config->displayName(), - QVariant::fromValue(static_cast(config))); + // Temporary to be able to check + QnxConfiguration config(envFile); + config.ensureContents(); + if (!config.isValid()) { + QMessageBox::warning(Core::ICore::dialogParent(), + Tr::tr("Warning"), + Tr::tr("Configuration is not valid.")); + return; + } + + setConfigState(envFile, Added); + m_configsCombo->addItem(config.m_configName, QVariant::fromValue(envFile)); } void QnxSettingsWidget::removeConfiguration() { - const int currentIndex = m_configsCombo->currentIndex(); - auto config = static_cast( - m_configsCombo->itemData(currentIndex).value()); + const FilePath envFile = m_configsCombo->currentData().value(); + QTC_ASSERT(!envFile.isEmpty(), return); - if (!config) - return; + QnxConfiguration *config = dd->configurationFromEnvFile(envFile); + QTC_ASSERT(config, return); + + config->ensureContents(); QMessageBox::StandardButton button = QMessageBox::question(Core::ICore::dialogParent(), Tr::tr("Remove QNX Configuration"), - Tr::tr("Are you sure you want to remove:\n %1?").arg(config->displayName()), + Tr::tr("Are you sure you want to remove:\n %1?") + .arg(config->m_configName), QMessageBox::Yes | QMessageBox::No); if (button == QMessageBox::Yes) { - setConfigState(config, Removed); - m_configsCombo->removeItem(currentIndex); + setConfigState(envFile, Removed); + m_configsCombo->removeItem(m_configsCombo->currentIndex()); + updateInformation(); } } void QnxSettingsWidget::generateKits(bool checked) { - const int currentIndex = m_configsCombo->currentIndex(); - auto config = static_cast( - m_configsCombo->itemData(currentIndex).value()); - if (!config) - return; - - setConfigState(config, checked ? Activated : Deactivated); + const FilePath envFile = m_configsCombo->currentData().value(); + setConfigState(envFile, checked ? Activated : Deactivated); } void QnxSettingsWidget::updateInformation() { - const int currentIndex = m_configsCombo->currentIndex(); + const FilePath envFile = m_configsCombo->currentData().value(); - auto config = static_cast( - m_configsCombo->itemData(currentIndex).value()); - - // update the checkbox - m_generateKitsCheckBox->setEnabled(config ? config->isValid() : false); - m_generateKitsCheckBox->setChecked(config ? config->isActive() : false); - - // update information - m_configName->setText(config ? config->displayName() : QString()); - m_configVersion->setText(config ? config->version().toString() : QString()); - m_configHost->setText(config ? config->qnxHost().toString() : QString()); - m_configTarget->setText(config ? config->qnxTarget().toString() : QString()); + if (QnxConfiguration *config = dd->configurationFromEnvFile(envFile)) { + config->ensureContents(); + m_generateKitsCheckBox->setEnabled(config->isValid()); + m_generateKitsCheckBox->setChecked(config->isActive()); + m_configName->setText(config->m_configName); + m_configVersion->setText(config->m_version.toString()); + m_configHost->setText(config->m_qnxHost.toString()); + m_configTarget->setText(config->m_qnxTarget.toString()); + } else { + m_generateKitsCheckBox->setEnabled(false); + m_generateKitsCheckBox->setChecked(false); + m_configName->setText({}); + m_configVersion->setText({}); + m_configHost->setText({}); + m_configTarget->setText({}); + } } void QnxSettingsWidget::populateConfigsCombo() { m_configsCombo->clear(); - const QList configList = m_qnxConfigManager->configurations(); - for (QnxConfiguration *config : configList) { - m_configsCombo->addItem(config->displayName(), - QVariant::fromValue(static_cast(config))); - } + for (const QnxConfiguration &config : std::as_const(dd->m_configurations)) + m_configsCombo->addItem(config.m_configName, QVariant::fromValue(config.m_envFile)); updateInformation(); } -void QnxSettingsWidget::setConfigState(QnxConfiguration *config, State state) +void QnxSettingsWidget::setConfigState(const FilePath &envFile, State state) { State stateToRemove = Activated; switch (state) { @@ -223,45 +678,79 @@ void QnxSettingsWidget::setConfigState(QnxConfiguration *config, State state) } for (const ConfigState &configState : std::as_const(m_changedConfigs)) { - if (configState.config == config && configState.state == stateToRemove) + if (configState.envFile == envFile && configState.state == stateToRemove) m_changedConfigs.removeAll(configState); } - m_changedConfigs.append(ConfigState{config, state}); + m_changedConfigs.append(ConfigState{envFile, state}); } void QnxSettingsWidget::apply() { for (const ConfigState &configState : std::as_const(m_changedConfigs)) { switch (configState.state) { - case Activated : - configState.config->activate(); + case Activated: { + QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile); + QTC_ASSERT(config, break); + config->activate(); break; - case Deactivated: - configState.config->deactivate(); + } + case Deactivated: { + QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile); + QTC_ASSERT(config, break); + config->deactivate(); break; - case Added: - m_qnxConfigManager->addConfiguration(configState.config); + } + case Added: { + QnxConfiguration config(configState.envFile); + config.ensureContents(); + dd->m_configurations.insert(configState.envFile, config); break; + } case Removed: - configState.config->deactivate(); - m_qnxConfigManager->removeConfiguration(configState.config); + QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile); + QTC_ASSERT(config, break); + config->deactivate(); + dd->m_configurations.remove(configState.envFile); break; } } m_changedConfigs.clear(); + populateConfigsCombo(); } - // QnxSettingsPage +QList QnxSettingsPage::autoDetect(const QList &alreadyKnown) +{ + QList result; + for (const QnxConfiguration &config : std::as_const(dd->m_configurations)) { + config.ensureContents(); + for (const QnxTarget &target : std::as_const(config.m_targets)) { + result += Utils::filtered(alreadyKnown, [config, target](ToolChain *tc) { + return tc->typeId() == Constants::QNX_TOOLCHAIN_ID + && tc->targetAbi() == target.m_abi + && tc->compilerCommand() == config.m_qccCompiler; + }); + } + } + return result; +} + QnxSettingsPage::QnxSettingsPage() { setId("DD.Qnx Configuration"); setDisplayName(Tr::tr("QNX")); setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); setWidgetCreator([] { return new QnxSettingsWidget; }); + + dd = new QnxSettingsPagePrivate; +} + +QnxSettingsPage::~QnxSettingsPage() +{ + delete dd; } } // Qnx::Internal diff --git a/src/plugins/qnx/qnxsettingspage.h b/src/plugins/qnx/qnxsettingspage.h index cdf6f1ba860..f127d5f35e4 100644 --- a/src/plugins/qnx/qnxsettingspage.h +++ b/src/plugins/qnx/qnxsettingspage.h @@ -5,12 +5,18 @@ #include +namespace ProjectExplorer { class ToolChain; } + namespace Qnx::Internal { class QnxSettingsPage final : public Core::IOptionsPage { public: QnxSettingsPage(); + ~QnxSettingsPage(); + + static QList autoDetect( + const QList &alreadyKnown); }; } // Qnx::Internal diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp index 187c507da49..8176b3d17c9 100644 --- a/src/plugins/qnx/qnxtoolchain.cpp +++ b/src/plugins/qnx/qnxtoolchain.cpp @@ -3,9 +3,8 @@ #include "qnxtoolchain.h" -#include "qnxconfiguration.h" -#include "qnxconfigurationmanager.h" #include "qnxconstants.h" +#include "qnxsettingspage.h" #include "qnxtr.h" #include "qnxutils.h" @@ -222,10 +221,7 @@ Toolchains QnxToolChainFactory::autoDetect(const ToolchainDetector &detector) co if (detector.device) return {}; - Toolchains tcs; - const auto configurations = QnxConfigurationManager::instance()->configurations(); - for (QnxConfiguration *configuration : configurations) - tcs += configuration->autoDetect(detector.alreadyKnown); + Toolchains tcs = QnxSettingsPage::autoDetect(detector.alreadyKnown); return tcs; } diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp index 697e95bebc6..5c1107f5997 100644 --- a/src/plugins/qnx/qnxutils.cpp +++ b/src/plugins/qnx/qnxutils.cpp @@ -16,6 +16,15 @@ using namespace Utils; namespace Qnx::Internal { +QnxTarget::QnxTarget(const Utils::FilePath &path, const ProjectExplorer::Abi &abi) : + m_path(path), m_abi(abi) +{} + +QString QnxTarget::shortDescription() const +{ + return QnxUtils::cpuDirShortDescription(cpuDir()); +} + QString QnxUtils::cpuDirFromAbi(const Abi &abi) { if (abi.os() != Abi::OS::QnxOS) diff --git a/src/plugins/qnx/qnxutils.h b/src/plugins/qnx/qnxutils.h index 4f523953e46..2fea51ccc63 100644 --- a/src/plugins/qnx/qnxutils.h +++ b/src/plugins/qnx/qnxutils.h @@ -14,12 +14,14 @@ namespace Qnx::Internal { class QnxTarget { public: - QnxTarget(const Utils::FilePath &path, const ProjectExplorer::Abi &abi) : - m_path(path), m_abi(abi) - { - } + QnxTarget(const Utils::FilePath &path, const ProjectExplorer::Abi &abi); + + QString shortDescription() const; + QString cpuDir() const { return m_path.fileName(); } + Utils::FilePath m_path; ProjectExplorer::Abi m_abi; + Utils::FilePath m_debuggerPath; }; namespace QnxUtils {