Switch QNX tool chains from hard-coded to detected ABIs

Move the target detection code from the QnxConfiguration class into a
separate function that can be used by the QnxConfiguration code and
the QnxToolChain code.

Move some resetToolChain calls after setSdpPath calls.  QNX ABI
detection depends on the SDP path.

Change-Id: I7417a5a1064a77edfb113d9d0010f1e061b81ca6
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
James McDonnell
2016-12-16 12:48:53 -05:00
parent 46e4ecbd44
commit f163cdc9fe
6 changed files with 102 additions and 36 deletions

View File

@@ -267,7 +267,6 @@ QVariant QnxConfiguration::createDebugger(const Target &target)
QnxToolChain *QnxConfiguration::createToolChain(const Target &target) QnxToolChain *QnxConfiguration::createToolChain(const Target &target)
{ {
QnxToolChain *toolChain = new QnxToolChain(ToolChain::AutoDetection); QnxToolChain *toolChain = new QnxToolChain(ToolChain::AutoDetection);
toolChain->resetToolChain(qccCompilerPath());
toolChain->setLanguage(ProjectExplorer::Constants::CXX_LANGUAGE_ID); toolChain->setLanguage(ProjectExplorer::Constants::CXX_LANGUAGE_ID);
toolChain->setTargetAbi(target.m_abi); toolChain->setTargetAbi(target.m_abi);
toolChain->setDisplayName( toolChain->setDisplayName(
@@ -277,6 +276,7 @@ QnxToolChain *QnxConfiguration::createToolChain(const Target &target)
.arg(displayName()) .arg(displayName())
.arg(target.shortDescription())); .arg(target.shortDescription()));
toolChain->setSdpPath(sdpPath().toString()); toolChain->setSdpPath(sdpPath().toString());
toolChain->resetToolChain(qccCompilerPath());
ToolChainManager::registerToolChain(toolChain); ToolChainManager::registerToolChain(toolChain);
return toolChain; return toolChain;
} }
@@ -414,26 +414,9 @@ const QnxConfiguration::Target *QnxConfiguration::findTargetByDebuggerPath(
void QnxConfiguration::updateTargets() void QnxConfiguration::updateTargets()
{ {
m_targets.clear(); m_targets.clear();
QList<QnxTarget> targets = QnxUtils::findTargets(m_qnxTarget);
QDir targetsDir(m_qnxTarget.toString()); for (const auto &target : targets)
QStringList targetNames = targetsDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); m_targets.append(Target(target.m_abi, target.m_path));
foreach (const QString &targetName, targetNames) {
FileName targetPath = FileName(m_qnxTarget).appendPath(targetName);
FileName libc = FileName(targetPath).appendPath("lib/libc.so");
if (libc.exists()) {
QList<Abi> abis = Abi::abisOfBinary(libc);
if (abis.count() > 0) {
if (abis.count() > 1)
qWarning() << libc << "has more than one ABI ... processing all";
foreach (const Abi &abi, abis)
m_targets.append(Target(abi, targetPath));
} else {
qWarning() << libc << "has no ABIs ... discarded";
}
}
}
} }
void QnxConfiguration::assignDebuggersToTargets() void QnxConfiguration::assignDebuggersToTargets()

View File

@@ -103,7 +103,7 @@ private:
class Target class Target
{ {
public: public:
Target(const ProjectExplorer::Abi &abi, Utils::FileName &path) Target(const ProjectExplorer::Abi &abi, const Utils::FileName &path)
: m_abi(abi), m_path(path) : m_abi(abi), m_path(path)
{ {
} }

View File

@@ -30,7 +30,7 @@
#include "qnxutils.h" #include "qnxutils.h"
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <utils/algorithm.h>
#include <utils/pathchooser.h> #include <utils/pathchooser.h>
#include <QFormLayout> #include <QFormLayout>
@@ -43,15 +43,32 @@ namespace Internal {
static const char CompilerSdpPath[] = "Qnx.QnxToolChain.NDKPath"; static const char CompilerSdpPath[] = "Qnx.QnxToolChain.NDKPath";
static const QList<Abi> qccSupportedAbis() static QList<Abi> detectTargetAbis(const FileName &sdpPath)
{ {
QList<Abi> abis; QList<Abi> result;
abis << Abi(Abi::ArmArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32); FileName qnxTarget;
abis << Abi(Abi::ArmArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64);
abis << Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32);
abis << Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64);
return abis; if (!sdpPath.fileName().isEmpty()) {
QList<Utils::EnvironmentItem> environment = QnxUtils::qnxEnvironment(sdpPath.toString());
foreach (const Utils::EnvironmentItem &item, environment) {
if (item.name == QLatin1Literal("QNX_TARGET"))
qnxTarget = FileName::fromString(item.value);
}
}
if (qnxTarget.isEmpty())
return result;
QList<QnxTarget> targets = QnxUtils::findTargets(qnxTarget);
for (const auto &target : targets) {
if (!result.contains(target.m_abi))
result.append(target.m_abi);
}
Utils::sort(result,
[](const Abi &arg1, const Abi &arg2) { return arg1.toString() < arg2.toString(); });
return result;
} }
static void setQnxEnvironment(Environment &env, const QList<EnvironmentItem> &qnxEnv) static void setQnxEnvironment(Environment &env, const QList<EnvironmentItem> &qnxEnv)
@@ -133,10 +150,9 @@ void QnxToolChain::setSdpPath(const QString &sdpPath)
toolChainUpdated(); toolChainUpdated();
} }
// qcc doesn't support a "-dumpmachine" option to get supported abis
GccToolChain::DetectedAbisResult QnxToolChain::detectSupportedAbis() const GccToolChain::DetectedAbisResult QnxToolChain::detectSupportedAbis() const
{ {
return qccSupportedAbis(); return detectTargetAbis(FileName::fromString(m_sdpPath));
} }
// Qcc is a multi-compiler driver, and most of the gcc options can be accomplished by using the -Wp, and -Wc // Qcc is a multi-compiler driver, and most of the gcc options can be accomplished by using the -Wp, and -Wc
@@ -227,8 +243,9 @@ QnxToolChainConfigWidget::QnxToolChainConfigWidget(QnxToolChain *tc)
m_sdpPath->setPath(tc->sdpPath()); m_sdpPath->setPath(tc->sdpPath());
m_sdpPath->setEnabled(!tc->isAutoDetected()); m_sdpPath->setEnabled(!tc->isAutoDetected());
m_abiWidget->setAbis(qccSupportedAbis(), tc->targetAbi()); QList<Abi> abiList = detectTargetAbis(m_sdpPath->fileName());
m_abiWidget->setEnabled(!tc->isAutoDetected()); m_abiWidget->setAbis(abiList, tc->targetAbi());
m_abiWidget->setEnabled(!tc->isAutoDetected() && !abiList.isEmpty());
m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand); m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
//: SDP refers to 'Software Development Platform'. //: SDP refers to 'Software Development Platform'.
@@ -236,7 +253,8 @@ QnxToolChainConfigWidget::QnxToolChainConfigWidget(QnxToolChain *tc)
m_mainLayout->addRow(tr("&ABI:"), m_abiWidget); m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
connect(m_compilerCommand, &PathChooser::rawPathChanged, this, &ToolChainConfigWidget::dirty); connect(m_compilerCommand, &PathChooser::rawPathChanged, this, &ToolChainConfigWidget::dirty);
connect(m_sdpPath, &PathChooser::rawPathChanged, this, &ToolChainConfigWidget::dirty); connect(m_sdpPath, &PathChooser::rawPathChanged,
this, &QnxToolChainConfigWidget::handleSdpPathChange);
connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolChainConfigWidget::dirty); connect(m_abiWidget, &AbiWidget::abiChanged, this, &ToolChainConfigWidget::dirty);
} }
@@ -248,10 +266,10 @@ void QnxToolChainConfigWidget::applyImpl()
QnxToolChain *tc = static_cast<QnxToolChain *>(toolChain()); QnxToolChain *tc = static_cast<QnxToolChain *>(toolChain());
Q_ASSERT(tc); Q_ASSERT(tc);
QString displayName = tc->displayName(); QString displayName = tc->displayName();
tc->resetToolChain(m_compilerCommand->fileName());
tc->setDisplayName(displayName); // reset display name tc->setDisplayName(displayName); // reset display name
tc->setSdpPath(m_sdpPath->fileName().toString()); tc->setSdpPath(m_sdpPath->fileName().toString());
tc->setTargetAbi(m_abiWidget->currentAbi()); tc->setTargetAbi(m_abiWidget->currentAbi());
tc->resetToolChain(m_compilerCommand->fileName());
} }
void QnxToolChainConfigWidget::discardImpl() void QnxToolChainConfigWidget::discardImpl()
@@ -276,5 +294,24 @@ bool QnxToolChainConfigWidget::isDirtyImpl() const
|| m_abiWidget->currentAbi() != tc->targetAbi(); || m_abiWidget->currentAbi() != tc->targetAbi();
} }
void QnxToolChainConfigWidget::handleSdpPathChange()
{
Abi currentAbi = m_abiWidget->currentAbi();
bool customAbi = m_abiWidget->isCustomAbi();
QList<Abi> abiList = detectTargetAbis(m_sdpPath->fileName());
m_abiWidget->setEnabled(!abiList.isEmpty());
// Find a good ABI for the new compiler:
Abi newAbi;
if (customAbi)
newAbi = currentAbi;
else if (abiList.contains(currentAbi))
newAbi = currentAbi;
m_abiWidget->setAbis(abiList, newAbi);
emit dirty();
}
} // namespace Internal } // namespace Internal
} // namespace Qnx } // namespace Qnx

View File

@@ -99,6 +99,8 @@ private:
bool isDirtyImpl() const override; bool isDirtyImpl() const override;
void makeReadOnlyImpl() override { } void makeReadOnlyImpl() override { }
void handleSdpPathChange();
Utils::PathChooser *m_compilerCommand; Utils::PathChooser *m_compilerCommand;
Utils::PathChooser *m_sdpPath; Utils::PathChooser *m_sdpPath;
ProjectExplorer::AbiWidget *m_abiWidget; ProjectExplorer::AbiWidget *m_abiWidget;

View File

@@ -26,11 +26,14 @@
#include "qnxutils.h" #include "qnxutils.h"
#include "qnxqtversion.h" #include "qnxqtversion.h"
#include <utils/fileutils.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h> #include <utils/temporaryfile.h>
#include <QDebug>
#include <QDir> #include <QDir>
#include <QDirIterator>
#include <QDomDocument> #include <QDomDocument>
#include <QProcess> #include <QProcess>
#include <QStandardPaths> #include <QStandardPaths>
@@ -227,3 +230,31 @@ QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironment(const QString &sdpPath)
{ {
return qnxEnvironmentFromEnvFile(envFilePath(sdpPath)); return qnxEnvironmentFromEnvFile(envFilePath(sdpPath));
} }
QList<QnxTarget> QnxUtils::findTargets(const Utils::FileName &basePath)
{
using namespace Utils;
QList<QnxTarget> result;
QDirIterator iterator(basePath.toString());
while (iterator.hasNext()) {
iterator.next();
FileName libc = FileName::fromString(iterator.filePath()).appendPath("lib/libc.so");
if (libc.exists()) {
auto abis = Abi::abisOfBinary(libc);
if (abis.isEmpty()) {
qWarning() << libc << "has no ABIs ... discarded";
continue;
}
if (abis.count() > 1)
qWarning() << libc << "has more than one ABI ... processing all";
FileName path = FileName::fromString(iterator.filePath());
for (auto abi : abis)
result.append(QnxTarget(path, abi));
}
}
return result;
}

View File

@@ -27,6 +27,7 @@
#include "qnxconstants.h" #include "qnxconstants.h"
#include <projectexplorer/abi.h>
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
@@ -53,6 +54,17 @@ public:
&& !target.isEmpty() && !version.isEmpty() && !installationXmlFilePath.isEmpty(); } && !target.isEmpty() && !version.isEmpty() && !installationXmlFilePath.isEmpty(); }
}; };
class QnxTarget
{
public:
QnxTarget(const Utils::FileName &path, const ProjectExplorer::Abi &abi) :
m_path(path), m_abi(abi)
{
}
Utils::FileName m_path;
ProjectExplorer::Abi m_abi;
};
class QnxUtils class QnxUtils
{ {
public: public:
@@ -64,6 +76,7 @@ public:
static QString defaultTargetVersion(const QString &sdpPath); static QString defaultTargetVersion(const QString &sdpPath);
static QList<ConfigInstallInformation> installedConfigs(const QString &configPath = QString()); static QList<ConfigInstallInformation> installedConfigs(const QString &configPath = QString());
static QList<Utils::EnvironmentItem> qnxEnvironment(const QString &sdpPath); static QList<Utils::EnvironmentItem> qnxEnvironment(const QString &sdpPath);
static QList<QnxTarget> findTargets(const Utils::FileName &basePath);
}; };
} // namespace Internal } // namespace Internal