diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 194c3c52296..fa7918526ed 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -532,10 +532,14 @@ void AndroidBuildApkStep::setBuildTargetSdk(const QString &sdk) QVariant AndroidBuildApkStep::data(Core::Id id) const { - if (id == Constants::AndroidNdkPlatform) - return AndroidConfigurations::currentConfig().bestNdkPlatformMatch(AndroidManager::minimumSDK(target())).mid(8); + QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit()); + + if (id == Constants::AndroidNdkPlatform) { + return AndroidConfigurations::currentConfig() + .bestNdkPlatformMatch(AndroidManager::minimumSDK(target()), qtVersion).mid(8); + } if (id == Constants::NdkLocation) - return QVariant::fromValue(AndroidConfigurations::currentConfig().ndkLocation()); + return QVariant::fromValue(AndroidConfigurations::currentConfig().ndkLocation(qtVersion)); if (id == Constants::SdkLocation) return QVariant::fromValue(AndroidConfigurations::currentConfig().sdkLocation()); if (id == Constants::AndroidABIs) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index d8e9b92f5f8..0e794dd6d7e 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -102,7 +102,6 @@ namespace { const QLatin1String SDKLocationKey("SDKLocation"); const QLatin1String SdkFullyConfiguredKey("AllEssentialsInstalled"); const QLatin1String SDKManagerToolArgsKey("SDKManagerToolArgs"); - const QLatin1String NDKLocationKey("NDKLocation"); const QLatin1String OpenJDKLocationKey("OpenJDKLocation"); const QLatin1String KeystoreLocationKey("KeystoreLocation"); const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation"); @@ -237,10 +236,8 @@ void AndroidConfig::load(const QSettings &settings) m_partitionSize = settings.value(PartitionSizeKey, 1024).toInt(); m_sdkLocation = FilePath::fromString(settings.value(SDKLocationKey).toString()); m_sdkManagerToolArgs = settings.value(SDKManagerToolArgsKey).toStringList(); - m_ndkLocation = FilePath::fromString(settings.value(NDKLocationKey).toString()); m_openJDKLocation = FilePath::fromString(settings.value(OpenJDKLocationKey).toString()); m_keystoreLocation = FilePath::fromString(settings.value(KeystoreLocationKey).toString()); - m_toolchainHost = settings.value(ToolchainHostKey).toString(); m_automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool(); m_sdkFullyConfigured = settings.value(SdkFullyConfiguredKey, false).toBool(); @@ -250,16 +247,12 @@ void AndroidConfig::load(const QSettings &settings) // persisten settings m_sdkLocation = FilePath::fromString(reader.restoreValue(SDKLocationKey, m_sdkLocation.toString()).toString()); m_sdkManagerToolArgs = reader.restoreValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs).toStringList(); - m_ndkLocation = FilePath::fromString(reader.restoreValue(NDKLocationKey, m_ndkLocation.toString()).toString()); m_openJDKLocation = FilePath::fromString(reader.restoreValue(OpenJDKLocationKey, m_openJDKLocation.toString()).toString()); - m_keystoreLocation = FilePath::fromString(reader.restoreValue(KeystoreLocationKey, m_keystoreLocation.toString()).toString()); - m_toolchainHost = reader.restoreValue(ToolchainHostKey, m_toolchainHost).toString(); m_automaticKitCreation = reader.restoreValue(AutomaticKitCreationKey, m_automaticKitCreation).toBool(); m_sdkFullyConfigured = reader.restoreValue(SdkFullyConfiguredKey, m_sdkFullyConfigured).toBool(); // persistent settings } parseDependenciesJson(); - m_NdkInformationUpToDate = false; } void AndroidConfig::save(QSettings &settings) const @@ -271,51 +264,13 @@ void AndroidConfig::save(QSettings &settings) const // user settings settings.setValue(SDKLocationKey, m_sdkLocation.toString()); settings.setValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs); - settings.setValue(NDKLocationKey, m_ndkLocation.toString()); settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString()); settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString()); settings.setValue(PartitionSizeKey, m_partitionSize); settings.setValue(AutomaticKitCreationKey, m_automaticKitCreation); - settings.setValue(ToolchainHostKey, m_toolchainHost); settings.setValue(SdkFullyConfiguredKey, m_sdkFullyConfigured); } -void AndroidConfig::updateNdkInformation() const -{ - if (m_NdkInformationUpToDate) - return; - m_availableNdkPlatforms.clear(); - QDirIterator it(m_ndkLocation.pathAppended("platforms").toString(), QStringList("android-*"), QDir::Dirs); - while (it.hasNext()) { - const QString &fileName = it.next(); - m_availableNdkPlatforms.push_back(fileName.midRef(fileName.lastIndexOf(QLatin1Char('-')) + 1).toInt()); - } - Utils::sort(m_availableNdkPlatforms, std::greater<>()); - - // detect toolchain host - QStringList hostPatterns; - switch (HostOsInfo::hostOs()) { - case OsTypeLinux: - hostPatterns << QLatin1String("linux*"); - break; - case OsTypeWindows: - hostPatterns << QLatin1String("windows*"); - break; - case OsTypeMac: - hostPatterns << QLatin1String("darwin*"); - break; - default: /* unknown host */ return; - } - - QDirIterator jt(m_ndkLocation.pathAppended("prebuilt").toString(), hostPatterns, QDir::Dirs); - if (jt.hasNext()) { - jt.next(); - m_toolchainHost = jt.fileName(); - } - - m_NdkInformationUpToDate = true; -} - void AndroidConfig::parseDependenciesJson() { QString sdkConfigFile(Core::ICore::resourcePath() + JsonFilePath); @@ -382,6 +337,22 @@ void AndroidConfig::parseDependenciesJson() } } +QVector AndroidConfig::availableNdkPlatforms(const BaseQtVersion *qtVersion) const +{ + QVector availableNdkPlatforms; + QDirIterator it(ndkLocation(qtVersion).pathAppended("platforms").toString(), + QStringList("android-*"), + QDir::Dirs); + while (it.hasNext()) { + const QString &fileName = it.next(); + availableNdkPlatforms.push_back( + fileName.midRef(fileName.lastIndexOf(QLatin1Char('-')) + 1).toInt()); + } + Utils::sort(availableNdkPlatforms, std::greater<>()); + + return availableNdkPlatforms; +} + QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms) { return Utils::transform(platforms, AndroidConfig::apiLevelNameFor); @@ -444,9 +415,9 @@ FilePath AndroidConfig::aaptToolPath() const return aaptToolPath.pathAppended(toolPath); } -FilePath AndroidConfig::toolchainPath() const +FilePath AndroidConfig::toolchainPath(const BaseQtVersion *qtVersion) const { - const FilePath toolchainPath = m_ndkLocation.pathAppended("toolchains/llvm/prebuilt/"); + const FilePath toolchainPath = ndkLocation(qtVersion).pathAppended("toolchains/llvm/prebuilt/"); // detect toolchain host QStringList hostPatterns; @@ -472,29 +443,34 @@ FilePath AndroidConfig::toolchainPath() const return {}; } -FilePath AndroidConfig::clangPath() const +FilePath AndroidConfig::clangPath(const BaseQtVersion *qtVersion) const { - const FilePath path = toolchainPath(); + const FilePath path = toolchainPath(qtVersion); if (path.isEmpty()) return {}; return path.pathAppended(HostOsInfo::withExecutableSuffix("bin/clang")); } -FilePath AndroidConfig::gdbPath(const ProjectExplorer::Abi &abi) const +FilePath AndroidConfig::gdbPath(const ProjectExplorer::Abi &abi, const BaseQtVersion *qtVersion) const { - const FilePath path = m_ndkLocation.pathAppended( - QString("prebuilt/%1/bin/gdb%2").arg(toolchainHost(), QTC_HOST_EXE_SUFFIX)); + const FilePath path = ndkLocation(qtVersion).pathAppended( + QString("prebuilt/%1/bin/gdb%2").arg(toolchainHost(qtVersion), QTC_HOST_EXE_SUFFIX)); if (path.exists()) return path; // fallback for old NDKs (e.g. 10e) - return m_ndkLocation.pathAppended(QString("toolchains/%1-4.9/prebuilt/%2/bin/%3-gdb%4") - .arg(toolchainPrefix(abi), toolchainHost(), toolsPrefix(abi), QTC_HOST_EXE_SUFFIX)); + return ndkLocation(qtVersion).pathAppended(QString("toolchains/%1-4.9/prebuilt/%2/bin/%3-gdb%4") + .arg(toolchainPrefix(abi), toolchainHost(qtVersion), toolsPrefix(abi), QTC_HOST_EXE_SUFFIX)); } -FilePath AndroidConfig::makePath() const +FilePath AndroidConfig::makePath(const BaseQtVersion *qtVersion) const { - return m_ndkLocation.pathAppended( - QString("prebuilt/%1/bin/make%2").arg(toolchainHost(), QTC_HOST_EXE_SUFFIX)); + return makePathFromNdk(ndkLocation(qtVersion)); +} + +FilePath AndroidConfig::makePathFromNdk(const FilePath &ndkLocation) const +{ + return ndkLocation.pathAppended( + QString("prebuilt/%1/bin/make%2").arg(toolchainHostFromNdk(ndkLocation), QTC_HOST_EXE_SUFFIX)); } FilePath AndroidConfig::openJDKBinPath() const @@ -757,11 +733,10 @@ bool AndroidConfig::useNativeUiTools() const return !version.isNull() && version <= QVersionNumber(25, 3 ,0); } -QString AndroidConfig::bestNdkPlatformMatch(int target) const +QString AndroidConfig::bestNdkPlatformMatch(int target, const BaseQtVersion *qtVersion) const { target = std::max(AndroidManager::apiLevelRange().first, target); - updateNdkInformation(); - foreach (int apiLevel, m_availableNdkPlatforms) { + foreach (int apiLevel, availableNdkPlatforms(qtVersion)) { if (apiLevel <= target) return QString::fromLatin1("android-%1").arg(apiLevel); } @@ -812,9 +787,9 @@ void AndroidConfig::setSdkManagerToolArgs(const QStringList &args) m_sdkManagerToolArgs = args; } -FilePath AndroidConfig::ndkLocation() const +FilePath AndroidConfig::ndkLocation(const BaseQtVersion *qtVersion) const { - return m_ndkLocation; + return sdkLocation().pathAppended(ndkPathFromQtVersion(*qtVersion)); } FilePath AndroidConfig::defaultNdkLocation() const @@ -837,9 +812,9 @@ static inline QString gdbServerArch(const QString &androidAbi) } } -FilePath AndroidConfig::gdbServer(const QString &androidAbi) const +FilePath AndroidConfig::gdbServer(const QString &androidAbi, const BaseQtVersion *qtVersion) const { - const FilePath path = AndroidConfigurations::currentConfig().ndkLocation() + const FilePath path = AndroidConfigurations::currentConfig().ndkLocation(qtVersion) .pathAppended(QString("prebuilt/android-%1/gdbserver/gdbserver") .arg(gdbServerArch(androidAbi))); if (path.exists()) @@ -847,16 +822,21 @@ FilePath AndroidConfig::gdbServer(const QString &androidAbi) const return {}; } -QVersionNumber AndroidConfig::ndkVersion() const +QVersionNumber AndroidConfig::ndkVersion(const BaseQtVersion *qtVersion) const +{ + return ndkVersion(ndkLocation(qtVersion)); +} + +QVersionNumber AndroidConfig::ndkVersion(const FilePath &ndkPath) const { QVersionNumber version; - if (!m_ndkLocation.exists()) { + if (!ndkPath.exists()) { qCDebug(avdConfigLog) << "Cannot find ndk version. Check NDK path." - << m_ndkLocation.toString(); + << ndkPath.toString(); return version; } - const FilePath ndkPropertiesPath = m_ndkLocation.pathAppended("source.properties"); + const FilePath ndkPropertiesPath = ndkPath.pathAppended("source.properties"); if (ndkPropertiesPath.exists()) { // source.properties files exists in NDK version > 11 QSettings settings(ndkPropertiesPath.toString(), QSettings::IniFormat); @@ -864,7 +844,7 @@ QVersionNumber AndroidConfig::ndkVersion() const version = QVersionNumber::fromString(versionStr); } else { // No source.properties. There should be a file named RELEASE.TXT - const FilePath ndkReleaseTxtPath = m_ndkLocation.pathAppended("RELEASE.TXT"); + const FilePath ndkReleaseTxtPath = ndkPath.pathAppended("RELEASE.TXT"); Utils::FileReader reader; QString errorString; if (reader.fetch(ndkReleaseTxtPath.toString(), &errorString)) { @@ -892,12 +872,6 @@ QVersionNumber AndroidConfig::ndkVersion() const return version; } -void AndroidConfig::setNdkLocation(const FilePath &ndkLocation) -{ - m_ndkLocation = ndkLocation; - m_NdkInformationUpToDate = false; -} - QStringList AndroidConfig::allEssentials() const { QList installedVersions = QtVersionManager::versions( @@ -925,7 +899,7 @@ QStringList AndroidConfig::essentialsFromQtVersion(const BaseQtVersion &version) QString AndroidConfig::ndkPathFromQtVersion(const BaseQtVersion &version) const { - QtVersionNumber qtVersion = version.qtVersion(); + QtVersionNumber qtVersion(version.qtVersionString()); for (const SdkForQtVersions &item : m_specificQtVersions) if (item.containsVersion(qtVersion)) return item.ndkPath; @@ -969,10 +943,39 @@ void AndroidConfig::setKeystoreLocation(const FilePath &keystoreLocation) m_keystoreLocation = keystoreLocation; } -QString AndroidConfig::toolchainHost() const +QString AndroidConfig::toolchainHost(const BaseQtVersion *qtVersion) const { - updateNdkInformation(); - return m_toolchainHost; + return toolchainHostFromNdk(ndkLocation(qtVersion)); +} + +QString AndroidConfig::toolchainHostFromNdk(const FilePath &ndkPath) const +{ + // detect toolchain host + QString toolchainHost; + QStringList hostPatterns; + switch (HostOsInfo::hostOs()) { + case OsTypeLinux: + hostPatterns << QLatin1String("linux*"); + break; + case OsTypeWindows: + hostPatterns << QLatin1String("windows*"); + break; + case OsTypeMac: + hostPatterns << QLatin1String("darwin*"); + break; + default: /* unknown host */ + return toolchainHost; + } + + QDirIterator jt(ndkPath.pathAppended("prebuilt").toString(), + hostPatterns, + QDir::Dirs); + if (jt.hasNext()) { + jt.next(); + toolchainHost = jt.fileName(); + } + + return toolchainHost; } unsigned AndroidConfig::partitionSize() const @@ -1087,9 +1090,9 @@ void AndroidConfigurations::removeOldToolChains() } } -static QVariant findOrRegisterDebugger(ToolChain *tc) +static QVariant findOrRegisterDebugger(ToolChain *tc, const BaseQtVersion *qtVersion) { - const FilePath command = AndroidConfigurations::currentConfig().gdbPath(tc->targetAbi()); + const FilePath command = AndroidConfigurations::currentConfig().gdbPath(tc->targetAbi(), qtVersion); // check if the debugger is already registered, but ignoring the display name const Debugger::DebuggerItem *existing = Debugger::DebuggerItemManager::findByCommand(command); if (existing && existing->engineType() == Debugger::GdbEngineType && existing->isAutoDetected() @@ -1116,7 +1119,7 @@ void AndroidConfigurations::updateAutomaticKitList() for (auto k: androidKits) { if (k->value(Constants::ANDROID_KIT_NDK).isNull() || k->value(Constants::ANDROID_KIT_SDK).isNull()) { - k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation().toString()); + k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation(QtSupport::QtKitAspect::qtVersion(k)).toString()); k->setValue(Constants::ANDROID_KIT_SDK, currentConfig().sdkLocation().toString()); } } @@ -1163,16 +1166,22 @@ void AndroidConfigurations::updateAutomaticKitList() for (ToolChain *tc : toolchains) { if (tc->language() != Core::Id(ProjectExplorer::Constants::CXX_LANGUAGE_ID)) continue; - const QList allLanguages = Utils::filtered(toolchains, - [tc](ToolChain *otherTc) { - return tc->targetAbi() == otherTc->targetAbi(); - }); - - QHash toolChainForLanguage; - for (ToolChain *tc : allLanguages) - toolChainForLanguage[tc->language()] = tc; for (const QtSupport::BaseQtVersion *qt : qtVersionsForArch.value(tc->targetAbi())) { + FilePath tcNdk = static_cast(tc)->ndkLocation(); + if (tcNdk != currentConfig().ndkLocation(qt)) + continue; + + const QList allLanguages + = Utils::filtered(toolchains, [tc, tcNdk](ToolChain *otherTc) { + FilePath otherNdk = static_cast(otherTc)->ndkLocation(); + return tc->targetAbi() == otherTc->targetAbi() && tcNdk == otherNdk; + }); + + QHash toolChainForLanguage; + for (ToolChain *tc : allLanguages) + toolChainForLanguage[tc->language()] = tc; + Kit *existingKit = Utils::findOrDefault(existingKits, [&](const Kit *b) { if (qt != QtSupport::QtKitAspect::qtVersion(b)) return false; @@ -1190,12 +1199,12 @@ void AndroidConfigurations::updateAutomaticKitList() ToolChainKitAspect::setToolChain(k, tc); QtSupport::QtKitAspect::setQtVersion(k, qt); DeviceKitAspect::setDevice(k, device); - Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc)); + Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc, QtKitAspect::qtVersion(k))); k->makeSticky(); k->setUnexpandedDisplayName(tr("Android for %1 (Clang %2)") .arg(static_cast(qt)->androidAbis().join(",")) .arg(qt->displayName())); - k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation().toString()); + k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation(qt).toString()); k->setValueSilently(Constants::ANDROID_KIT_SDK, currentConfig().sdkLocation().toString()); }; diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 93250713aa7..4a4217e3a2c 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -122,11 +122,11 @@ public: QStringList sdkManagerToolArgs() const; void setSdkManagerToolArgs(const QStringList &args); - Utils::FilePath ndkLocation() const; + Utils::FilePath ndkLocation(const QtSupport::BaseQtVersion *qtVersion) const; Utils::FilePath defaultNdkLocation() const; - Utils::FilePath gdbServer(const QString &androidAbi) const; - QVersionNumber ndkVersion() const; - void setNdkLocation(const Utils::FilePath &ndkLocation); + Utils::FilePath gdbServer(const QString &androidAbi, const QtSupport::BaseQtVersion *qtVersion) const; + QVersionNumber ndkVersion(const QtSupport::BaseQtVersion *qtVersion) const; + QVersionNumber ndkVersion(const Utils::FilePath &ndkPath) const; QUrl sdkToolsUrl() const { return m_sdkToolsUrl; }; QByteArray getSdkToolsSha256() const { return m_sdkToolsSha256; }; @@ -143,7 +143,8 @@ public: Utils::FilePath keystoreLocation() const; void setKeystoreLocation(const Utils::FilePath &keystoreLocation); - QString toolchainHost() const; + QString toolchainHost(const QtSupport::BaseQtVersion *qtVersion) const; + QString toolchainHostFromNdk(const Utils::FilePath &ndkPath) const; unsigned partitionSize() const; void setPartitionSize(unsigned partitionSize); @@ -158,18 +159,19 @@ public: Utils::FilePath avdManagerToolPath() const; Utils::FilePath aaptToolPath() const; - Utils::FilePath toolchainPath() const; - Utils::FilePath clangPath() const; + Utils::FilePath toolchainPath(const QtSupport::BaseQtVersion *qtVersion) const; + Utils::FilePath clangPath(const QtSupport::BaseQtVersion *qtVersion) const; - Utils::FilePath gdbPath(const ProjectExplorer::Abi &abi) const; - Utils::FilePath makePath() const; + Utils::FilePath gdbPath(const ProjectExplorer::Abi &abi, const QtSupport::BaseQtVersion *qtVersion) const; + Utils::FilePath makePath(const QtSupport::BaseQtVersion *qtVersion) const; + Utils::FilePath makePathFromNdk(const Utils::FilePath &ndkLocation) const; Utils::FilePath keytoolPath() const; QVector connectedDevices(QString *error = nullptr) const; static QVector connectedDevices(const Utils::FilePath &adbToolPath, QString *error = nullptr); - QString bestNdkPlatformMatch(int target) const; + QString bestNdkPlatformMatch(int target, const QtSupport::BaseQtVersion *qtVersion) const; static ProjectExplorer::Abi abiForToolChainPrefix(const QString &toolchainPrefix); static QLatin1String toolchainPrefix(const ProjectExplorer::Abi &abi); @@ -199,12 +201,12 @@ private: bool isBootToQt(const QString &device) const; static QString getAvdName(const QString &serialnumber); - void updateNdkInformation() const; void parseDependenciesJson(); + QVector availableNdkPlatforms(const QtSupport::BaseQtVersion *qtVersion) const; + Utils::FilePath m_sdkLocation; QStringList m_sdkManagerToolArgs; - Utils::FilePath m_ndkLocation; Utils::FilePath m_openJDKLocation; Utils::FilePath m_keystoreLocation; unsigned m_partitionSize = 1024; @@ -217,10 +219,6 @@ private: bool m_sdkFullyConfigured = false; //caches - mutable bool m_NdkInformationUpToDate = false; - mutable QString m_toolchainHost; - mutable QVector m_availableNdkPlatforms; - mutable QHash m_serialNumberToDeviceName; }; diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index 1d5737552ef..3ffed5e7ecb 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -122,14 +122,13 @@ void AndroidDebugSupport::start() qCDebug(androidDebugSupportLog) << "Start. Package name: " << packageName << "PID: " << m_runner->pid().pid(); + QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit); if (!Utils::HostOsInfo::isWindowsHost() && - AndroidConfigurations::currentConfig().ndkVersion() >= QVersionNumber(11, 0, 0)) { + AndroidConfigurations::currentConfig().ndkVersion(qtVersion) >= QVersionNumber(11, 0, 0)) { qCDebug(androidDebugSupportLog) << "UseTargetAsync: " << true; setUseTargetAsync(true); } - QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit); - if (isCppDebugging()) { qCDebug(androidDebugSupportLog) << "C++ debugging enabled"; const ProjectNode *node = target->project()->findNodeForBuildKey(runControl()->buildKey()); @@ -160,7 +159,7 @@ void AndroidDebugSupport::start() // TODO find a way to use the new sysroot layout // instead ~/android/ndk-bundle/platforms/android-29/arch-arm64 // use ~/android/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/sysroot - Utils::FilePath sysRoot = AndroidConfigurations::currentConfig().ndkLocation() + Utils::FilePath sysRoot = AndroidConfigurations::currentConfig().ndkLocation(qtVersion) .pathAppended("platforms") .pathAppended(QString("android-%1").arg(sdkVersion)) .pathAppended(devicePreferredAbi); diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 16a50c48a5f..9b94f3473ce 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -293,22 +293,25 @@ QJsonObject AndroidManager::deploymentSettings(const Target *target) QJsonObject settings; settings["_description"] = qtcSignature; settings["qt"] = qt->prefix().toString(); - settings["ndk"] = AndroidConfigurations::currentConfig().ndkLocation().toString(); + settings["ndk"] = AndroidConfigurations::currentConfig().ndkLocation(qt).toString(); settings["sdk"] = AndroidConfigurations::currentConfig().sdkLocation().toString(); if (qt->qtVersion() < QtSupport::QtVersionNumber(5, 14, 0)) { const QStringList abis = applicationAbis(target); QTC_ASSERT(abis.size() == 1, return {}); - settings["stdcpp-path"] = AndroidConfigurations::currentConfig().toolchainPath() + settings["stdcpp-path"] = AndroidConfigurations::currentConfig().toolchainPath(qt) .pathAppended("sysroot/usr/lib/") .pathAppended(archTriplet(abis.first())) .pathAppended("libc++_shared.so").toString(); } else { - settings["stdcpp-path"] = AndroidConfigurations::currentConfig().toolchainPath().pathAppended("sysroot/usr/lib/").toString(); + settings["stdcpp-path"] = AndroidConfigurations::currentConfig() + .toolchainPath(qt) + .pathAppended("sysroot/usr/lib/") + .toString(); } settings["toolchain-prefix"] = "llvm"; settings["tool-prefix"] = "llvm"; settings["useLLVM"] = true; - settings["ndk-host"] = AndroidConfigurations::currentConfig().toolchainHost(); + settings["ndk-host"] = AndroidConfigurations::currentConfig().toolchainHost(qt); return settings; } diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp index 7f98cb2f9d5..6f0bff08bcb 100644 --- a/src/plugins/android/androidmanifesteditorwidget.cpp +++ b/src/plugins/android/androidmanifesteditorwidget.cpp @@ -34,6 +34,8 @@ #include #include +#include + #include #include #include @@ -612,8 +614,10 @@ void AndroidManifestEditorWidget::postSave() const Utils::FilePath docPath = m_textEditorWidget->textDocument()->filePath(); if (Target *target = androidTarget(docPath)) { if (BuildConfiguration *bc = target->activeBuildConfiguration()) { - QString androidNdkPlatform = AndroidConfigurations::currentConfig() - .bestNdkPlatformMatch(AndroidManager::minimumSDK(target)); + QString androidNdkPlatform = AndroidConfigurations::currentConfig().bestNdkPlatformMatch( + AndroidManager::minimumSDK(target), + QtSupport::QtKitAspect::qtVersion( + androidTarget(m_textEditorWidget->textDocument()->filePath())->kit())); if (m_androidNdkPlatform != androidNdkPlatform) { m_androidNdkPlatform = androidNdkPlatform; bc->updateCacheAndEmitEnvironmentChanged(); diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 43a50e29e3e..1fcdd9bd720 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -178,6 +178,7 @@ void AndroidPlugin::kitsRestored() } AndroidConfigurations::updateAutomaticKitList(); + AndroidConfigurations::registerNewToolChains(); connect(QtSupport::QtVersionManager::instance(), &QtSupport::QtVersionManager::qtVersionsChanged, AndroidConfigurations::instance(), &AndroidConfigurations::updateAutomaticKitList); disconnect(KitManager::instance(), &KitManager::kitsLoaded, diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index 48aeab8e543..9b6a2df57c5 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -70,7 +70,7 @@ QString AndroidQtVersion::invalidReason() const { QString tmp = BaseQtVersion::invalidReason(); if (tmp.isEmpty()) { - if (AndroidConfigurations::currentConfig().ndkLocation().isEmpty()) + if (AndroidConfigurations::currentConfig().ndkLocation(this).isEmpty()) return tr("NDK is not configured in Devices > Android."); if (AndroidConfigurations::currentConfig().sdkLocation().isEmpty()) return tr("SDK is not configured in Devices > Android."); @@ -126,16 +126,17 @@ void AndroidQtVersion::addToEnvironment(const Kit *k, Utils::Environment &env) c { const AndroidConfig &config =AndroidConfigurations::currentConfig(); // this env vars are used by qmake mkspecs to generate makefiles (check QTDIR/mkspecs/android-g++/qmake.conf for more info) - env.set(QLatin1String("ANDROID_NDK_HOST"), config.toolchainHost()); - env.set(QLatin1String("ANDROID_NDK_ROOT"), config.ndkLocation().toUserOutput()); + env.set(QLatin1String("ANDROID_NDK_HOST"), config.toolchainHost(this)); + env.set(QLatin1String("ANDROID_NDK_ROOT"), config.ndkLocation(this).toUserOutput()); env.set(QLatin1String("ANDROID_NDK_PLATFORM"), - config.bestNdkPlatformMatch(qMax(minimumNDK(), AndroidManager::minimumSDK(k)))); + config.bestNdkPlatformMatch(qMax(minimumNDK(), AndroidManager::minimumSDK(k)), this)); } Utils::Environment AndroidQtVersion::qmakeRunEnvironment() const { Utils::Environment env = Utils::Environment::systemEnvironment(); - env.set(QLatin1String("ANDROID_NDK_ROOT"), AndroidConfigurations::currentConfig().ndkLocation().toUserOutput()); + env.set(QLatin1String("ANDROID_NDK_ROOT"), + AndroidConfigurations::currentConfig().ndkLocation(this).toUserOutput()); return env; } diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index db5e9807e69..1fb878109f6 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -225,10 +225,11 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa << "Extra Start Args:" << m_amStartExtraArgs << "Before Start ADB cmds:" << m_beforeStartAdbCommands << "After finish ADB cmds:" << m_afterFinishAdbCommands; + QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit()); QString preferredAbi = AndroidManager::apkDevicePreferredAbi(target); if (!preferredAbi.isEmpty()) - m_gdbserverPath = AndroidConfigurations::instance()->currentConfig().gdbServer(preferredAbi).toString(); - QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit()); + m_gdbserverPath = AndroidConfigurations::instance() + ->currentConfig().gdbServer(preferredAbi, version).toString(); m_useAppParamsForQmlDebugger = version->qtVersion() >= QtSupport::QtVersionNumber(5, 12); } diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index bd7b1add50f..e70a7ce34fb 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -336,10 +336,8 @@ Utils::FilePath AndroidSettingsWidget::getDefaultSdkPath() void AndroidSettingsWidget::updateNdkList() { m_ui->ndkListComboBox->clear(); - QString currentNdk = m_androidConfig.ndkLocation().toString(); for (const Ndk *ndk : m_sdkManager->installedNdkPackages()) m_ui->ndkListComboBox->addItem(ndk->installedLocation().toString()); - m_ui->ndkListComboBox->setCurrentText(currentNdk); } AndroidSettingsWidget::AndroidSettingsWidget() @@ -584,7 +582,6 @@ Utils::FilePath AndroidSettingsWidget::findJdkInCommonPaths() void AndroidSettingsWidget::validateNdk() { auto ndkPath = Utils::FilePath::fromUserInput(m_ui->ndkListComboBox->currentText()); - m_androidConfig.setNdkLocation(ndkPath); auto summaryWidget = static_cast(m_ui->androidDetailsWidget->widget()); summaryWidget->setPointValid(NdkPathExistsRow, ndkPath.exists()); @@ -745,9 +742,10 @@ void AndroidSettingsWidget::updateUI() m_ui->sdkManagerTab->setEnabled(sdkToolsOk); m_sdkManagerWidget->setSdkManagerControlsEnabled(!m_androidConfig.useNativeUiTools()); + Utils::FilePath currentNdk = Utils::FilePath::fromString(m_ui->ndkListComboBox->currentText()); auto infoText = tr("(SDK Version: %1, NDK Bundle Version: %2)") - .arg(m_androidConfig.sdkToolsVersion().toString()) - .arg(m_androidConfig.ndkVersion().toString()); + .arg(m_androidConfig.sdkToolsVersion().toString()) + .arg(currentNdk.isEmpty() ? "" : m_androidConfig.ndkVersion(currentNdk).toString()); androidSummaryWidget->setInfoText(androidSetupOk ? infoText : ""); m_ui->javaDetailsWidget->setState(javaSetupOk ? Utils::DetailsWidget::Collapsed : diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index b132d0042bd..a9f5aeb2816 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -27,6 +27,7 @@ #include "androidconstants.h" #include "androidconfigurations.h" +#include #include #include @@ -78,22 +79,36 @@ AndroidToolChain::AndroidToolChain() setTypeDisplayName(AndroidToolChainFactory::tr("Android Clang")); } +Utils::FilePath AndroidToolChain::ndkLocation() const +{ + return m_ndkLocation; +} + +void AndroidToolChain::setNdkLocation(const Utils::FilePath &ndkLocation) +{ + m_ndkLocation = ndkLocation; +} + AndroidToolChain::~AndroidToolChain() = default; bool AndroidToolChain::isValid() const { - return ClangToolChain::isValid() - && typeId() == Constants::ANDROID_TOOLCHAIN_TYPEID - && targetAbi().isValid() - && compilerCommand().isChildOf(AndroidConfigurations::currentConfig().ndkLocation()) - && !originalTargetTriple().isEmpty(); + const bool isChildofNdk = compilerCommand().isChildOf(m_ndkLocation); + // If we're restoring a toolchain we set NDK path ourselves so it's enough to check against SDK + const bool isChildofSdk = compilerCommand().isChildOf( + AndroidConfigurations::currentConfig().sdkLocation()); + + return ClangToolChain::isValid() && typeId() == Constants::ANDROID_TOOLCHAIN_TYPEID + && targetAbi().isValid() + && (isChildofNdk || isChildofSdk) + && !originalTargetTriple().isEmpty(); } void AndroidToolChain::addToEnvironment(Environment &env) const { - env.set(QLatin1String("ANDROID_NDK_HOST"), - AndroidConfigurations::currentConfig().toolchainHost()); - const Utils::FilePath javaHome = AndroidConfigurations::currentConfig().openJDKLocation(); + AndroidConfig config = AndroidConfigurations::currentConfig(); + env.set(QLatin1String("ANDROID_NDK_HOST"), config.toolchainHostFromNdk(m_ndkLocation)); + const Utils::FilePath javaHome = config.openJDKLocation(); if (javaHome.exists()) { env.set(QLatin1String("JAVA_HOME"), javaHome.toString()); const FilePath javaBin = javaHome.pathAppended("bin"); @@ -101,10 +116,8 @@ void AndroidToolChain::addToEnvironment(Environment &env) const if (!currentJavaFilePath.isChildOf(javaBin)) env.prependOrSetPath(javaBin.toUserOutput()); } - env.set(QLatin1String("ANDROID_HOME"), - AndroidConfigurations::currentConfig().sdkLocation().toString()); - env.set(QLatin1String("ANDROID_SDK_ROOT"), - AndroidConfigurations::currentConfig().sdkLocation().toString()); + env.set(QLatin1String("ANDROID_HOME"), config.sdkLocation().toString()); + env.set(QLatin1String("ANDROID_SDK_ROOT"), config.sdkLocation().toString()); } bool AndroidToolChain::fromMap(const QVariantMap &data) @@ -122,7 +135,7 @@ QStringList AndroidToolChain::suggestedMkspecList() const FilePath AndroidToolChain::makeCommand(const Environment &env) const { Q_UNUSED(env) - FilePath makePath = AndroidConfigurations::currentConfig().makePath(); + FilePath makePath = AndroidConfigurations::currentConfig().makePathFromNdk(m_ndkLocation); return makePath.exists() ? makePath : FilePath::fromString("make"); } @@ -160,53 +173,83 @@ static FilePath clangPlusPlusPath(const FilePath &clangPath) QFileInfo(clangPath.toString()).baseName() + "++")); } +static QList androidQtVersionsWithUniqueNdk() +{ + AndroidConfig config = AndroidConfigurations::currentConfig(); + + auto androidQtVersions = QtSupport::QtVersionManager::versions( + [](const QtSupport::BaseQtVersion *v) { + return v->targetDeviceTypes().contains(Android::Constants::ANDROID_DEVICE_TYPE); + }); + + auto shouldRemove = [config](const QtSupport::BaseQtVersion *first, + const QtSupport::BaseQtVersion *second) { + return config.ndkLocation(first) == config.ndkLocation(second); + }; + + QList::iterator it = std::unique(androidQtVersions.begin(), + androidQtVersions.end(), + shouldRemove); + androidQtVersions.erase(it, androidQtVersions.end()); + + return androidQtVersions; +} + ToolChainList AndroidToolChainFactory::autodetectToolChainsForNdk(const ToolChainList &alreadyKnown) { QList result; - FilePath clangPath = AndroidConfigurations::currentConfig().clangPath(); - if (!clangPath.exists()) { - qCDebug(androidTCLog) << "Clang toolchains detection fails. Can not find Clang"<< clangPath; - return result; - } + const QList androidQtVersions = androidQtVersionsWithUniqueNdk(); + const AndroidConfig config = AndroidConfigurations::currentConfig(); - qCDebug(androidTCLog) << "Detecting toolchains from Android NDK:" - << AndroidConfigurations::currentConfig().ndkLocation(); - - for (const Core::Id &lang : LanguageIds) { - FilePath compilerCommand = clangPath; - if (lang == ProjectExplorer::Constants::CXX_LANGUAGE_ID) - compilerCommand = clangPlusPlusPath(clangPath); - - if (!compilerCommand.exists()) { - qCDebug(androidTCLog) << "Skipping Clang toolchain. Can not find compiler" - << compilerCommand; - continue; + for (const QtSupport::BaseQtVersion *qtVersion : androidQtVersions) { + FilePath clangPath = config.clangPath(qtVersion); + if (!clangPath.exists()) { + qCDebug(androidTCLog) << "Clang toolchains detection fails. Can not find Clang" + << clangPath; + return result; } - auto targetItr = ClangTargets.constBegin(); - while (targetItr != ClangTargets.constEnd()) { - const Abi &abi = targetItr.value(); - const QString target = targetItr.key(); - ToolChain *tc = findToolChain(compilerCommand, lang, target, alreadyKnown); - if (tc) { - qCDebug(androidTCLog) << "Tool chain already known" << abi.toString() << lang; - } else { - qCDebug(androidTCLog) << "New Clang toolchain found" << abi.toString() << lang; - auto atc = new AndroidToolChain; - atc->setOriginalTargetTriple(target); - atc->setLanguage(lang); - atc->setTargetAbi(ClangTargets[target]); - atc->setPlatformCodeGenFlags({"-target", target}); - atc->setPlatformLinkerFlags({"-target", target}); - atc->setDetection(ToolChain::AutoDetection); - atc->setDisplayName(QString("Android Clang (%1, %2)") - .arg(ToolChainManager::displayNameOfLanguageId(lang), - AndroidConfig::displayName(abi))); - atc->resetToolChain(compilerCommand); - tc = atc; + qCDebug(androidTCLog) << "Detecting toolchains from Android NDK:" + << config.ndkLocation(qtVersion); + + for (const Core::Id &lang : LanguageIds) { + FilePath compilerCommand = clangPath; + if (lang == ProjectExplorer::Constants::CXX_LANGUAGE_ID) + compilerCommand = clangPlusPlusPath(clangPath); + + if (!compilerCommand.exists()) { + qCDebug(androidTCLog) + << "Skipping Clang toolchain. Can not find compiler" << compilerCommand; + continue; + } + + auto targetItr = ClangTargets.constBegin(); + while (targetItr != ClangTargets.constEnd()) { + const Abi &abi = targetItr.value(); + const QString target = targetItr.key(); + ToolChain *tc = findToolChain(compilerCommand, lang, target, alreadyKnown); + if (tc) { + qCDebug(androidTCLog) << "Tool chain already known" << abi.toString() << lang; + } else { + qCDebug(androidTCLog) << "New Clang toolchain found" << abi.toString() << lang; + auto atc = new AndroidToolChain(); + atc->setNdkLocation(config.ndkLocation(qtVersion)); + atc->setOriginalTargetTriple(target); + atc->setLanguage(lang); + atc->setTargetAbi(ClangTargets[target]); + atc->setPlatformCodeGenFlags({"-target", target}); + atc->setPlatformLinkerFlags({"-target", target}); + atc->setDetection(ToolChain::AutoDetection); + atc->setDisplayName(QString("Android Clang (%1, %2, NDK %3)") + .arg(ToolChainManager::displayNameOfLanguageId(lang), + AndroidConfig::displayName(abi), + config.ndkVersion(qtVersion).toString())); + atc->resetToolChain(compilerCommand); + tc = atc; + } + result << tc; + ++targetItr; } - result << tc; - ++targetItr; } } diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h index 7f620dd9805..26c55f20a13 100644 --- a/src/plugins/android/androidtoolchain.h +++ b/src/plugins/android/androidtoolchain.h @@ -25,6 +25,8 @@ #pragma once +#include + #include namespace Android { @@ -44,6 +46,9 @@ public: Utils::FilePath makeCommand(const Utils::Environment &environment) const override; bool fromMap(const QVariantMap &data) override; + void setNdkLocation(const Utils::FilePath &ndkLocation); + Utils::FilePath ndkLocation() const; + protected: DetectedAbisResult detectSupportedAbis() const override; @@ -51,6 +56,8 @@ private: explicit AndroidToolChain(); friend class AndroidToolChainFactory; + + Utils::FilePath m_ndkLocation; }; class AndroidToolChainFactory : public ProjectExplorer::ToolChainFactory