From 49443d689e6ebac22ab756413ea1d6baac314dd4 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Jan 2022 09:28:43 +0100 Subject: [PATCH] Android: Detect available Ndk platforms also for recent Ndk versions In order to detect the list of platforms that an Ndk installation supports, AndroidConfig::availableNdkPlatforms iterates through the directories of the Ndk. The directory structure of the Ndk changed in the recent versions. So that the detection that works with Ndk 19 does not work with Ndk 23. Also, the new directory structure is split up by Android ABI. And the lists of supported platforms differ between ABI. This change adds detection for the new structure, in case that the old implementation fails to return a list. It also adds an autotest that covers the old and new detection of supported platforms. Fixes: QTCREATORBUG-26772 Change-Id: I6e584963f51feca0bf90c7ed3a9fdb03cb5d39e6 Reviewed-by: Assam Boudjelthia --- src/plugins/android/CMakeLists.txt | 6 + src/plugins/android/android.qbs | 8 ++ src/plugins/android/android_tst.qrc | 71 ++++++++++++ src/plugins/android/androidconfigurations.cpp | 106 +++++++++++++++++- src/plugins/android/androidconfigurations.h | 3 +- src/plugins/android/androidplugin.h | 2 + 6 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 src/plugins/android/android_tst.qrc diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index b87f7ad1d24..2f4b06f634a 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -54,3 +54,9 @@ add_qtc_plugin(Android splashscreencontainerwidget.cpp splashscreencontainerwidget.h splashscreenwidget.cpp splashscreenwidget.h ) + +extend_qtc_plugin(Android + CONDITION WITH_TESTS + SOURCES + android_tst.qrc +) diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 08e69d9421c..9d655cad61a 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -120,5 +120,13 @@ Project { "splashscreenwidget.cpp", "splashscreenwidget.h" ] + + Group { + name: "Unit tests" + condition: qtc.testsEnabled + files: [ + "android_tst.qrc", + ] + } } } diff --git a/src/plugins/android/android_tst.qrc b/src/plugins/android/android_tst.qrc new file mode 100644 index 00000000000..2d557291176 --- /dev/null +++ b/src/plugins/android/android_tst.qrc @@ -0,0 +1,71 @@ + + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + android.qrc + + diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index a58ed30f19e..ef3aa2d6053 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -77,6 +77,11 @@ #include #include +#ifdef WITH_TESTS +# include +# include "androidplugin.h" +#endif // WITH_TESTS + using namespace QtSupport; using namespace ProjectExplorer; using namespace Utils; @@ -368,11 +373,11 @@ void AndroidConfig::parseDependenciesJson() } } -QVector AndroidConfig::availableNdkPlatforms(const QtVersion *qtVersion) const +static QVector availableNdkPlatformsLegacy(const FilePath &ndkLocation) { QVector availableNdkPlatforms; - ndkLocation(qtVersion) + ndkLocation .pathAppended("platforms") .iterateDirectory( [&availableNdkPlatforms](const FilePath &filePath) { @@ -384,10 +389,43 @@ QVector AndroidConfig::availableNdkPlatforms(const QtVersion *qtVersion) co }, {{"android-*"}, QDir::Dirs}); - Utils::sort(availableNdkPlatforms, std::greater<>()); return availableNdkPlatforms; } +static QVector availableNdkPlatformsV21Plus(const FilePath &ndkLocation, const Abis &abis, + OsType hostOs) +{ + if (abis.isEmpty()) + return {}; + + const QString abi = AndroidConfig::toolsPrefix(abis.first()); + const FilePath libPath = + AndroidConfig::toolchainPathFromNdk(ndkLocation, hostOs) / "sysroot/usr/lib" / abi; + const QList dirEntries = libPath.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot); + const QVector availableNdkPlatforms = + Utils::transform(dirEntries, [](const FilePath &path) { + return path.fileName().toInt(); }); + return availableNdkPlatforms; +} + +static QVector availableNdkPlatformsImpl(const FilePath &ndkLocation, const Abis &abis, + OsType hostOs) +{ + QVector result = availableNdkPlatformsLegacy(ndkLocation); + + if (result.isEmpty()) + result = availableNdkPlatformsV21Plus(ndkLocation, abis, hostOs); + + Utils::sort(result, std::greater<>()); + return result; +} + +QVector AndroidConfig::availableNdkPlatforms(const QtVersion *qtVersion) const +{ + return availableNdkPlatformsImpl(ndkLocation(qtVersion), qtVersion->qtAbis(), + HostOsInfo::hostOs()); +} + QStringList AndroidConfig::getCustomNdkList() const { return m_customNdkList; @@ -513,7 +551,7 @@ FilePath AndroidConfig::avdManagerToolPath() const return FilePath(); } -FilePath AndroidConfig::toolchainPathFromNdk(const FilePath &ndkLocation) +FilePath AndroidConfig::toolchainPathFromNdk(const FilePath &ndkLocation, OsType hostOs) { const FilePath tcPath = ndkLocation / "toolchains/"; FilePath toolchainPath; @@ -525,7 +563,7 @@ FilePath AndroidConfig::toolchainPathFromNdk(const FilePath &ndkLocation) // detect toolchain host QStringList hostPatterns; - switch (HostOsInfo::hostOs()) { + switch (hostOs) { case OsTypeLinux: hostPatterns << QLatin1String("linux*"); break; @@ -1641,4 +1679,62 @@ void AndroidConfigurations::updateAndroidDevice() AndroidConfigurations *AndroidConfigurations::m_instance = nullptr; +#ifdef WITH_TESTS +void AndroidPlugin::testAndroidConfigAvailableNdkPlatforms_data() +{ + QTest::addColumn("ndkPath"); + QTest::addColumn("abis"); + QTest::addColumn("hostOs"); + QTest::addColumn >("expectedPlatforms"); + + QTest::newRow("ndkLegacy") + << FilePath::fromUserInput(":/android/tst/ndk/19.2.5345600") + << Abis() + << OsTypeOther + << QVector{28, 27, 26, 24, 23, 22, 21, 19, 18, 17, 16}; + + const FilePath ndkV21Plus = FilePath::fromUserInput(":/android/tst/ndk/23.1.7779620"); + const QVector abis32Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21, 19, 18, 17, 16}; + const QVector abis64Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21}; + QTest::newRow("ndkV21Plus armeabi-v7a OsTypeWindows") + << ndkV21Plus + << Abis{AndroidManager::androidAbi2Abi( + ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A)} + << OsTypeWindows + << abis32Bit; + + QTest::newRow("ndkV21Plus arm64-v8a OsTypeLinux") + << ndkV21Plus + << Abis{AndroidManager::androidAbi2Abi( + ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A)} + << OsTypeLinux + << abis64Bit; + + QTest::newRow("ndkV21Plus x86 OsTypeMac") + << ndkV21Plus + << Abis{AndroidManager::androidAbi2Abi( + ProjectExplorer::Constants::ANDROID_ABI_X86)} + << OsTypeMac + << abis32Bit; + + QTest::newRow("ndkV21Plus x86_64 OsTypeWindows") + << ndkV21Plus + << Abis{AndroidManager::androidAbi2Abi( + ProjectExplorer::Constants::ANDROID_ABI_X86_64)} + << OsTypeWindows + << abis64Bit; +} + +void AndroidPlugin::testAndroidConfigAvailableNdkPlatforms() +{ + QFETCH(FilePath, ndkPath); + QFETCH(Abis, abis); + QFETCH(OsType, hostOs); + QFETCH(QVector, expectedPlatforms); + + const QVector foundPlatforms = availableNdkPlatformsImpl(ndkPath, abis, hostOs); + QCOMPARE(foundPlatforms, expectedPlatforms); +} +#endif // WITH_TESTS + } // namespace Android diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index c924a3f3173..07a0055ea09 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -135,7 +135,8 @@ public: Utils::FilePath avdManagerToolPath() const; Utils::FilePath toolchainPath(const QtSupport::QtVersion *qtVersion) const; - static Utils::FilePath toolchainPathFromNdk(const Utils::FilePath &ndkLocation); + static Utils::FilePath toolchainPathFromNdk(const Utils::FilePath &ndkLocation, + Utils::OsType hostOs = Utils::HostOsInfo::hostOs()); static Utils::FilePath clangPathFromNdk(const Utils::FilePath &ndkLocation); Utils::FilePath gdbPath(const ProjectExplorer::Abi &abi, const QtSupport::QtVersion *qtVersion) const; diff --git a/src/plugins/android/androidplugin.h b/src/plugins/android/androidplugin.h index d90449c3926..d4ad726cf05 100644 --- a/src/plugins/android/androidplugin.h +++ b/src/plugins/android/androidplugin.h @@ -48,6 +48,8 @@ class AndroidPlugin final : public ExtensionSystem::IPlugin private slots: void testAndroidSdkManagerProgressParser_data(); void testAndroidSdkManagerProgressParser(); + void testAndroidConfigAvailableNdkPlatforms_data(); + void testAndroidConfigAvailableNdkPlatforms(); #endif // WITH_TESTS };