diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index b1714944cfd..c187ba7b735 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -953,6 +953,16 @@ bool AndroidConfig::sdkToolsOk() const QStringList AndroidConfig::essentialsFromQtVersion(const QtVersion &version) const { + if (auto androidQtVersion = dynamic_cast(&version)) { + bool ok; + const AndroidQtVersion::BuiltWith bw = androidQtVersion->builtWith(&ok); + if (ok) { + const QString ndkPackage = ndkPackageMarker() + bw.ndkVersion.toString(); + return QStringList(ndkPackage) + + packagesWithoutNdks(m_defaultSdkDepends.essentialPackages); + } + } + QVersionNumber qtVersion = version.qtVersion(); for (const SdkForQtVersions &item : m_specificQtVersions) if (item.containsVersion(qtVersion)) @@ -973,6 +983,13 @@ static FilePath ndkSubPath(const SdkForQtVersions &packages) FilePath AndroidConfig::ndkSubPathFromQtVersion(const QtVersion &version) const { + if (auto androidQtVersion = dynamic_cast(&version)) { + bool ok; + const AndroidQtVersion::BuiltWith bw = androidQtVersion->builtWith(&ok); + if (ok) + return FilePath::fromString(NdksSubDir) / bw.ndkVersion.toString(); + } + for (const SdkForQtVersions &item : m_specificQtVersions) if (item.containsVersion(version.qtVersion())) return ndkSubPath(item); diff --git a/src/plugins/android/androidplugin.h b/src/plugins/android/androidplugin.h index 2b0fc3fe081..394786e5340 100644 --- a/src/plugins/android/androidplugin.h +++ b/src/plugins/android/androidplugin.h @@ -27,6 +27,8 @@ private slots: void testAndroidSdkManagerProgressParser(); void testAndroidConfigAvailableNdkPlatforms_data(); void testAndroidConfigAvailableNdkPlatforms(); + void testAndroidQtVersionParseBuiltWith_data(); + void testAndroidQtVersionParseBuiltWith(); #endif // WITH_TESTS }; diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index 194312cf66a..3dc6561311a 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -26,8 +27,15 @@ #include +#include +#include #include +#ifdef WITH_TESTS +# include +# include "androidplugin.h" +#endif // WITH_TESTS + using namespace ProjectExplorer; namespace Android { @@ -137,6 +145,22 @@ Utils::FilePath AndroidQtVersion::androidDeploymentSettings(const Target *target .arg(displayName)); } +AndroidQtVersion::BuiltWith AndroidQtVersion::builtWith(bool *ok) const +{ + const Utils::FilePath coreModuleJson = qmakeFilePath().parentDir().parentDir() + // version.prefix() not yet set when this is called + / "modules/Core.json"; + if (coreModuleJson.exists()) { + Utils::FileReader reader; + if (reader.fetch(coreModuleJson)) + return parseBuiltWith(reader.data(), ok); + } + + if (ok) + *ok = false; + return {}; +} + static int versionFromPlatformString(const QString &string, bool *ok = nullptr) { static const QRegularExpression regex("android-(\\d+)"); @@ -146,6 +170,32 @@ static int versionFromPlatformString(const QString &string, bool *ok = nullptr) return match.hasMatch() ? match.captured(1).toInt(ok) : -1; } +AndroidQtVersion::BuiltWith AndroidQtVersion::parseBuiltWith(const QByteArray &modulesCoreJsonData, + bool *ok) +{ + bool validPlatformString = false; + AndroidQtVersion::BuiltWith result; + const QJsonObject jsonObject = QJsonDocument::fromJson(modulesCoreJsonData).object(); + if (const QJsonValue builtWith = jsonObject.value("built_with"); !builtWith.isUndefined()) { + if (const QJsonValue android = builtWith["android"]; !android.isUndefined()) { + if (const QJsonValue apiVersion = android["api_version"]; !apiVersion.isUndefined()) { + const QString apiVersionString = apiVersion.toString(); + const int v = versionFromPlatformString(apiVersionString, &validPlatformString); + if (validPlatformString) + result.apiVersion = v; + } + if (const QJsonValue ndk = android["ndk"]; !ndk.isUndefined()) { + if (const QJsonValue version = ndk["version"]; !version.isUndefined()) + result.ndkVersion = QVersionNumber::fromString(version.toString()); + } + } + } + + if (ok) + *ok = validPlatformString && !result.ndkVersion.isNull(); + return result; +} + void AndroidQtVersion::parseMkSpec(ProFileEvaluator *evaluator) const { m_androidAbis = evaluator->values("ALL_ANDROID_ABIS"); @@ -187,5 +237,68 @@ AndroidQtVersionFactory::AndroidQtVersionFactory() }); } +#ifdef WITH_TESTS +void AndroidPlugin::testAndroidQtVersionParseBuiltWith_data() +{ + QTest::addColumn("modulesCoreJson"); + QTest::addColumn("hasInfo"); + QTest::addColumn("ndkVersion"); + QTest::addColumn("apiVersion"); + + QTest::newRow("Android Qt 6.4") + << R"({ + "module_name": "Core", + "version": "6.4.1", + "built_with": { + "compiler_id": "Clang", + "compiler_target": "x86_64-none-linux-android23", + "compiler_version": "12.0.8", + "cross_compiled": true, + "target_system": "Android" + } + })" + << false + << QVersionNumber() + << -1; + + QTest::newRow("Android Qt 6.5") + << R"({ + "module_name": "Core", + "version": "6.5.0", + "built_with": { + "android": { + "api_version": "android-31", + "ndk": { + "version": "25.1.8937393" + } + }, + "compiler_id": "Clang", + "compiler_target": "i686-none-linux-android23", + "compiler_version": "14.0.6", + "cross_compiled": true, + "target_system": "Android" + } + })" + << true + << QVersionNumber(25, 1, 8937393) + << 31; +} + +void AndroidPlugin::testAndroidQtVersionParseBuiltWith() +{ + QFETCH(QString, modulesCoreJson); + QFETCH(bool, hasInfo); + QFETCH(int, apiVersion); + QFETCH(QVersionNumber, ndkVersion); + + bool ok = false; + const AndroidQtVersion::BuiltWith bw = + AndroidQtVersion::parseBuiltWith(modulesCoreJson.toUtf8(), &ok); + QCOMPARE(ok, hasInfo); + QCOMPARE(bw.apiVersion, apiVersion); + QCOMPARE(bw.ndkVersion, ndkVersion); +} +#endif // WITH_TESTS + } // Internal } // Android diff --git a/src/plugins/android/androidqtversion.h b/src/plugins/android/androidqtversion.h index 7dedca61928..1549c870dae 100644 --- a/src/plugins/android/androidqtversion.h +++ b/src/plugins/android/androidqtversion.h @@ -34,6 +34,13 @@ public: static Utils::FilePath androidDeploymentSettings(const ProjectExplorer::Target *target); + struct BuiltWith { + int apiVersion = -1; + QVersionNumber ndkVersion; + }; + static BuiltWith parseBuiltWith(const QByteArray &modulesCoreJsonData, bool *ok = nullptr); + BuiltWith builtWith(bool *ok = nullptr) const; + protected: void parseMkSpec(ProFileEvaluator *) const override; private: