Android: Add C toolchains

This should fix kits complaining about wrongly set C compilers and
ABI incompatibility between C and C++ compilers.

Task-number: QTCREATORBUG-17165
Task-number: QTCREATORBUG-17166
Change-Id: Ia002490b471e0f5306c3a76b27158869920452ed
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
Tobias Hunger
2016-10-24 15:53:37 +02:00
parent c777bd32bc
commit 5a2001f730
5 changed files with 97 additions and 79 deletions

View File

@@ -507,9 +507,12 @@ FileName AndroidConfig::toolPath(const Abi &abi, const QString &ndkToolChainVers
.arg(toolsPrefix(abi))); .arg(toolsPrefix(abi)));
} }
FileName AndroidConfig::gccPath(const Abi &abi, const QString &ndkToolChainVersion) const FileName AndroidConfig::gccPath(const Abi &abi, ToolChain::Language lang,
const QString &ndkToolChainVersion) const
{ {
return toolPath(abi, ndkToolChainVersion).appendString(QLatin1String("-gcc" QTC_HOST_EXE_SUFFIX)); const QString tool
= HostOsInfo::withExecutableSuffix(QString::fromLatin1(lang == ToolChain::Language::C ? "-gcc" : "-g++"));
return toolPath(abi, ndkToolChainVersion).appendString(tool);
} }
FileName AndroidConfig::gdbPath(const Abi &abi, const QString &ndkToolChainVersion) const FileName AndroidConfig::gdbPath(const Abi &abi, const QString &ndkToolChainVersion) const
@@ -1198,24 +1201,32 @@ QString AndroidConfigurations::defaultDevice(Project *project, const QString &ab
return map.value(abi); return map.value(abi);
} }
static bool equalKits(Kit *a, Kit *b) static bool matchToolChain(const ToolChain *atc, const ToolChain *btc)
{
if (atc == btc)
return true;
if (!atc || !btc)
return false;
if (atc->typeId() != Constants::ANDROID_TOOLCHAIN_ID || btc->typeId() != Constants::ANDROID_TOOLCHAIN_ID)
return false;
auto aatc = static_cast<const AndroidToolChain *>(atc);
auto abtc = static_cast<const AndroidToolChain *>(btc);
return aatc->ndkToolChainVersion() == abtc->ndkToolChainVersion()
&& aatc->targetAbi() == abtc->targetAbi();
}
static bool matchKits(const Kit *a, const Kit *b)
{ {
if (QtSupport::QtKitInformation::qtVersion(a) != QtSupport::QtKitInformation::qtVersion(b)) if (QtSupport::QtKitInformation::qtVersion(a) != QtSupport::QtKitInformation::qtVersion(b))
return false; return false;
ToolChain *atc = ToolChainKitInformation::toolChain(a, ToolChain::Language::Cxx);
ToolChain *btc = ToolChainKitInformation::toolChain(b, ToolChain::Language::Cxx); return matchToolChain(ToolChainKitInformation::toolChain(a, ToolChain::Language::Cxx),
if (atc == btc) ToolChainKitInformation::toolChain(b, ToolChain::Language::Cxx))
return true; && matchToolChain(ToolChainKitInformation::toolChain(a, ToolChain::Language::C),
if (!atc || atc->typeId() != Constants::ANDROID_TOOLCHAIN_ID) ToolChainKitInformation::toolChain(b, ToolChain::Language::C));
return false;
if (!btc || btc->typeId() != Constants::ANDROID_TOOLCHAIN_ID)
return false;
AndroidToolChain *aatc = static_cast<AndroidToolChain *>(atc);
AndroidToolChain *bbtc = static_cast<AndroidToolChain *>(btc);
if (aatc->ndkToolChainVersion() == bbtc->ndkToolChainVersion()
&& aatc->targetAbi() == bbtc->targetAbi())
return true;
return false;
} }
void AndroidConfigurations::registerNewToolChains() void AndroidConfigurations::registerNewToolChains()
@@ -1243,23 +1254,7 @@ void AndroidConfigurations::removeOldToolChains()
void AndroidConfigurations::updateAutomaticKitList() void AndroidConfigurations::updateAutomaticKitList()
{ {
QList<AndroidToolChain *> toolchains;
if (AndroidConfigurations::currentConfig().automaticKitCreation()) {
// having a empty toolchains list will remove all autodetected kits for android
// exactly what we want in that case
foreach (ToolChain *tc, ToolChainManager::toolChains()) {
if (!tc->isAutoDetected())
continue;
if (tc->typeId() != Constants::ANDROID_TOOLCHAIN_ID)
continue;
if (!tc->isValid()) // going to be deleted
continue;
toolchains << static_cast<AndroidToolChain *>(tc);
}
}
QList<Kit *> existingKits; QList<Kit *> existingKits;
foreach (Kit *k, KitManager::kits()) { foreach (Kit *k, KitManager::kits()) {
if (DeviceTypeKitInformation::deviceTypeId(k) != Core::Id(Constants::ANDROID_DEVICE_TYPE)) if (DeviceTypeKitInformation::deviceTypeId(k) != Core::Id(Constants::ANDROID_DEVICE_TYPE))
continue; continue;
@@ -1305,15 +1300,29 @@ void AndroidConfigurations::updateAutomaticKitList()
// register new kits // register new kits
QList<Kit *> newKits; QList<Kit *> newKits;
foreach (AndroidToolChain *tc, toolchains) { const QList<ToolChain *> tmp = Utils::filtered(ToolChainManager::toolChains(), [](ToolChain *tc) {
if (tc->isSecondaryToolChain()) return tc->isAutoDetected()
&& tc->isValid()
&& tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID
&& !static_cast<AndroidToolChain *>(tc)->isSecondaryToolChain();
});
const QList<AndroidToolChain *> toolchains = Utils::transform(tmp, [](ToolChain *tc) {
return static_cast<AndroidToolChain *>(tc);
});
for (AndroidToolChain *tc : toolchains) {
if (tc->isSecondaryToolChain() || tc->language() != ToolChain::Language::Cxx)
continue; continue;
const QList<AndroidToolChain *> allLanguages = Utils::filtered(toolchains,
[tc](AndroidToolChain *otherTc) {
return tc->targetAbi() == otherTc->targetAbi();
});
QList<QtSupport::BaseQtVersion *> qtVersions = qtVersionsForArch.value(tc->targetAbi()); QList<QtSupport::BaseQtVersion *> qtVersions = qtVersionsForArch.value(tc->targetAbi());
foreach (QtSupport::BaseQtVersion *qt, qtVersions) { foreach (QtSupport::BaseQtVersion *qt, qtVersions) {
Kit *newKit = new Kit; Kit *newKit = new Kit;
newKit->setAutoDetected(true); newKit->setAutoDetected(true);
DeviceTypeKitInformation::setDeviceTypeId(newKit, Core::Id(Constants::ANDROID_DEVICE_TYPE)); DeviceTypeKitInformation::setDeviceTypeId(newKit, Core::Id(Constants::ANDROID_DEVICE_TYPE));
ToolChainKitInformation::setToolChain(newKit, tc); for (AndroidToolChain *tc : allLanguages)
ToolChainKitInformation::setToolChain(newKit, tc);
QtSupport::QtKitInformation::setQtVersion(newKit, qt); QtSupport::QtKitInformation::setQtVersion(newKit, qt);
DeviceKitInformation::setDevice(newKit, device); DeviceKitInformation::setDevice(newKit, device);
@@ -1337,12 +1346,13 @@ void AndroidConfigurations::updateAutomaticKitList()
Kit *existingKit = existingKits.at(i); Kit *existingKit = existingKits.at(i);
for (int j = 0; j < newKits.count(); ++j) { for (int j = 0; j < newKits.count(); ++j) {
Kit *newKit = newKits.at(j); Kit *newKit = newKits.at(j);
if (equalKits(existingKit, newKit)) { if (matchKits(existingKit, newKit)) {
// Kit is already registered, nothing to do // Kit is already registered, nothing to do
newKits.removeAt(j); newKits.removeAt(j);
existingKits.at(i)->makeSticky(); existingKits.at(i)->makeSticky();
existingKits.removeAt(i); existingKits.removeAt(i);
ToolChainKitInformation::setToolChain(existingKit, ToolChainKitInformation::toolChain(newKit, ToolChain::Language::Cxx)); for (ToolChain::Language lang : ToolChain::allLanguages())
ToolChainKitInformation::setToolChain(existingKit, ToolChainKitInformation::toolChain(newKit, lang));
KitManager::deleteKit(newKit); KitManager::deleteKit(newKit);
j = newKits.count(); j = newKits.count();
} }

View File

@@ -27,6 +27,8 @@
#include "android_global.h" #include "android_global.h"
#include <projectexplorer/toolchain.h>
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
@@ -126,7 +128,9 @@ public:
Utils::FileName emulatorToolPath() const; Utils::FileName emulatorToolPath() const;
Utils::FileName gccPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const; Utils::FileName gccPath(const ProjectExplorer::Abi &abi,
ProjectExplorer::ToolChain::Language lang,
const QString &ndkToolChainVersion) const;
Utils::FileName gdbPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const; Utils::FileName gdbPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const;
Utils::FileName keytoolPath() const; Utils::FileName keytoolPath() const;

View File

@@ -314,6 +314,8 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode)
// Check for a gdb with a broken python // Check for a gdb with a broken python
QStringList gdbPaths; QStringList gdbPaths;
foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) { foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) {
if (ati.language == ProjectExplorer::ToolChain::Language::C)
continue;
// we only check the arm gdbs, that's indicative enough // we only check the arm gdbs, that's indicative enough
if (ati.abi.architecture() != ProjectExplorer::Abi::ArmArchitecture) if (ati.abi.architecture() != ProjectExplorer::Abi::ArmArchitecture)
continue; continue;
@@ -329,8 +331,10 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode)
// See if we have qt versions for those toolchains // See if we have qt versions for those toolchains
QSet<ProjectExplorer::Abi> toolchainsForAbi; QSet<ProjectExplorer::Abi> toolchainsForAbi;
foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) {
toolchainsForAbi.insert(ati.abi); if (ati.language == ProjectExplorer::ToolChain::Language::Cxx)
toolchainsForAbi.insert(ati.abi);
}
QSet<ProjectExplorer::Abi> qtVersionsForAbi; QSet<ProjectExplorer::Abi> qtVersionsForAbi;
foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::unsortedVersions()) { foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::unsortedVersions()) {
@@ -496,16 +500,6 @@ void AndroidSettingsWidget::saveSettings()
AndroidConfigurations::setConfig(m_androidConfig); AndroidConfigurations::setConfig(m_androidConfig);
} }
int indexOf(const QList<AndroidToolChainFactory::AndroidToolChainInformation> &list, const Utils::FileName &f)
{
int end = list.count();
for (int i = 0; i < end; ++i) {
if (list.at(i).compilerCommand == f)
return i;
}
return -1;
}
void AndroidSettingsWidget::sdkLocationEditingFinished() void AndroidSettingsWidget::sdkLocationEditingFinished()
{ {
m_androidConfig.setSdkLocation(Utils::FileName::fromUserInput(m_ui->SDKLocationPathChooser->rawPath())); m_androidConfig.setSdkLocation(Utils::FileName::fromUserInput(m_ui->SDKLocationPathChooser->rawPath()));

View File

@@ -302,16 +302,17 @@ QList<AndroidToolChainFactory::AndroidToolChainInformation> AndroidToolChainFact
int idx = versionRegExp.indexIn(fileName); int idx = versionRegExp.indexIn(fileName);
if (idx == -1) if (idx == -1)
continue; continue;
AndroidToolChainInformation ati; for (const ToolChain::Language lang : { ToolChain::Language::Cxx, ToolChain::Language::C }) {
ati.version = fileName.mid(idx + 1); AndroidToolChainInformation ati;
QString platform = fileName.left(idx); ati.language = lang;
ati.abi = AndroidConfig::abiForToolChainPrefix(platform); ati.version = fileName.mid(idx + 1);
if (ati.abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported QString platform = fileName.left(idx);
continue; ati.abi = AndroidConfig::abiForToolChainPrefix(platform);
// AndroidToolChain *tc = new AndroidToolChain(arch, version, true); if (ati.abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
ati.compilerCommand = AndroidConfigurations::currentConfig().gccPath(ati.abi, ati.version); continue;
// tc->setCompilerCommand(compilerPath); ati.compilerCommand = AndroidConfigurations::currentConfig().gccPath(ati.abi, lang, ati.version);
result.append(ati); result.append(ati);
}
} }
return result; return result;
} }
@@ -353,19 +354,22 @@ bool AndroidToolChainFactory::versionCompareLess(const QList<int> &a, const QLis
return false; return false;
} }
bool AndroidToolChainFactory::versionCompareLess(AndroidToolChain *atc, AndroidToolChain *btc) bool AndroidToolChainFactory::versionCompareLess(QList<AndroidToolChain *> atc,
QList<AndroidToolChain *> btc)
{ {
QList<int> a = versionNumberFromString(atc->ndkToolChainVersion()); const QList<int> a = versionNumberFromString(atc.at(0)->ndkToolChainVersion());
QList<int> b = versionNumberFromString(btc->ndkToolChainVersion()); const QList<int> b = versionNumberFromString(btc.at(0)->ndkToolChainVersion());
return versionCompareLess(a, b); return versionCompareLess(a, b);
} }
static AndroidToolChain *findToolChain(Utils::FileName &compilerPath, const QList<ToolChain *> &alreadyKnown) static AndroidToolChain *findToolChain(Utils::FileName &compilerPath, ToolChain::Language lang,
const QList<ToolChain *> &alreadyKnown)
{ {
return static_cast<AndroidToolChain *>( return static_cast<AndroidToolChain *>(
Utils::findOrDefault(alreadyKnown, [compilerPath](ToolChain *tc) { Utils::findOrDefault(alreadyKnown, [compilerPath, lang](ToolChain *tc) {
return tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID return tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID
&& tc->language() == lang
&& tc->compilerCommand() == compilerPath; && tc->compilerCommand() == compilerPath;
})); }));
} }
@@ -382,7 +386,7 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath,
FileName path = ndkPath; FileName path = ndkPath;
QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(),
QStringList() << QLatin1String("*"), QDir::Dirs); QStringList() << QLatin1String("*"), QDir::Dirs);
QHash<Abi, AndroidToolChain *> newestToolChainForArch; QHash<Abi, QList<AndroidToolChain *>> newestToolChainForArch;
while (it.hasNext()) { while (it.hasNext()) {
const QString &fileName = FileName::fromString(it.next()).fileName(); const QString &fileName = FileName::fromString(it.next()).fileName();
@@ -394,26 +398,30 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath,
Abi abi = AndroidConfig::abiForToolChainPrefix(platform); Abi abi = AndroidConfig::abiForToolChainPrefix(platform);
if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
continue; continue;
FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, version); QList<AndroidToolChain *> toolChainBundle;
for (ToolChain::Language lang : { ToolChain::Language::Cxx, ToolChain::Language::C }) {
FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, lang, version);
AndroidToolChain *tc = findToolChain(compilerPath, alreadyKnown); AndroidToolChain *tc = findToolChain(compilerPath, lang, alreadyKnown);
if (!tc) { if (!tc) {
tc = new AndroidToolChain(abi, version, ToolChain::Language::Cxx, tc = new AndroidToolChain(abi, version, lang,
ToolChain::AutoDetection); ToolChain::AutoDetection);
tc->resetToolChain(compilerPath); tc->resetToolChain(compilerPath);
}
result.append(tc);
toolChainBundle.append(tc);
} }
result.append(tc);
auto it = newestToolChainForArch.constFind(abi); auto it = newestToolChainForArch.constFind(abi);
if (it == newestToolChainForArch.constEnd()) if (it == newestToolChainForArch.constEnd())
newestToolChainForArch.insert(abi, tc); newestToolChainForArch.insert(abi, toolChainBundle);
else if (versionCompareLess(it.value(), tc)) else if (versionCompareLess(it.value(), toolChainBundle))
newestToolChainForArch[abi] = tc; newestToolChainForArch[abi] = toolChainBundle;
} }
foreach (ToolChain *tc, result) { foreach (ToolChain *tc, result) {
AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc); AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
atc->setSecondaryToolChain(newestToolChainForArch.value(atc->targetAbi()) != atc); atc->setSecondaryToolChain(!newestToolChainForArch.value(atc->targetAbi()).contains(atc));
} }
return result; return result;

View File

@@ -104,6 +104,7 @@ public:
class AndroidToolChainInformation class AndroidToolChainInformation
{ {
public: public:
ProjectExplorer::ToolChain::Language language;
Utils::FileName compilerCommand; Utils::FileName compilerCommand;
ProjectExplorer::Abi abi; ProjectExplorer::Abi abi;
QString version; QString version;
@@ -116,7 +117,8 @@ public:
static QList<int> versionNumberFromString(const QString &version); static QList<int> versionNumberFromString(const QString &version);
static bool versionCompareLess(const QList<int> &a, const QList<int> &b); static bool versionCompareLess(const QList<int> &a, const QList<int> &b);
static bool versionCompareLess(AndroidToolChain *atc, AndroidToolChain *btc); static bool versionCompareLess(QList<AndroidToolChain *> atc,
QList<AndroidToolChain *> btc);
static QList<int> newestToolChainVersionForArch(const ProjectExplorer::Abi &abi); static QList<int> newestToolChainVersionForArch(const ProjectExplorer::Abi &abi);
private: private:
static QHash<ProjectExplorer::Abi, QList<int> > m_newestVersionForAbi; static QHash<ProjectExplorer::Abi, QList<int> > m_newestVersionForAbi;