Qnx: Re-work item store

This reduces the number of updates from the env* files and
overall simplifies the architecture.

I actually believe that it would be better if the whole configuration
settings page would not exist but be part of the device settings page.

Change-Id: I4184b74fc2c9695356752903c861f3758a6d7c73
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
hjk
2023-04-06 17:29:18 +02:00
parent 5adb656550
commit dde4a7ebf5
12 changed files with 576 additions and 831 deletions

View File

@@ -4,8 +4,6 @@ add_qtc_plugin(Qnx
SOURCES SOURCES
qnx.qrc qnx.qrc
qnxanalyzesupport.cpp qnxanalyzesupport.h qnxanalyzesupport.cpp qnxanalyzesupport.h
qnxconfiguration.cpp qnxconfiguration.h
qnxconfigurationmanager.cpp qnxconfigurationmanager.h
qnxconstants.h qnxconstants.h
qnxdebugsupport.cpp qnxdebugsupport.h qnxdebugsupport.cpp qnxdebugsupport.h
qnxdeployqtlibrariesdialog.cpp qnxdeployqtlibrariesdialog.h qnxdeployqtlibrariesdialog.cpp qnxdeployqtlibrariesdialog.h

View File

@@ -20,8 +20,6 @@ QtcPlugin {
"qnxtoolchain.h", "qnxtoolchain.h",
"qnx.qrc", "qnx.qrc",
"qnxconstants.h", "qnxconstants.h",
"qnxconfiguration.cpp",
"qnxconfiguration.h",
"qnxanalyzesupport.cpp", "qnxanalyzesupport.cpp",
"qnxanalyzesupport.h", "qnxanalyzesupport.h",
"qnxdebugsupport.cpp", "qnxdebugsupport.cpp",
@@ -30,8 +28,6 @@ QtcPlugin {
"qnxdevice.h", "qnxdevice.h",
"qnxdevicetester.cpp", "qnxdevicetester.cpp",
"qnxdevicetester.h", "qnxdevicetester.h",
"qnxconfigurationmanager.cpp",
"qnxconfigurationmanager.h",
"qnxsettingspage.cpp", "qnxsettingspage.cpp",
"qnxsettingspage.h", "qnxsettingspage.h",
"qnxtr.h", "qnxtr.h",

View File

@@ -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 <coreplugin/icore.h>
#include <debugger/debuggeritem.h>
#include <debugger/debuggeritemmanager.h>
#include <debugger/debuggerkitinformation.h>
#include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/kitmanager.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtversionmanager.h>
#include <qtsupport/qtkitinformation.h>
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
#include <utils/algorithm.h>
#include <QDebug>
#include <QDomDocument>
#include <QMessageBox>
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<DebuggerItem> debuggersToRemove;
const QList<DebuggerItem> debuggerItems = DebuggerItemManager::debuggers();
for (const DebuggerItem &debuggerItem : debuggerItems) {
if (findTargetByDebuggerPath(debuggerItem.command()))
debuggersToRemove.append(debuggerItem);
}
const QList<Kit *> 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<QnxQtVersion *>(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<ToolChain *> QnxConfiguration::autoDetect(const QList<ToolChain *> &alreadyKnown)
{
QList<ToolChain *> 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<ToolChain *> QnxConfiguration::findToolChain(const QList<ToolChain *> &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<QnxTarget> 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

View File

@@ -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 <utils/fileutils.h>
#include <utils/environment.h>
#include <projectexplorer/abi.h>
#include <debugger/debuggeritemmanager.h>
#include <QVariant>
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<ProjectExplorer::ToolChain *> autoDetect(
const QList<ProjectExplorer::ToolChain *> &alreadyKnown);
private:
QList<ProjectExplorer::ToolChain *> findToolChain(
const QList<ProjectExplorer::ToolChain *> &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<Target> m_targets;
QnxQtVersion *qnxQtVersion(const Target &target) const;
void createTools(const Target &target);
QVariant createDebugger(const Target &target);
using QnxToolChainMap = std::map<const char*, QnxToolChain*>;
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

View File

@@ -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 <coreplugin/icore.h>
#include <utils/persistentsettings.h>
#include <utils/qtcassert.h>
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<QnxConfiguration *> 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

View File

@@ -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 <utils/fileutils.h>
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<QnxConfiguration*> 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<QnxConfiguration*> m_configurations;
Utils::PersistentSettingsWriter *m_writer;
};
} // Qnx::Internal

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qnxanalyzesupport.h" #include "qnxanalyzesupport.h"
#include "qnxconfigurationmanager.h"
#include "qnxconstants.h" #include "qnxconstants.h"
#include "qnxdebugsupport.h" #include "qnxdebugsupport.h"
#include "qnxdevice.h" #include "qnxdevice.h"
@@ -80,7 +79,7 @@ public:
QAction *m_debugSeparator = nullptr; QAction *m_debugSeparator = nullptr;
QAction m_attachToQnxApplication{Tr::tr("Attach to remote QNX application..."), nullptr}; QAction m_attachToQnxApplication{Tr::tr("Attach to remote QNX application..."), nullptr};
QnxConfigurationManager configurationManager; QnxSettingsPage settingsPage;
QnxQtVersionFactory qtVersionFactory; QnxQtVersionFactory qtVersionFactory;
QnxDeviceFactory deviceFactory; QnxDeviceFactory deviceFactory;
QnxDeployConfigurationFactory deployConfigFactory; QnxDeployConfigurationFactory deployConfigFactory;
@@ -88,7 +87,6 @@ public:
Constants::QNX_DIRECT_UPLOAD_STEP_ID}; Constants::QNX_DIRECT_UPLOAD_STEP_ID};
QnxDeployStepFactory makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId}; QnxDeployStepFactory makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId};
QnxRunConfigurationFactory runConfigFactory; QnxRunConfigurationFactory runConfigFactory;
QnxSettingsPage settingsPage;
QnxToolChainFactory toolChainFactory; QnxToolChainFactory toolChainFactory;
SimpleTargetRunnerFactory runWorkerFactory{{runConfigFactory.runConfigurationId()}}; SimpleTargetRunnerFactory runWorkerFactory{{runConfigFactory.runConfigurationId()}};
QnxDebugWorkerFactory debugWorkerFactory; QnxDebugWorkerFactory debugWorkerFactory;
@@ -112,10 +110,6 @@ private:
void QnxPlugin::extensionsInitialized() void QnxPlugin::extensionsInitialized()
{ {
// Can't do yet as not all devices are around.
connect(DeviceManager::instance(), &DeviceManager::devicesLoaded,
&d->configurationManager, &QnxConfigurationManager::restoreConfigurations);
// Attach support // Attach support
connect(&d->m_attachToQnxApplication, &QAction::triggered, this, &showAttachToProcessDialog); connect(&d->m_attachToQnxApplication, &QAction::triggered, this, &showAttachToProcessDialog);

View File

@@ -3,29 +3,481 @@
#include "qnxsettingspage.h" #include "qnxsettingspage.h"
#include "qnxconfiguration.h" #include "qnxqtversion.h"
#include "qnxconfigurationmanager.h" #include "qnxtoolchain.h"
#include "qnxtr.h" #include "qnxtr.h"
#include "qnxutils.h"
#include "qnxversionnumber.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <debugger/debuggeritem.h>
#include <debugger/debuggeritemmanager.h>
#include <debugger/debuggerkitinformation.h>
#include <projectexplorer/devicesupport/devicemanager.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/kitmanager.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtversionmanager.h> #include <qtsupport/qtversionmanager.h>
#include <qtsupport/qtkitinformation.h>
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
#include <utils/algorithm.h>
#include <utils/layoutbuilder.h> #include <utils/layoutbuilder.h>
#include <utils/persistentsettings.h>
#include <utils/qtcassert.h>
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox> #include <QComboBox>
#include <QDebug>
#include <QDomDocument>
#include <QGroupBox> #include <QGroupBox>
#include <QLabel> #include <QLabel>
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton> #include <QPushButton>
using namespace ProjectExplorer;
using namespace QtSupport;
using namespace Utils; using namespace Utils;
using namespace Debugger;
namespace Qnx::Internal { 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<QnxTarget> 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<DebuggerItem> debuggersToRemove;
const QList<DebuggerItem> debuggerItems = DebuggerItemManager::debuggers();
for (const DebuggerItem &debuggerItem : debuggerItems) {
if (findTargetByDebuggerPath(debuggerItem.command()))
debuggersToRemove.append(debuggerItem);
}
const QList<Kit *> 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<QnxQtVersion *>(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<QnxConfiguration *>(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<FilePath, QnxConfiguration> m_configurations;
PersistentSettingsWriter m_writer{qnxConfigSettingsFileName(), "QnxConfigurations"};
};
static QnxSettingsPagePrivate *dd = nullptr;
// QnxSettingsWidget
class QnxSettingsWidget final : public Core::IOptionsPageWidget class QnxSettingsWidget final : public Core::IOptionsPageWidget
{ {
public: public:
@@ -42,10 +494,10 @@ public:
public: public:
bool operator ==(const ConfigState &cs) const 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; State state;
}; };
@@ -57,7 +509,7 @@ public:
void updateInformation(); void updateInformation();
void populateConfigsCombo(); void populateConfigsCombo();
void setConfigState(QnxConfiguration *config, State state); void setConfigState(const FilePath &envFile, State state);
private: private:
QComboBox *m_configsCombo = new QComboBox; QComboBox *m_configsCombo = new QComboBox;
@@ -67,7 +519,6 @@ private:
QLabel *m_configHost = new QLabel; QLabel *m_configHost = new QLabel;
QLabel *m_configTarget = new QLabel; QLabel *m_configTarget = new QLabel;
QnxConfigurationManager *m_qnxConfigManager = QnxConfigurationManager::instance();
QList<ConfigState> m_changedConfigs; QList<ConfigState> m_changedConfigs;
}; };
@@ -101,6 +552,7 @@ QnxSettingsWidget::QnxSettingsWidget()
}.attachTo(this); }.attachTo(this);
populateConfigsCombo(); populateConfigsCombo();
connect(addButton, &QAbstractButton::clicked, connect(addButton, &QAbstractButton::clicked,
this, &QnxSettingsWidget::addConfiguration); this, &QnxSettingsWidget::addConfiguration);
connect(removeButton, &QAbstractButton::clicked, connect(removeButton, &QAbstractButton::clicked,
@@ -109,17 +561,14 @@ QnxSettingsWidget::QnxSettingsWidget()
this, &QnxSettingsWidget::updateInformation); this, &QnxSettingsWidget::updateInformation);
connect(m_generateKitsCheckBox, &QAbstractButton::toggled, connect(m_generateKitsCheckBox, &QAbstractButton::toggled,
this, &QnxSettingsWidget::generateKits); this, &QnxSettingsWidget::generateKits);
connect(m_qnxConfigManager, &QnxConfigurationManager::configurationsListUpdated, connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
this, &QnxSettingsWidget::populateConfigsCombo);
connect(QtSupport::QtVersionManager::instance(),
&QtSupport::QtVersionManager::qtVersionsChanged,
this, &QnxSettingsWidget::updateInformation); this, &QnxSettingsWidget::updateInformation);
} }
void QnxSettingsWidget::addConfiguration() void QnxSettingsWidget::addConfiguration()
{ {
QString filter; QString filter;
if (Utils::HostOsInfo::isWindowsHost()) if (HostOsInfo::isWindowsHost())
filter = "*.bat file"; filter = "*.bat file";
else else
filter = "*.sh file"; filter = "*.sh file";
@@ -129,82 +578,88 @@ void QnxSettingsWidget::addConfiguration()
if (envFile.isEmpty()) if (envFile.isEmpty())
return; return;
QnxConfiguration *config = new QnxConfiguration(envFile); if (dd->m_configurations.contains(envFile)) {
if (m_qnxConfigManager->configurations().contains(config) || !config->isValid()) {
QMessageBox::warning(Core::ICore::dialogParent(), QMessageBox::warning(Core::ICore::dialogParent(),
Tr::tr("Warning"), Tr::tr("Warning"),
Tr::tr("Configuration already exists or is invalid.")); Tr::tr("Configuration already exists."));
delete config;
return; return;
} }
setConfigState(config, Added); // Temporary to be able to check
m_configsCombo->addItem(config->displayName(), QnxConfiguration config(envFile);
QVariant::fromValue(static_cast<void*>(config))); 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() void QnxSettingsWidget::removeConfiguration()
{ {
const int currentIndex = m_configsCombo->currentIndex(); const FilePath envFile = m_configsCombo->currentData().value<FilePath>();
auto config = static_cast<QnxConfiguration*>( QTC_ASSERT(!envFile.isEmpty(), return);
m_configsCombo->itemData(currentIndex).value<void*>());
if (!config) QnxConfiguration *config = dd->configurationFromEnvFile(envFile);
return; QTC_ASSERT(config, return);
config->ensureContents();
QMessageBox::StandardButton button = QMessageBox::StandardButton button =
QMessageBox::question(Core::ICore::dialogParent(), QMessageBox::question(Core::ICore::dialogParent(),
Tr::tr("Remove QNX Configuration"), 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); QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) { if (button == QMessageBox::Yes) {
setConfigState(config, Removed); setConfigState(envFile, Removed);
m_configsCombo->removeItem(currentIndex); m_configsCombo->removeItem(m_configsCombo->currentIndex());
updateInformation();
} }
} }
void QnxSettingsWidget::generateKits(bool checked) void QnxSettingsWidget::generateKits(bool checked)
{ {
const int currentIndex = m_configsCombo->currentIndex(); const FilePath envFile = m_configsCombo->currentData().value<FilePath>();
auto config = static_cast<QnxConfiguration*>( setConfigState(envFile, checked ? Activated : Deactivated);
m_configsCombo->itemData(currentIndex).value<void*>());
if (!config)
return;
setConfigState(config, checked ? Activated : Deactivated);
} }
void QnxSettingsWidget::updateInformation() void QnxSettingsWidget::updateInformation()
{ {
const int currentIndex = m_configsCombo->currentIndex(); const FilePath envFile = m_configsCombo->currentData().value<FilePath>();
auto config = static_cast<QnxConfiguration*>( if (QnxConfiguration *config = dd->configurationFromEnvFile(envFile)) {
m_configsCombo->itemData(currentIndex).value<void*>()); config->ensureContents();
m_generateKitsCheckBox->setEnabled(config->isValid());
// update the checkbox m_generateKitsCheckBox->setChecked(config->isActive());
m_generateKitsCheckBox->setEnabled(config ? config->isValid() : false); m_configName->setText(config->m_configName);
m_generateKitsCheckBox->setChecked(config ? config->isActive() : false); m_configVersion->setText(config->m_version.toString());
m_configHost->setText(config->m_qnxHost.toString());
// update information m_configTarget->setText(config->m_qnxTarget.toString());
m_configName->setText(config ? config->displayName() : QString()); } else {
m_configVersion->setText(config ? config->version().toString() : QString()); m_generateKitsCheckBox->setEnabled(false);
m_configHost->setText(config ? config->qnxHost().toString() : QString()); m_generateKitsCheckBox->setChecked(false);
m_configTarget->setText(config ? config->qnxTarget().toString() : QString()); m_configName->setText({});
m_configVersion->setText({});
m_configHost->setText({});
m_configTarget->setText({});
}
} }
void QnxSettingsWidget::populateConfigsCombo() void QnxSettingsWidget::populateConfigsCombo()
{ {
m_configsCombo->clear(); m_configsCombo->clear();
const QList<QnxConfiguration *> configList = m_qnxConfigManager->configurations(); for (const QnxConfiguration &config : std::as_const(dd->m_configurations))
for (QnxConfiguration *config : configList) { m_configsCombo->addItem(config.m_configName, QVariant::fromValue(config.m_envFile));
m_configsCombo->addItem(config->displayName(),
QVariant::fromValue(static_cast<void*>(config)));
}
updateInformation(); updateInformation();
} }
void QnxSettingsWidget::setConfigState(QnxConfiguration *config, State state) void QnxSettingsWidget::setConfigState(const FilePath &envFile, State state)
{ {
State stateToRemove = Activated; State stateToRemove = Activated;
switch (state) { switch (state) {
@@ -223,45 +678,79 @@ void QnxSettingsWidget::setConfigState(QnxConfiguration *config, State state)
} }
for (const ConfigState &configState : std::as_const(m_changedConfigs)) { 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.removeAll(configState);
} }
m_changedConfigs.append(ConfigState{config, state}); m_changedConfigs.append(ConfigState{envFile, state});
} }
void QnxSettingsWidget::apply() void QnxSettingsWidget::apply()
{ {
for (const ConfigState &configState : std::as_const(m_changedConfigs)) { for (const ConfigState &configState : std::as_const(m_changedConfigs)) {
switch (configState.state) { switch (configState.state) {
case Activated : case Activated: {
configState.config->activate(); QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile);
QTC_ASSERT(config, break);
config->activate();
break; break;
case Deactivated: }
configState.config->deactivate(); case Deactivated: {
QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile);
QTC_ASSERT(config, break);
config->deactivate();
break; break;
case Added: }
m_qnxConfigManager->addConfiguration(configState.config); case Added: {
QnxConfiguration config(configState.envFile);
config.ensureContents();
dd->m_configurations.insert(configState.envFile, config);
break; break;
}
case Removed: case Removed:
configState.config->deactivate(); QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile);
m_qnxConfigManager->removeConfiguration(configState.config); QTC_ASSERT(config, break);
config->deactivate();
dd->m_configurations.remove(configState.envFile);
break; break;
} }
} }
m_changedConfigs.clear(); m_changedConfigs.clear();
populateConfigsCombo();
} }
// QnxSettingsPage // QnxSettingsPage
QList<ToolChain *> QnxSettingsPage::autoDetect(const QList<ToolChain *> &alreadyKnown)
{
QList<ToolChain *> 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() QnxSettingsPage::QnxSettingsPage()
{ {
setId("DD.Qnx Configuration"); setId("DD.Qnx Configuration");
setDisplayName(Tr::tr("QNX")); setDisplayName(Tr::tr("QNX"));
setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY);
setWidgetCreator([] { return new QnxSettingsWidget; }); setWidgetCreator([] { return new QnxSettingsWidget; });
dd = new QnxSettingsPagePrivate;
}
QnxSettingsPage::~QnxSettingsPage()
{
delete dd;
} }
} // Qnx::Internal } // Qnx::Internal

View File

@@ -5,12 +5,18 @@
#include <coreplugin/dialogs/ioptionspage.h> #include <coreplugin/dialogs/ioptionspage.h>
namespace ProjectExplorer { class ToolChain; }
namespace Qnx::Internal { namespace Qnx::Internal {
class QnxSettingsPage final : public Core::IOptionsPage class QnxSettingsPage final : public Core::IOptionsPage
{ {
public: public:
QnxSettingsPage(); QnxSettingsPage();
~QnxSettingsPage();
static QList<ProjectExplorer::ToolChain *> autoDetect(
const QList<ProjectExplorer::ToolChain *> &alreadyKnown);
}; };
} // Qnx::Internal } // Qnx::Internal

View File

@@ -3,9 +3,8 @@
#include "qnxtoolchain.h" #include "qnxtoolchain.h"
#include "qnxconfiguration.h"
#include "qnxconfigurationmanager.h"
#include "qnxconstants.h" #include "qnxconstants.h"
#include "qnxsettingspage.h"
#include "qnxtr.h" #include "qnxtr.h"
#include "qnxutils.h" #include "qnxutils.h"
@@ -222,10 +221,7 @@ Toolchains QnxToolChainFactory::autoDetect(const ToolchainDetector &detector) co
if (detector.device) if (detector.device)
return {}; return {};
Toolchains tcs; Toolchains tcs = QnxSettingsPage::autoDetect(detector.alreadyKnown);
const auto configurations = QnxConfigurationManager::instance()->configurations();
for (QnxConfiguration *configuration : configurations)
tcs += configuration->autoDetect(detector.alreadyKnown);
return tcs; return tcs;
} }

View File

@@ -16,6 +16,15 @@ using namespace Utils;
namespace Qnx::Internal { 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) QString QnxUtils::cpuDirFromAbi(const Abi &abi)
{ {
if (abi.os() != Abi::OS::QnxOS) if (abi.os() != Abi::OS::QnxOS)

View File

@@ -14,12 +14,14 @@ namespace Qnx::Internal {
class QnxTarget class QnxTarget
{ {
public: public:
QnxTarget(const Utils::FilePath &path, const ProjectExplorer::Abi &abi) : QnxTarget(const Utils::FilePath &path, const ProjectExplorer::Abi &abi);
m_path(path), m_abi(abi)
{ QString shortDescription() const;
} QString cpuDir() const { return m_path.fileName(); }
Utils::FilePath m_path; Utils::FilePath m_path;
ProjectExplorer::Abi m_abi; ProjectExplorer::Abi m_abi;
Utils::FilePath m_debuggerPath;
}; };
namespace QnxUtils { namespace QnxUtils {