From 5a2001f730b78a4f71ee883c1e33c1ef0c1a4531 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 24 Oct 2016 15:53:37 +0200 Subject: [PATCH] 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 --- src/plugins/android/androidconfigurations.cpp | 86 +++++++++++-------- src/plugins/android/androidconfigurations.h | 6 +- src/plugins/android/androidsettingswidget.cpp | 18 ++-- src/plugins/android/androidtoolchain.cpp | 62 +++++++------ src/plugins/android/androidtoolchain.h | 4 +- 5 files changed, 97 insertions(+), 79 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 191555b948b..e68f0f3473e 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -507,9 +507,12 @@ FileName AndroidConfig::toolPath(const Abi &abi, const QString &ndkToolChainVers .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 @@ -1198,24 +1201,32 @@ QString AndroidConfigurations::defaultDevice(Project *project, const QString &ab 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(atc); + auto abtc = static_cast(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)) return false; - ToolChain *atc = ToolChainKitInformation::toolChain(a, ToolChain::Language::Cxx); - ToolChain *btc = ToolChainKitInformation::toolChain(b, ToolChain::Language::Cxx); - if (atc == btc) - return true; - if (!atc || atc->typeId() != Constants::ANDROID_TOOLCHAIN_ID) - return false; - if (!btc || btc->typeId() != Constants::ANDROID_TOOLCHAIN_ID) - return false; - AndroidToolChain *aatc = static_cast(atc); - AndroidToolChain *bbtc = static_cast(btc); - if (aatc->ndkToolChainVersion() == bbtc->ndkToolChainVersion() - && aatc->targetAbi() == bbtc->targetAbi()) - return true; - return false; + + return matchToolChain(ToolChainKitInformation::toolChain(a, ToolChain::Language::Cxx), + ToolChainKitInformation::toolChain(b, ToolChain::Language::Cxx)) + && matchToolChain(ToolChainKitInformation::toolChain(a, ToolChain::Language::C), + ToolChainKitInformation::toolChain(b, ToolChain::Language::C)); } void AndroidConfigurations::registerNewToolChains() @@ -1243,23 +1254,7 @@ void AndroidConfigurations::removeOldToolChains() void AndroidConfigurations::updateAutomaticKitList() { - QList 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(tc); - } - } - QList existingKits; - foreach (Kit *k, KitManager::kits()) { if (DeviceTypeKitInformation::deviceTypeId(k) != Core::Id(Constants::ANDROID_DEVICE_TYPE)) continue; @@ -1305,15 +1300,29 @@ void AndroidConfigurations::updateAutomaticKitList() // register new kits QList newKits; - foreach (AndroidToolChain *tc, toolchains) { - if (tc->isSecondaryToolChain()) + const QList tmp = Utils::filtered(ToolChainManager::toolChains(), [](ToolChain *tc) { + return tc->isAutoDetected() + && tc->isValid() + && tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID + && !static_cast(tc)->isSecondaryToolChain(); + }); + const QList toolchains = Utils::transform(tmp, [](ToolChain *tc) { + return static_cast(tc); + }); + for (AndroidToolChain *tc : toolchains) { + if (tc->isSecondaryToolChain() || tc->language() != ToolChain::Language::Cxx) continue; + const QList allLanguages = Utils::filtered(toolchains, + [tc](AndroidToolChain *otherTc) { + return tc->targetAbi() == otherTc->targetAbi(); + }); QList qtVersions = qtVersionsForArch.value(tc->targetAbi()); foreach (QtSupport::BaseQtVersion *qt, qtVersions) { Kit *newKit = new Kit; newKit->setAutoDetected(true); 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); DeviceKitInformation::setDevice(newKit, device); @@ -1337,12 +1346,13 @@ void AndroidConfigurations::updateAutomaticKitList() Kit *existingKit = existingKits.at(i); for (int j = 0; j < newKits.count(); ++j) { Kit *newKit = newKits.at(j); - if (equalKits(existingKit, newKit)) { + if (matchKits(existingKit, newKit)) { // Kit is already registered, nothing to do newKits.removeAt(j); existingKits.at(i)->makeSticky(); 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); j = newKits.count(); } diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 6a73c766951..1f6b2f6d07e 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -27,6 +27,8 @@ #include "android_global.h" +#include + #include #include #include @@ -126,7 +128,9 @@ public: 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 keytoolPath() const; diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 50befd044fc..f5bafe43feb 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -314,6 +314,8 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode) // Check for a gdb with a broken python QStringList gdbPaths; foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) { + if (ati.language == ProjectExplorer::ToolChain::Language::C) + continue; // we only check the arm gdbs, that's indicative enough if (ati.abi.architecture() != ProjectExplorer::Abi::ArmArchitecture) continue; @@ -329,8 +331,10 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode) // See if we have qt versions for those toolchains QSet toolchainsForAbi; - foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) - toolchainsForAbi.insert(ati.abi); + foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) { + if (ati.language == ProjectExplorer::ToolChain::Language::Cxx) + toolchainsForAbi.insert(ati.abi); + } QSet qtVersionsForAbi; foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::unsortedVersions()) { @@ -496,16 +500,6 @@ void AndroidSettingsWidget::saveSettings() AndroidConfigurations::setConfig(m_androidConfig); } -int indexOf(const QList &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() { m_androidConfig.setSdkLocation(Utils::FileName::fromUserInput(m_ui->SDKLocationPathChooser->rawPath())); diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index f89b6330715..6794d85d3e1 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -302,16 +302,17 @@ QList AndroidToolChainFact int idx = versionRegExp.indexIn(fileName); if (idx == -1) continue; - AndroidToolChainInformation ati; - ati.version = fileName.mid(idx + 1); - QString platform = fileName.left(idx); - ati.abi = AndroidConfig::abiForToolChainPrefix(platform); - if (ati.abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported - continue; - // AndroidToolChain *tc = new AndroidToolChain(arch, version, true); - ati.compilerCommand = AndroidConfigurations::currentConfig().gccPath(ati.abi, ati.version); - // tc->setCompilerCommand(compilerPath); - result.append(ati); + for (const ToolChain::Language lang : { ToolChain::Language::Cxx, ToolChain::Language::C }) { + AndroidToolChainInformation ati; + ati.language = lang; + ati.version = fileName.mid(idx + 1); + QString platform = fileName.left(idx); + ati.abi = AndroidConfig::abiForToolChainPrefix(platform); + if (ati.abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported + continue; + ati.compilerCommand = AndroidConfigurations::currentConfig().gccPath(ati.abi, lang, ati.version); + result.append(ati); + } } return result; } @@ -353,19 +354,22 @@ bool AndroidToolChainFactory::versionCompareLess(const QList &a, const QLis return false; } -bool AndroidToolChainFactory::versionCompareLess(AndroidToolChain *atc, AndroidToolChain *btc) +bool AndroidToolChainFactory::versionCompareLess(QList atc, + QList btc) { - QList a = versionNumberFromString(atc->ndkToolChainVersion()); - QList b = versionNumberFromString(btc->ndkToolChainVersion()); + const QList a = versionNumberFromString(atc.at(0)->ndkToolChainVersion()); + const QList b = versionNumberFromString(btc.at(0)->ndkToolChainVersion()); return versionCompareLess(a, b); } -static AndroidToolChain *findToolChain(Utils::FileName &compilerPath, const QList &alreadyKnown) +static AndroidToolChain *findToolChain(Utils::FileName &compilerPath, ToolChain::Language lang, + const QList &alreadyKnown) { return static_cast( - Utils::findOrDefault(alreadyKnown, [compilerPath](ToolChain *tc) { + Utils::findOrDefault(alreadyKnown, [compilerPath, lang](ToolChain *tc) { return tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID + && tc->language() == lang && tc->compilerCommand() == compilerPath; })); } @@ -382,7 +386,7 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath, FileName path = ndkPath; QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), QStringList() << QLatin1String("*"), QDir::Dirs); - QHash newestToolChainForArch; + QHash> newestToolChainForArch; while (it.hasNext()) { const QString &fileName = FileName::fromString(it.next()).fileName(); @@ -394,26 +398,30 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath, Abi abi = AndroidConfig::abiForToolChainPrefix(platform); if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported continue; - FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, version); + QList toolChainBundle; + for (ToolChain::Language lang : { ToolChain::Language::Cxx, ToolChain::Language::C }) { + FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, lang, version); - AndroidToolChain *tc = findToolChain(compilerPath, alreadyKnown); - if (!tc) { - tc = new AndroidToolChain(abi, version, ToolChain::Language::Cxx, - ToolChain::AutoDetection); - tc->resetToolChain(compilerPath); + AndroidToolChain *tc = findToolChain(compilerPath, lang, alreadyKnown); + if (!tc) { + tc = new AndroidToolChain(abi, version, lang, + ToolChain::AutoDetection); + tc->resetToolChain(compilerPath); + } + result.append(tc); + toolChainBundle.append(tc); } - result.append(tc); auto it = newestToolChainForArch.constFind(abi); if (it == newestToolChainForArch.constEnd()) - newestToolChainForArch.insert(abi, tc); - else if (versionCompareLess(it.value(), tc)) - newestToolChainForArch[abi] = tc; + newestToolChainForArch.insert(abi, toolChainBundle); + else if (versionCompareLess(it.value(), toolChainBundle)) + newestToolChainForArch[abi] = toolChainBundle; } foreach (ToolChain *tc, result) { AndroidToolChain *atc = static_cast(tc); - atc->setSecondaryToolChain(newestToolChainForArch.value(atc->targetAbi()) != atc); + atc->setSecondaryToolChain(!newestToolChainForArch.value(atc->targetAbi()).contains(atc)); } return result; diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h index 5fd58532f2e..fecfe070fcf 100644 --- a/src/plugins/android/androidtoolchain.h +++ b/src/plugins/android/androidtoolchain.h @@ -104,6 +104,7 @@ public: class AndroidToolChainInformation { public: + ProjectExplorer::ToolChain::Language language; Utils::FileName compilerCommand; ProjectExplorer::Abi abi; QString version; @@ -116,7 +117,8 @@ public: static QList versionNumberFromString(const QString &version); static bool versionCompareLess(const QList &a, const QList &b); - static bool versionCompareLess(AndroidToolChain *atc, AndroidToolChain *btc); + static bool versionCompareLess(QList atc, + QList btc); static QList newestToolChainVersionForArch(const ProjectExplorer::Abi &abi); private: static QHash > m_newestVersionForAbi;