From cb48e4854aaade6216ffca4060885a8ce16367d7 Mon Sep 17 00:00:00 2001
From: Daniel Teske <daniel.teske@theqtcompany.com>
Date: Tue, 18 Nov 2014 18:37:05 +0100
Subject: [PATCH] Android 64bit toolchains

Change-Id: Ia2b57013b392237434ea3649c4f60a671e84ceb5
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
Reviewed-by: BogDan Vatra <bogdan@kde.org>
---
 src/plugins/android/androidconfigurations.cpp | 99 ++++++++++++++-----
 src/plugins/android/androidconfigurations.h   | 13 +--
 src/plugins/android/androidsettingswidget.cpp | 23 ++---
 src/plugins/android/androidtoolchain.cpp      | 69 +++++++------
 src/plugins/android/androidtoolchain.h        |  8 +-
 src/plugins/projectexplorer/abi.cpp           |  3 +
 src/plugins/projectexplorer/abi.h             | 10 ++
 7 files changed, 143 insertions(+), 82 deletions(-)

diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp
index a8b77a3ffef..9e74f386246 100644
--- a/src/plugins/android/androidconfigurations.cpp
+++ b/src/plugins/android/androidconfigurations.cpp
@@ -90,12 +90,25 @@ namespace {
     const QLatin1String DefaultDevice("DefaultDevice");
     const QLatin1String PartitionSizeKey("PartitionSize");
     const QLatin1String ToolchainHostKey("ToolchainHost");
+
     const QLatin1String ArmToolchainPrefix("arm-linux-androideabi");
     const QLatin1String X86ToolchainPrefix("x86");
     const QLatin1String MipsToolchainPrefix("mipsel-linux-android");
+    const QLatin1String AArch64ToolchainPrefix("aarch64-linux-android");
+    const QLatin1String X86_64ToolchainPrefix("x86_64");
+
     const QLatin1String ArmToolsPrefix("arm-linux-androideabi");
     const QLatin1String X86ToolsPrefix("i686-linux-android");
     const QLatin1String MipsToolsPrefix("mipsel-linux-android");
+    const QLatin1String AArch64ToolsPrefix("aarch64-linux-android");
+    const QLatin1String X86_64ToolsPrefix("x86_64-linux-android");
+
+    const QLatin1String ArmToolsDisplayName("arm");
+    const QLatin1String X86ToolsDisplayName("i686");
+    const QLatin1String MipsToolsDisplayName("mipsel");
+    const QLatin1String AArch64ToolsDisplayName("aarch64");
+    const QLatin1String X86_64ToolsDisplayName("x86_64");
+
     const QLatin1String Unknown("unknown");
     const QLatin1String keytoolName("keytool");
     const QLatin1String jarsignerName("jarsigner");
@@ -164,23 +177,41 @@ namespace {
 // AndroidConfig
 //////////////////////////////////
 
-Abi::Architecture AndroidConfig::architectureForToolChainPrefix(const QString& toolchainprefix)
-{
-    if (toolchainprefix == ArmToolchainPrefix)
-        return Abi::ArmArchitecture;
-    if (toolchainprefix == X86ToolchainPrefix)
-        return Abi::X86Architecture;
-    if (toolchainprefix == MipsToolchainPrefix)
-        return Abi::MipsArchitecture;
-    return Abi::UnknownArchitecture;
+Abi AndroidConfig::abiForToolChainPrefix(const QString &toolchainPrefix)
+{
+    Abi::Architecture arch = Abi::UnknownArchitecture;
+    unsigned char wordWidth = 32;
+    if (toolchainPrefix == ArmToolchainPrefix) {
+        arch = Abi::ArmArchitecture;
+    } else if (toolchainPrefix == X86ToolchainPrefix) {
+        arch = Abi::X86Architecture;
+    } else if (toolchainPrefix == MipsToolchainPrefix) {
+        arch = Abi::MipsArchitecture;
+    } else if (toolchainPrefix == AArch64ToolchainPrefix) {
+        arch = Abi::ArmArchitecture;
+        wordWidth = 64;
+    } else if (toolchainPrefix == X86_64ToolchainPrefix) {
+        arch = Abi::X86Architecture;
+        wordWidth = 64;
+    }
+
+    Abi abi = ProjectExplorer::Abi(arch,
+                                   ProjectExplorer::Abi::LinuxOS,
+                                   ProjectExplorer::Abi::AndroidLinuxFlavor, ProjectExplorer::Abi::ElfFormat,
+                                   wordWidth);
+    return abi;
 }
 
-QLatin1String AndroidConfig::toolchainPrefix(Abi::Architecture architecture)
+QLatin1String AndroidConfig::toolchainPrefix(const Abi &abi)
 {
-    switch (architecture) {
+    switch (abi.architecture()) {
     case Abi::ArmArchitecture:
+        if (abi.wordWidth() == 64)
+            return AArch64ToolchainPrefix;
         return ArmToolchainPrefix;
     case Abi::X86Architecture:
+        if (abi.wordWidth() == 64)
+            return X86_64ToolchainPrefix;
         return X86ToolchainPrefix;
     case Abi::MipsArchitecture:
         return MipsToolchainPrefix;
@@ -189,12 +220,16 @@ QLatin1String AndroidConfig::toolchainPrefix(Abi::Architecture architecture)
     }
 }
 
-QLatin1String AndroidConfig::toolsPrefix(Abi::Architecture architecture)
+QLatin1String AndroidConfig::toolsPrefix(const Abi &abi)
 {
-    switch (architecture) {
+    switch (abi.architecture()) {
     case Abi::ArmArchitecture:
+        if (abi.wordWidth() == 64)
+            return AArch64ToolsPrefix;
         return ArmToolsPrefix;
     case Abi::X86Architecture:
+        if (abi.wordWidth() == 64)
+            return X86_64ToolsPrefix;
         return X86ToolsPrefix;
     case Abi::MipsArchitecture:
         return MipsToolsPrefix;
@@ -203,6 +238,24 @@ QLatin1String AndroidConfig::toolsPrefix(Abi::Architecture architecture)
     }
 }
 
+QLatin1String AndroidConfig::displayName(const Abi &abi)
+{
+    switch (abi.architecture()) {
+    case Abi::ArmArchitecture:
+        if (abi.wordWidth() == 64)
+            return AArch64ToolsDisplayName;
+        return ArmToolsDisplayName;
+    case Abi::X86Architecture:
+        if (abi.wordWidth() == 64)
+            return X86_64ToolsDisplayName;
+        return X86ToolsDisplayName;
+    case Abi::MipsArchitecture:
+        return MipsToolsDisplayName;
+    default:
+        return Unknown;
+    }
+}
+
 void AndroidConfig::load(const QSettings &settings)
 {
     // user settings
@@ -433,24 +486,24 @@ FileName AndroidConfig::emulatorToolPath() const
     return path.appendPath(QLatin1String("tools/emulator" QTC_HOST_EXE_SUFFIX));
 }
 
-FileName AndroidConfig::toolPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
+FileName AndroidConfig::toolPath(const Abi &abi, const QString &ndkToolChainVersion) const
 {
     FileName path = m_ndkLocation;
     return path.appendPath(QString::fromLatin1("toolchains/%1-%2/prebuilt/%3/bin/%4")
-            .arg(toolchainPrefix(architecture))
+            .arg(toolchainPrefix(abi))
             .arg(ndkToolChainVersion)
             .arg(toolchainHost())
-            .arg(toolsPrefix(architecture)));
+            .arg(toolsPrefix(abi)));
 }
 
-FileName AndroidConfig::gccPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
+FileName AndroidConfig::gccPath(const Abi &abi, const QString &ndkToolChainVersion) const
 {
-    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-gcc" QTC_HOST_EXE_SUFFIX));
+    return toolPath(abi, ndkToolChainVersion).appendString(QLatin1String("-gcc" QTC_HOST_EXE_SUFFIX));
 }
 
-FileName AndroidConfig::gdbPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
+FileName AndroidConfig::gdbPath(const Abi &abi, const QString &ndkToolChainVersion) const
 {
-    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-gdb" QTC_HOST_EXE_SUFFIX));
+    return toolPath(abi, ndkToolChainVersion).appendString(QLatin1String("-gdb" QTC_HOST_EXE_SUFFIX));
 }
 
 FileName AndroidConfig::openJDKBinPath() const
@@ -1138,14 +1191,14 @@ void AndroidConfigurations::updateAutomaticKitList()
         existingKits << k;
     }
 
-    QMap<Abi::Architecture, QList<QtSupport::BaseQtVersion *> > qtVersionsForArch;
+    QHash<Abi, QList<QtSupport::BaseQtVersion *> > qtVersionsForArch;
     foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::versions()) {
         if (qtVersion->type() != QLatin1String(Constants::ANDROIDQT))
             continue;
         QList<Abi> qtAbis = qtVersion->qtAbis();
         if (qtAbis.empty())
             continue;
-        qtVersionsForArch[qtAbis.first().architecture()].append(qtVersion);
+        qtVersionsForArch[qtAbis.first()].append(qtVersion);
     }
 
     DeviceManager *dm = DeviceManager::instance();
@@ -1162,7 +1215,7 @@ void AndroidConfigurations::updateAutomaticKitList()
     foreach (AndroidToolChain *tc, toolchains) {
         if (tc->isSecondaryToolChain())
             continue;
-        QList<QtSupport::BaseQtVersion *> qtVersions = qtVersionsForArch.value(tc->targetAbi().architecture());
+        QList<QtSupport::BaseQtVersion *> qtVersions = qtVersionsForArch.value(tc->targetAbi());
         foreach (QtSupport::BaseQtVersion *qt, qtVersions) {
             Kit *newKit = new Kit;
             newKit->setAutoDetected(true);
diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h
index 55152b81e13..7c1d7649f97 100644
--- a/src/plugins/android/androidconfigurations.h
+++ b/src/plugins/android/androidconfigurations.h
@@ -126,8 +126,8 @@ public:
     Utils::FileName emulatorToolPath() const;
 
 
-    Utils::FileName gccPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const;
-    Utils::FileName gdbPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const;
+    Utils::FileName gccPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const;
+    Utils::FileName gdbPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const;
 
     Utils::FileName keytoolPath() const;
 
@@ -156,9 +156,10 @@ public:
     QString waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface<bool> &fi = QFutureInterface<bool>()) const;
     QString bestNdkPlatformMatch(int target) const;
 
-    static ProjectExplorer::Abi::Architecture architectureForToolChainPrefix(const QString &toolchainprefix);
-    static QLatin1String toolchainPrefix(ProjectExplorer::Abi::Architecture architecture);
-    static QLatin1String toolsPrefix(ProjectExplorer::Abi::Architecture architecture);
+    static ProjectExplorer::Abi abiForToolChainPrefix(const QString &toolchainPrefix);
+    static QLatin1String toolchainPrefix(const ProjectExplorer::Abi &abi);
+    static QLatin1String toolsPrefix(const ProjectExplorer::Abi &abi);
+    static QLatin1String displayName(const ProjectExplorer::Abi &abi);
 
     QString getProductModel(const QString &device) const;
     bool hasFinishedBooting(const QString &device) const;
@@ -170,7 +171,7 @@ private:
     static CreateAvdInfo createAVDImpl(CreateAvdInfo info, Utils::FileName androidToolPath, Utils::Environment env);
     static QVector<AndroidDeviceInfo> androidVirtualDevicesImpl(const Utils::FileName &androidTool, const Utils::Environment &environment);
 
-    Utils::FileName toolPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const;
+    Utils::FileName toolPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const;
     Utils::FileName openJDKBinPath() const;
     int getSDKVersion(const QString &device) const;
     QStringList getAbis(const QString &device) const;
diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp
index af79f85f7af..6b34cd9c677 100644
--- a/src/plugins/android/androidsettingswidget.cpp
+++ b/src/plugins/android/androidsettingswidget.cpp
@@ -282,9 +282,9 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode)
             QStringList gdbPaths;
             foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) {
                 // we only check the arm gdbs, that's indicative enough
-                if (ati.architecture != ProjectExplorer::Abi::ArmArchitecture)
+                if (ati.abi.architecture() != ProjectExplorer::Abi::ArmArchitecture)
                     continue;
-                Utils::FileName gdbPath = m_androidConfig.gdbPath(ati.architecture, ati.version);
+                Utils::FileName gdbPath = m_androidConfig.gdbPath(ati.abi, ati.version);
                 if (gdbPath.exists())
                     gdbPaths << gdbPath.toString();
             }
@@ -295,32 +295,29 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode)
             }
 
             // See if we have qt versions for those toolchains
-            QSet<ProjectExplorer::Abi::Architecture> toolchainsForArch;
+            QSet<ProjectExplorer::Abi> toolchainsForAbi;
             foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths)
-                toolchainsForArch.insert(ati.architecture);
+                toolchainsForAbi.insert(ati.abi);
 
-            QSet<ProjectExplorer::Abi::Architecture> qtVersionsForArch;
+            QSet<ProjectExplorer::Abi> qtVersionsForAbi;
             foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::versions()) {
                 if (qtVersion->type() != QLatin1String(Constants::ANDROIDQT) || qtVersion->qtAbis().isEmpty())
                     continue;
-                qtVersionsForArch.insert(qtVersion->qtAbis().first().architecture());
+                qtVersionsForAbi.insert(qtVersion->qtAbis().first());
             }
 
-            QSet<ProjectExplorer::Abi::Architecture> missingQtArchs = toolchainsForArch.subtract(qtVersionsForArch);
+            QSet<ProjectExplorer::Abi> missingQtArchs = toolchainsForAbi.subtract(qtVersionsForAbi);
             if (missingQtArchs.isEmpty()) {
                 m_ndkMissingQtArchs.clear();
             } else {
                 if (missingQtArchs.count() == 1) {
                     m_ndkMissingQtArchs = tr("Qt version for architecture %1 is missing.\n"
                                              "To add the Qt version, select Options > Build & Run > Qt Versions.")
-                            .arg(ProjectExplorer::Abi::toString((*missingQtArchs.constBegin())));
+                            .arg((*missingQtArchs.constBegin()).toString());
                 } else {
-                    QStringList missingArchs;
-                    foreach (ProjectExplorer::Abi::Architecture arch, missingQtArchs)
-                        missingArchs.append(ProjectExplorer::Abi::toString(arch));
-                    m_ndkMissingQtArchs = tr("Qt versions for architectures %1 are missing.\n"
+                    m_ndkMissingQtArchs = tr("Qt versions for %1 architectures are missing.\n"
                                              "To add the Qt versions, select Options > Build & Run > Qt Versions.")
-                            .arg(missingArchs.join(QLatin1String(", ")));
+                            .arg(missingQtArchs.size());
                 }
             }
         }
diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp
index fe3d8650665..4dccaaeafbc 100644
--- a/src/plugins/android/androidtoolchain.cpp
+++ b/src/plugins/android/androidtoolchain.cpp
@@ -64,17 +64,16 @@ using namespace Utils;
 static const char ANDROID_QT_VERSION_KEY[] = "Qt4ProjectManager.Android.QtVersion";
 static const char ANDROID_NDK_TC_VERION[] = "Qt4ProjectManager.Android.NDK_TC_VERION";
 
-QMap<Abi::Architecture, QList<int> > AndroidToolChainFactory::m_newestVersionForArch;
+QHash<Abi, QList<int> > AndroidToolChainFactory::m_newestVersionForAbi;
 FileName AndroidToolChainFactory::m_ndkLocation;
 
-AndroidToolChain::AndroidToolChain(Abi::Architecture arch, const QString &ndkToolChainVersion, Detection d)
+AndroidToolChain::AndroidToolChain(const Abi &abi, const QString &ndkToolChainVersion, Detection d)
     : GccToolChain(QLatin1String(Constants::ANDROID_TOOLCHAIN_ID), d),
       m_ndkToolChainVersion(ndkToolChainVersion), m_secondaryToolChain(false)
 {
-    Abi abi = Abi(arch, Abi::LinuxOS, Abi::AndroidLinuxFlavor, Abi::ElfFormat, 32);
     setTargetAbi(abi);
     setDisplayName(QString::fromLatin1("Android GCC (%1-%2)")
-                   .arg(Abi::toString(targetAbi().architecture()))
+                   .arg(AndroidConfig::displayName(targetAbi()))
                    .arg(ndkToolChainVersion));
 }
 
@@ -116,8 +115,8 @@ void AndroidToolChain::addToEnvironment(Environment &env) const
 // TODO invalidate all .pro files !!!
 
     env.set(QLatin1String("ANDROID_NDK_HOST"), AndroidConfigurations::currentConfig().toolchainHost());
-    env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_PREFIX"), AndroidConfig::toolchainPrefix(targetAbi().architecture()));
-    env.set(QLatin1String("ANDROID_NDK_TOOLS_PREFIX"), AndroidConfig::toolsPrefix(targetAbi().architecture()));
+    env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_PREFIX"), AndroidConfig::toolchainPrefix(targetAbi()));
+    env.set(QLatin1String("ANDROID_NDK_TOOLS_PREFIX"), AndroidConfig::toolsPrefix(targetAbi()));
     env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_VERSION"), m_ndkToolChainVersion);
     QString javaHome = AndroidConfigurations::currentConfig().openJDKLocation().toString();
     if (!javaHome.isEmpty() && QFileInfo::exists(javaHome))
@@ -141,7 +140,7 @@ ToolChainConfigWidget *AndroidToolChain::configurationWidget()
 
 FileName AndroidToolChain::suggestedDebugger() const
 {
-    return AndroidConfigurations::currentConfig().gdbPath(targetAbi().architecture(), m_ndkToolChainVersion);
+    return AndroidConfigurations::currentConfig().gdbPath(targetAbi(), m_ndkToolChainVersion);
 }
 
 FileName AndroidToolChain::suggestedGdbServer() const
@@ -153,7 +152,7 @@ FileName AndroidToolChain::suggestedGdbServer() const
         return path;
     path = AndroidConfigurations::currentConfig().ndkLocation();
     path.appendPath(QString::fromLatin1("toolchains/%1-%2/prebuilt/gdbserver")
-                               .arg(AndroidConfig::toolchainPrefix(targetAbi().architecture()))
+                               .arg(AndroidConfig::toolchainPrefix(targetAbi()))
                                .arg(m_ndkToolChainVersion));
     if (path.exists())
         return path;
@@ -192,16 +191,14 @@ bool AndroidToolChain::fromMap(const QVariantMap &data)
             return false;
         m_ndkToolChainVersion = command.mid(index + 1);
         QString platform = command.left(index);
-        Abi::Architecture arch = AndroidConfig::architectureForToolChainPrefix(platform);
-        Abi abi = Abi(arch, Abi::LinuxOS, Abi::AndroidLinuxFlavor, Abi::ElfFormat, 32);
-        setTargetAbi(abi);
+        setTargetAbi(AndroidConfig::abiForToolChainPrefix(platform));
     } else {
         m_ndkToolChainVersion = data.value(QLatin1String(ANDROID_NDK_TC_VERION)).toString();
     }
 
-    Abi::Architecture arch = targetAbi().architecture();
+    Abi abi = targetAbi();
     m_secondaryToolChain = AndroidToolChainFactory::versionCompareLess(AndroidToolChainFactory::versionNumberFromString(m_ndkToolChainVersion),
-                                                                       AndroidToolChainFactory::newestToolChainVersionForArch(arch));
+                                                                       AndroidToolChainFactory::newestToolChainVersionForArch(abi));
     return isValid();
 }
 
@@ -304,11 +301,11 @@ QList<AndroidToolChainFactory::AndroidToolChainInformation> AndroidToolChainFact
         AndroidToolChainInformation ati;
         ati.version = fileName.mid(idx + 1);
         QString platform = fileName.left(idx);
-        ati.architecture = AndroidConfig::architectureForToolChainPrefix(platform);
-        if (ati.architecture == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
+        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.architecture, ati.version);
+        ati.compilerCommand = AndroidConfigurations::currentConfig().gccPath(ati.abi, ati.version);
         // tc->setCompilerCommand(compilerPath);
         result.append(ati);
     }
@@ -369,7 +366,7 @@ QList<ToolChain *> AndroidToolChainFactory::createToolChainsForNdk(const FileNam
     FileName path = ndkPath;
     QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(),
                     QStringList() << QLatin1String("*"), QDir::Dirs);
-    QMap<Abi::Architecture, AndroidToolChain *> newestToolChainForArch;
+    QHash<Abi, AndroidToolChain *> newestToolChainForArch;
 
     while (it.hasNext()) {
         const QString &fileName = FileName::fromString(it.next()).fileName();
@@ -378,34 +375,34 @@ QList<ToolChain *> AndroidToolChainFactory::createToolChainsForNdk(const FileNam
             continue;
         QString version = fileName.mid(idx + 1);
         QString platform = fileName.left(idx);
-        Abi::Architecture arch = AndroidConfig::architectureForToolChainPrefix(platform);
-        if (arch == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
+        Abi abi = AndroidConfig::abiForToolChainPrefix(platform);
+        if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
             continue;
-        AndroidToolChain *tc = new AndroidToolChain(arch, version, ToolChain::AutoDetection);
-        FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(arch, version);
+        AndroidToolChain *tc = new AndroidToolChain(abi, version, ToolChain::AutoDetection);
+        FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, version);
         tc->resetToolChain(compilerPath);
         result.append(tc);
 
-        QMap<Abi::Architecture, AndroidToolChain *>::const_iterator it
-                = newestToolChainForArch.constFind(arch);
+        QHash<Abi, AndroidToolChain *>::const_iterator it
+                = newestToolChainForArch.constFind(abi);
         if (it == newestToolChainForArch.constEnd())
-            newestToolChainForArch.insert(arch, tc);
+            newestToolChainForArch.insert(abi, tc);
         else if (versionCompareLess(it.value(), tc))
-            newestToolChainForArch[arch] = tc;
+            newestToolChainForArch[abi] = tc;
     }
 
     foreach (ToolChain *tc, result) {
         AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
-        if (newestToolChainForArch.value(atc->targetAbi().architecture()) != atc)
+        if (newestToolChainForArch.value(atc->targetAbi()) != atc)
             atc->setSecondaryToolChain(true);
     }
 
     return result;
 }
 
-QList<int> AndroidToolChainFactory::newestToolChainVersionForArch(Abi::Architecture arch)
+QList<int> AndroidToolChainFactory::newestToolChainVersionForArch(const Abi &abi)
 {
-    if (m_newestVersionForArch.isEmpty()
+    if (m_newestVersionForAbi.isEmpty()
             || m_ndkLocation != AndroidConfigurations::currentConfig().ndkLocation()) {
         QRegExp versionRegExp(NDKGccVersionRegExp);
         m_ndkLocation = AndroidConfigurations::currentConfig().ndkLocation();
@@ -419,18 +416,18 @@ QList<int> AndroidToolChainFactory::newestToolChainVersionForArch(Abi::Architect
                 continue;
             QList<int> version = versionNumberFromString(fileName.mid(idx + 1));
             QString platform = fileName.left(idx);
-            Abi::Architecture arch = AndroidConfig::architectureForToolChainPrefix(platform);
-            if (arch == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
+            Abi abi = AndroidConfig::abiForToolChainPrefix(platform);
+            if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported
                 continue;
-            QMap<Abi::Architecture, QList<int> >::const_iterator it
-                    = m_newestVersionForArch.constFind(arch);
-            if (it == m_newestVersionForArch.constEnd())
-                m_newestVersionForArch.insert(arch, version);
+            QHash<Abi, QList<int> >::const_iterator it
+                    = m_newestVersionForAbi.constFind(abi);
+            if (it == m_newestVersionForAbi.constEnd())
+                m_newestVersionForAbi.insert(abi, version);
             else if (versionCompareLess(it.value(), version))
-                m_newestVersionForArch[arch] = version;
+                m_newestVersionForAbi[abi] = version;
         }
     }
-    return m_newestVersionForArch.value(arch);
+    return m_newestVersionForAbi.value(abi);
 }
 
 } // namespace Internal
diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h
index f482cca8aa0..dddb5506f39 100644
--- a/src/plugins/android/androidtoolchain.h
+++ b/src/plugins/android/androidtoolchain.h
@@ -69,7 +69,7 @@ protected:
     QList<ProjectExplorer::Abi> detectSupportedAbis() const;
 
 private:
-    explicit AndroidToolChain(ProjectExplorer::Abi::Architecture arch, const QString &ndkToolChainVersion, Detection d);
+    explicit AndroidToolChain(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion, Detection d);
     AndroidToolChain();
     AndroidToolChain(const AndroidToolChain &);
 
@@ -110,7 +110,7 @@ public:
     {
     public:
         Utils::FileName compilerCommand;
-        ProjectExplorer::Abi::Architecture architecture;
+        ProjectExplorer::Abi abi;
         QString version;
     };
 
@@ -120,9 +120,9 @@ public:
     static QList<int> versionNumberFromString(const QString &version);
     static bool versionCompareLess(const QList<int> &a, const QList<int> &b);
     static bool versionCompareLess(AndroidToolChain *atc, AndroidToolChain *btc);
-    static QList<int> newestToolChainVersionForArch(ProjectExplorer::Abi::Architecture arch);
+    static QList<int> newestToolChainVersionForArch(const ProjectExplorer::Abi &abi);
 private:
-    static QMap<ProjectExplorer::Abi::Architecture, QList<int> > m_newestVersionForArch;
+    static QHash<ProjectExplorer::Abi, QList<int> > m_newestVersionForAbi;
     static Utils::FileName m_ndkLocation;
 };
 
diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp
index a84c198840f..f00eb525f4c 100644
--- a/src/plugins/projectexplorer/abi.cpp
+++ b/src/plugins/projectexplorer/abi.cpp
@@ -240,6 +240,9 @@ static QList<Abi> abiOf(const QByteArray &data)
         case 40: // EM_ARM
             result.append(Abi(Abi::ArmArchitecture, os, flavor, Abi::ElfFormat, 32));
             break;
+        case 183: // EM_AARCH64
+            result.append(Abi(Abi::ArmArchitecture, os, flavor, Abi::ElfFormat, 64));
+            break;
         case 62: // EM_X86_64
             result.append(Abi(Abi::X86Architecture, os, flavor, Abi::ElfFormat, 64));
             break;
diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h
index b09016a0442..4f6fbd81b79 100644
--- a/src/plugins/projectexplorer/abi.h
+++ b/src/plugins/projectexplorer/abi.h
@@ -34,6 +34,7 @@
 #include "projectexplorer_export.h"
 
 #include <QList>
+#include <QHash>
 
 namespace Utils { class FileName; }
 
@@ -150,6 +151,15 @@ private:
     unsigned char m_wordWidth;
 };
 
+inline int qHash(const ProjectExplorer::Abi &abi)
+{
+    int h = abi.architecture()
+            + (abi.os() << 3)
+            + (abi.osFlavor() << 6)
+            + (abi.binaryFormat() << 10)
+            + (abi.wordWidth() << 13);
+    return QT_PREPEND_NAMESPACE(qHash)(h);
+}
 } // namespace ProjectExplorer
 
 #endif // PROJECTEXPLORER_ABI_H
-- 
GitLab