diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 3da456cf377..80a5d39dcc7 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -93,7 +93,6 @@ namespace { const QLatin1String OpenJDKLocationKey("OpenJDKLocation"); const QLatin1String KeystoreLocationKey("KeystoreLocation"); const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation"); - const QLatin1String MakeExtraSearchDirectory("MakeExtraSearchDirectory"); const QLatin1String PartitionSizeKey("PartitionSize"); const QLatin1String ToolchainHostKey("ToolchainHost"); @@ -256,10 +255,6 @@ void AndroidConfig::load(const QSettings &settings) m_keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString()); m_toolchainHost = settings.value(ToolchainHostKey).toString(); m_automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool(); - QString extraDirectory = settings.value(MakeExtraSearchDirectory).toString(); - m_makeExtraSearchDirectories.clear(); - if (!extraDirectory.isEmpty()) - m_makeExtraSearchDirectories << extraDirectory; PersistentSettingsReader reader; if (reader.load(FileName::fromString(sdkSettingsFileName())) @@ -272,10 +267,6 @@ void AndroidConfig::load(const QSettings &settings) m_keystoreLocation = FileName::fromString(reader.restoreValue(KeystoreLocationKey, m_keystoreLocation.toString()).toString()); m_toolchainHost = reader.restoreValue(ToolchainHostKey, m_toolchainHost).toString(); m_automaticKitCreation = reader.restoreValue(AutomaticKitCreationKey, m_automaticKitCreation).toBool(); - QString extraDirectory = reader.restoreValue(MakeExtraSearchDirectory).toString(); - m_makeExtraSearchDirectories.clear(); - if (!extraDirectory.isEmpty()) - m_makeExtraSearchDirectories << extraDirectory; // persistent settings } m_NdkInformationUpToDate = false; @@ -296,9 +287,6 @@ void AndroidConfig::save(QSettings &settings) const settings.setValue(PartitionSizeKey, m_partitionSize); settings.setValue(AutomaticKitCreationKey, m_automaticKitCreation); settings.setValue(ToolchainHostKey, m_toolchainHost); - settings.setValue(MakeExtraSearchDirectory, - m_makeExtraSearchDirectories.isEmpty() ? QString() - : m_makeExtraSearchDirectories.at(0)); } void AndroidConfig::updateNdkInformation() const @@ -382,16 +370,6 @@ FileName AndroidConfig::emulatorToolPath() const return path.appendPath(relativePath + QTC_HOST_EXE_SUFFIX); } -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(abi)) - .arg(ndkToolChainVersion) - .arg(toolchainHost()) - .arg(toolsPrefix(abi))); -} - FileName AndroidConfig::sdkManagerToolPath() const { FileName sdkPath = m_sdkLocation; @@ -423,28 +401,47 @@ FileName AndroidConfig::aaptToolPath() const return aaptToolPath; } -FileName AndroidConfig::gccPath(const Abi &abi, Core::Id lang, - const QString &ndkToolChainVersion) const +FileName AndroidConfig::clangPath() const { - const QString tool - = HostOsInfo::withExecutableSuffix(QString::fromLatin1(lang == Core::Id(ProjectExplorer::Constants::C_LANGUAGE_ID) ? "-gcc" : "-g++")); - return toolPath(abi, ndkToolChainVersion).appendString(tool); + FileName clangPath = m_ndkLocation; + clangPath.appendPath("toolchains/llvm/prebuilt/"); + + // 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 FileName(); + } + + QDirIterator iter(clangPath.toString(), hostPatterns, QDir::Dirs); + if (iter.hasNext()) { + iter.next(); + return clangPath.appendPath(iter.fileName()).appendPath("bin/clang"); + } + + return clangPath; } -FileName AndroidConfig::gdbPath(const Abi &abi, const QString &ndkToolChainVersion) const +FileName AndroidConfig::gdbPath() const { - const auto gdbPath = QString::fromLatin1("%1/prebuilt/%2/bin/gdb" QTC_HOST_EXE_SUFFIX).arg(m_ndkLocation.toString()).arg(toolchainHost()); - if (QFile::exists(gdbPath)) - return FileName::fromString(gdbPath); - - return toolPath(abi, ndkToolChainVersion).appendString(QLatin1String("-gdb" QTC_HOST_EXE_SUFFIX)); + FileName path = m_ndkLocation; + path.appendPath(QString("prebuilt/%1/bin/gdb%2").arg(toolchainHost(), QTC_HOST_EXE_SUFFIX)); + return path; } FileName AndroidConfig::makePath() const { - const QString makePath = QString::fromLatin1("%1/prebuilt/%2/bin/make" QTC_HOST_EXE_SUFFIX) - .arg(m_ndkLocation.toString()).arg(toolchainHost()); - return FileName::fromString(makePath); + FileName path = m_ndkLocation; + path.appendPath(QString("prebuilt/%1/bin/make%2").arg(toolchainHost(), QTC_HOST_EXE_SUFFIX)); + return path; } FileName AndroidConfig::openJDKBinPath() const @@ -868,11 +865,6 @@ QString AndroidConfig::toolchainHost() const return m_toolchainHost; } -QStringList AndroidConfig::makeExtraSearchDirectories() const -{ - return m_makeExtraSearchDirectories; -} - unsigned AndroidConfig::partitionSize() const { return m_partitionSize; @@ -965,8 +957,7 @@ static bool matchToolChain(const ToolChain *atc, const ToolChain *btc) auto aatc = static_cast(atc); auto abtc = static_cast(btc); - return aatc->ndkToolChainVersion() == abtc->ndkToolChainVersion() - && aatc->targetAbi() == abtc->targetAbi(); + return aatc->targetAbi() == abtc->targetAbi(); } static bool matchKits(const Kit *a, const Kit *b) @@ -986,8 +977,7 @@ void AndroidConfigurations::registerNewToolChains() = ToolChainManager::toolChains(Utils::equal(&ToolChain::typeId, Core::Id(Constants::ANDROID_TOOLCHAIN_ID))); const QList newToolchains - = AndroidToolChainFactory::autodetectToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation(), - existingAndroidToolChains); + = AndroidToolChainFactory::autodetectToolChainsForNdk(existingAndroidToolChains); foreach (ToolChain *tc, newToolchains) ToolChainManager::registerToolChain(tc); } @@ -1014,22 +1004,6 @@ void AndroidConfigurations::updateAutomaticKitList() return false; }); - // Update code for 3.0 beta, which shipped with a bug for the debugger settings - for (Kit *k : existingKits) { - ToolChain *tc = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID); - if (tc && Debugger::DebuggerKitInformation::runnable(k).executable != tc->suggestedDebugger().toString()) { - Debugger::DebuggerItem debugger; - debugger.setCommand(tc->suggestedDebugger()); - debugger.setEngineType(Debugger::GdbEngineType); - debugger.setUnexpandedDisplayName(tr("Android Debugger for %1").arg(tc->displayName())); - debugger.setAutoDetected(true); - debugger.setAbi(tc->targetAbi()); - debugger.reinitializeFromFile(); - QVariant id = Debugger::DebuggerItemManager::registerDebugger(debugger); - Debugger::DebuggerKitInformation::setDebugger(k, id); - } - } - QHash > qtVersionsForArch; const QList qtVersions = QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) { @@ -1052,18 +1026,16 @@ void AndroidConfigurations::updateAutomaticKitList() } // register new kits - const QList tmp = ToolChainManager::toolChains([](const ToolChain *tc) { + const QList toolchains = ToolChainManager::toolChains([](const ToolChain *tc) { return tc->isAutoDetected() && tc->isValid() - && tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID - && !static_cast(tc)->isSecondaryToolChain(); + && tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID; }); - const auto toolchains = Utils::static_container_cast(tmp); - for (AndroidToolChain *tc : toolchains) { - if (tc->isSecondaryToolChain() || tc->language() != Core::Id(ProjectExplorer::Constants::CXX_LANGUAGE_ID)) + for (ToolChain *tc : toolchains) { + if (tc->language() != Core::Id(ProjectExplorer::Constants::CXX_LANGUAGE_ID)) continue; - const QList allLanguages = Utils::filtered(toolchains, - [tc](AndroidToolChain *otherTc) { + const QList allLanguages = Utils::filtered(toolchains, + [tc](ToolChain *otherTc) { return tc->targetAbi() == otherTc->targetAbi(); }); @@ -1071,7 +1043,7 @@ void AndroidConfigurations::updateAutomaticKitList() k->setAutoDetected(true); k->setAutoDetectionSource("AndroidConfiguration"); DeviceTypeKitInformation::setDeviceTypeId(k, Core::Id(Constants::ANDROID_DEVICE_TYPE)); - for (AndroidToolChain *tc : allLanguages) + for (ToolChain *tc : allLanguages) ToolChainKitInformation::setToolChain(k, tc); QtSupport::QtKitInformation::setQtVersion(k, qt); DeviceKitInformation::setDevice(k, device); @@ -1104,9 +1076,9 @@ void AndroidConfigurations::updateAutomaticKitList() AndroidGdbServerKitInformation::setGdbSever(toSetup, currentConfig().gdbServer(tc->targetAbi())); toSetup->makeSticky(); - toSetup->setUnexpandedDisplayName(tr("Android for %1 (GCC %2, %3)") + + toSetup->setUnexpandedDisplayName(tr("Android for %1 (Clang %2)") .arg(static_cast(qt)->targetArch()) - .arg(tc->ndkToolChainVersion()) .arg(qt->displayName())); if (!existingKit) KitManager::registerKit(std::move(newKit)); diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 99544da511e..dff705bb1cd 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -117,7 +117,6 @@ public: void setKeystoreLocation(const Utils::FileName &keystoreLocation); QString toolchainHost() const; - QStringList makeExtraSearchDirectories() const; unsigned partitionSize() const; void setPartitionSize(unsigned partitionSize); @@ -134,10 +133,8 @@ public: Utils::FileName avdManagerToolPath() const; Utils::FileName aaptToolPath() const; - Utils::FileName gccPath(const ProjectExplorer::Abi &abi, Core::Id lang, - const QString &ndkToolChainVersion) const; - - Utils::FileName gdbPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const; + Utils::FileName clangPath() const; + Utils::FileName gdbPath() const; Utils::FileName makePath() const; Utils::FileName keytoolPath() const; @@ -162,7 +159,6 @@ public: private: static QString getDeviceProperty(const QString &adbToolPath, const QString &device, const QString &property); - Utils::FileName toolPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const; Utils::FileName openJDKBinPath() const; int getSDKVersion(const QString &device) const; static int getSDKVersion(const QString &adbToolPath, const QString &device); @@ -179,7 +175,6 @@ private: Utils::FileName m_ndkLocation; Utils::FileName m_openJDKLocation; Utils::FileName m_keystoreLocation; - QStringList m_makeExtraSearchDirectories; unsigned m_partitionSize = 1024; bool m_automaticKitCreation = true; diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index 4ab1f4f0cca..8bd4dd0cea8 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -26,31 +26,19 @@ #include "androidtoolchain.h" #include "androidconstants.h" #include "androidconfigurations.h" -#include "androidqtversion.h" -#include - -#include -#include - -#include #include #include -#include #include -#include -#include -#include -#include -#include -#include +#include +#include #include -#include + namespace { - const QLatin1String NDKGccVersionRegExp("-\\d[\\.\\d]+"); +Q_LOGGING_CATEGORY(androidTCLog, "qtc.android.toolchainmanagement"); } namespace Android { @@ -59,108 +47,51 @@ namespace Internal { using namespace ProjectExplorer; 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"; +static const QHash ClangTargets = { + {"arm-linux-androideabi", + Abi(Abi::ArmArchitecture, Abi::LinuxOS, Abi::AndroidLinuxFlavor, Abi::ElfFormat, 32)}, + {"i686-linux-android", + Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::AndroidLinuxFlavor, Abi::ElfFormat, 32)}, + {"x86_64-linux-android", + Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::AndroidLinuxFlavor, Abi::ElfFormat, 64)}, + {"aarch64-linux-android", + Abi(Abi::ArmArchitecture, Abi::LinuxOS, Abi::AndroidLinuxFlavor, Abi::ElfFormat, 64)}}; -QHash > AndroidToolChainFactory::m_newestVersionForAbi; -FileName AndroidToolChainFactory::m_ndkLocation; +static const QList LanguageIds = {ProjectExplorer::Constants::CXX_LANGUAGE_ID, + ProjectExplorer::Constants::C_LANGUAGE_ID}; -AndroidToolChain::AndroidToolChain(const Abi &abi, const QString &ndkToolChainVersion, Core::Id l, Detection d) - : GccToolChain(Constants::ANDROID_TOOLCHAIN_ID, d), - m_ndkToolChainVersion(ndkToolChainVersion), m_secondaryToolChain(false) +static ToolChain *findToolChain(Utils::FileName &compilerPath, Core::Id lang, const QString &target, + CToolChainList &alreadyKnown) { - setLanguage(l); - setTargetAbi(abi); - setDisplayName(QString::fromLatin1("Android GCC (%1, %2-%3)") - .arg(ToolChainManager::displayNameOfLanguageId(l), - AndroidConfig::displayName(targetAbi()), - ndkToolChainVersion)); + ToolChain * tc = Utils::findOrDefault(alreadyKnown, [target, compilerPath, lang](ToolChain *tc) { + return tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID + && tc->language() == lang + && tc->targetAbi() == ClangTargets[target] + && tc->compilerCommand() == compilerPath; + }); + return tc; } -// for fromMap -AndroidToolChain::AndroidToolChain() - : GccToolChain(Constants::ANDROID_TOOLCHAIN_ID, ToolChain::ManualDetection), - m_secondaryToolChain(false) -{ -} - -AndroidToolChain::AndroidToolChain(const AndroidToolChain &tc) = default; - AndroidToolChain::~AndroidToolChain() = default; -static QString getArch(const QString &triple) -{ - if (triple.indexOf("x86_64") == 0) - return QString::fromUtf8("x86_64"); - if (triple.indexOf("i686") == 0) - return QString::fromUtf8("x86"); - if (triple.indexOf("mips64") == 0) - return QString::fromUtf8("mips64"); - if (triple.indexOf("mips") == 0) - return QString::fromUtf8("mips"); - if (triple.indexOf("aarch64") == 0) - return QString::fromUtf8("arm64-v8a"); - return QString::fromUtf8("armeabi-v7a"); -} - -// Paths added here are those that were used by qmake. They were taken from -// *qtsource*/qtbase/mkspecs/common/android-base-head.conf -// Adding them here allows us to use them for all build systems. -static void addBuiltInHeaderPaths(ProjectExplorer::HeaderPaths &paths, - const QString &triple, const QString &version) -{ - const Utils::FileName ndkPath = AndroidConfigurations::currentConfig().ndkLocation(); - - // Get short version (for example 4.9) - auto versionNumber = QVersionNumber::fromString(version); - const QString clangVersion = QString("%1.%2") - .arg(versionNumber.majorVersion()).arg(versionNumber.minorVersion()); - Utils::FileName stdcppPath = ndkPath; - stdcppPath.appendPath("sources/cxx-stl/gnu-libstdc++/" + clangVersion); - Utils::FileName includePath = stdcppPath; - Utils::FileName cppLibsPath = stdcppPath; - cppLibsPath.appendPath("libs/" + getArch(triple) + "/include/"); - paths.prepend({cppLibsPath.toString(), ProjectExplorer::HeaderPathType::BuiltIn}); - includePath.appendPath("include/"); - paths.prepend({includePath.toString(), ProjectExplorer::HeaderPathType::BuiltIn}); - - paths.prepend({ndkPath.toString() + "/sysroot/usr/include/" + triple, - ProjectExplorer::HeaderPathType::BuiltIn}); - paths.prepend({ndkPath.toString() + "/sysroot/usr/include", - ProjectExplorer::HeaderPathType::BuiltIn}); -} - -AndroidToolChain::BuiltInHeaderPathsRunner AndroidToolChain::createBuiltInHeaderPathsRunner() const -{ - const QString triple = originalTargetTriple(); - const QString version = this->version(); - initExtraHeaderPathsFunction([triple, version] (HeaderPaths &paths) { - addBuiltInHeaderPaths(paths, triple, version); - }); - return GccToolChain::createBuiltInHeaderPathsRunner(); -} - QString AndroidToolChain::typeDisplayName() const { - return AndroidToolChainFactory::tr("Android GCC"); + return AndroidToolChainFactory::tr("Android Clang"); } bool AndroidToolChain::isValid() const { - return GccToolChain::isValid() && targetAbi().isValid() && !m_ndkToolChainVersion.isEmpty() + return ClangToolChain::isValid() + && typeId() == Constants::ANDROID_TOOLCHAIN_ID + && targetAbi().isValid() && compilerCommand().isChildOf(AndroidConfigurations::currentConfig().ndkLocation()) && !originalTargetTriple().isEmpty(); } void AndroidToolChain::addToEnvironment(Environment &env) const { -// TODO this vars should be configurable in projects -> build tab -// TODO invalidate all .pro files !!! - - env.set(QLatin1String("ANDROID_NDK_HOST"), AndroidConfigurations::currentConfig().toolchainHost()); - 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); + env.set(QLatin1String("ANDROID_NDK_HOST"), + AndroidConfigurations::currentConfig().toolchainHost()); const Utils::FileName javaHome = AndroidConfigurations::currentConfig().openJDKLocation(); if (!javaHome.isEmpty() && javaHome.toFileInfo().exists()) { env.set(QLatin1String("JAVA_HOME"), javaHome.toString()); @@ -169,26 +100,16 @@ void AndroidToolChain::addToEnvironment(Environment &env) const if (!Utils::contains(env.path(), [&javaBin](const Utils::FileName &p) { return p == javaBin; })) env.prependOrSetPath(javaBin.toUserOutput()); } - env.set(QLatin1String("ANDROID_HOME"), AndroidConfigurations::currentConfig().sdkLocation().toString()); - env.set(QLatin1String("ANDROID_SDK_ROOT"), AndroidConfigurations::currentConfig().sdkLocation().toString()); -} - -bool AndroidToolChain::operator ==(const ToolChain &tc) const -{ - if (!GccToolChain::operator ==(tc)) - return false; - - return m_ndkToolChainVersion == static_cast(tc).m_ndkToolChainVersion; -} - -std::unique_ptr AndroidToolChain::createConfigurationWidget() -{ - return std::make_unique(this); + env.set(QLatin1String("ANDROID_HOME"), + AndroidConfigurations::currentConfig().sdkLocation().toString()); + env.set(QLatin1String("ANDROID_SDK_ROOT"), + AndroidConfigurations::currentConfig().sdkLocation().toString()); } FileName AndroidToolChain::suggestedDebugger() const { - return AndroidConfigurations::currentConfig().gdbPath(targetAbi(), m_ndkToolChainVersion); + // TODO: Make use of LLDB if available. + return AndroidConfigurations::currentConfig().gdbPath(); } FileName AndroidToolChain::suggestedGdbServer() const @@ -196,45 +117,10 @@ FileName AndroidToolChain::suggestedGdbServer() const return AndroidConfigurations::currentConfig().gdbServer(targetAbi()); } -QVariantMap AndroidToolChain::toMap() const -{ - QVariantMap result = GccToolChain::toMap(); - result.insert(QLatin1String(ANDROID_NDK_TC_VERION), m_ndkToolChainVersion); - return result; -} - bool AndroidToolChain::fromMap(const QVariantMap &data) { - if (!GccToolChain::fromMap(data)) + if (!ClangToolChain::fromMap(data)) return false; - - if (data.contains(QLatin1String(ANDROID_QT_VERSION_KEY))) { - QString command = compilerCommand().toString(); - QString ndkPath = AndroidConfigurations::currentConfig().ndkLocation().toString(); - if (!command.startsWith(ndkPath)) - return false; - command = command.mid(ndkPath.length()); - if (!command.startsWith(QLatin1String("/toolchains/"))) - return false; - command = command.mid(12); - int index = command.indexOf(QLatin1Char('/')); - if (index == -1) - return false; - command = command.left(index); - QRegExp versionRegExp(NDKGccVersionRegExp); - index = versionRegExp.indexIn(command); - if (index == -1) - return false; - m_ndkToolChainVersion = command.mid(index + 1); - QString platform = command.left(index); - setTargetAbi(AndroidConfig::abiForToolChainPrefix(platform)); - } else { - m_ndkToolChainVersion = data.value(QLatin1String(ANDROID_NDK_TC_VERION)).toString(); - } - - Abi abi = targetAbi(); - m_secondaryToolChain = AndroidToolChainFactory::versionCompareLess(AndroidToolChainFactory::versionNumberFromString(m_ndkToolChainVersion), - AndroidToolChainFactory::newestToolChainVersionForArch(abi)); return isValid(); } @@ -246,59 +132,16 @@ FileNameList AndroidToolChain::suggestedMkspecList() const QString AndroidToolChain::makeCommand(const Environment &env) const { + Q_UNUSED(env); FileName makePath = AndroidConfigurations::currentConfig().makePath(); - if (makePath.exists()) - return makePath.toString(); - const Utils::FileNameList extraDirectories - = Utils::transform(AndroidConfigurations::currentConfig().makeExtraSearchDirectories(), - [](const QString &s) { return Utils::FileName::fromString(s); }); - if (HostOsInfo::isWindowsHost()) { - makePath = env.searchInPath("ma-make.exe", extraDirectories); - if (!makePath.isEmpty()) - return makePath.toString(); - makePath = env.searchInPath("mingw32-make", extraDirectories); - return makePath.isEmpty() ? QLatin1String("mingw32-make") : makePath.toString(); - } - - makePath = env.searchInPath("make", extraDirectories); - return makePath.isEmpty() ? "make" : makePath.toString(); -} - -QString AndroidToolChain::ndkToolChainVersion() const -{ - return m_ndkToolChainVersion; -} - -bool AndroidToolChain::isSecondaryToolChain() const -{ - return m_secondaryToolChain; -} - -void AndroidToolChain::setSecondaryToolChain(bool b) -{ - if (m_secondaryToolChain == b) - return; - m_secondaryToolChain = b; - toolChainUpdated(); + return makePath.exists() ? makePath.toString() : "make"; } GccToolChain::DetectedAbisResult AndroidToolChain::detectSupportedAbis() const { - GccToolChain::DetectedAbisResult supportedAbis = GccToolChain::detectSupportedAbis(); - supportedAbis.supportedAbis = {targetAbi()}; - return supportedAbis; + return GccToolChain::DetectedAbisResult({targetAbi()}, originalTargetTriple()); } -// -------------------------------------------------------------------------- -// ToolChainConfigWidget -// -------------------------------------------------------------------------- - -AndroidToolChainConfigWidget::AndroidToolChainConfigWidget(AndroidToolChain *tc) : - ToolChainConfigWidget(tc) -{ - QLabel *label = new QLabel(AndroidConfigurations::currentConfig().ndkLocation().toUserOutput()); - m_mainLayout->addRow(tr("NDK Root:"), label); -} // -------------------------------------------------------------------------- // ToolChainFactory @@ -306,7 +149,7 @@ AndroidToolChainConfigWidget::AndroidToolChainConfigWidget(AndroidToolChain *tc) AndroidToolChainFactory::AndroidToolChainFactory() { - setDisplayName(tr("Android GCC")); + setDisplayName(tr("Android Clang")); } QSet Android::Internal::AndroidToolChainFactory::supportedLanguages() const @@ -314,9 +157,9 @@ QSet Android::Internal::AndroidToolChainFactory::supportedLanguages() return {ProjectExplorer::Constants::CXX_LANGUAGE_ID}; } -QList AndroidToolChainFactory::autoDetect(const QList &alreadyKnown) +ToolChainList AndroidToolChainFactory::autoDetect(CToolChainList &alreadyKnown) { - return autodetectToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation(), alreadyKnown); + return autodetectToolChainsForNdk(alreadyKnown); } bool AndroidToolChainFactory::canRestore(const QVariantMap &data) @@ -334,184 +177,67 @@ ToolChain *AndroidToolChainFactory::restore(const QVariantMap &data) return nullptr; } -QList AndroidToolChainFactory::toolchainPathsForNdk(const FileName &ndkPath) -{ - QList result; - if (ndkPath.isEmpty()) - return result; - QRegExp versionRegExp(NDKGccVersionRegExp); - FileName path = ndkPath; - QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), - QStringList("*"), QDir::Dirs); - while (it.hasNext()) { - const QString &fileName = FileName::fromString(it.next()).fileName(); - int idx = versionRegExp.indexIn(fileName); - if (idx == -1) - continue; - for (const Core::Id lang : {ProjectExplorer::Constants::CXX_LANGUAGE_ID, - ProjectExplorer::Constants::C_LANGUAGE_ID}) { - 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) - continue; - ati.compilerCommand = AndroidConfigurations::currentConfig().gccPath(ati.abi, lang, ati.version); - result.append(ati); - } - } - return result; -} - -QList AndroidToolChainFactory::versionNumberFromString(const QString &version) -{ - QList result; - int start = 0; - int end = version.length(); - while (start <= end) { - int index = version.indexOf(QLatin1Char('.'), start); - if (index == -1) - index = end; - - bool ok; - int v = version.midRef(start, index - start).toInt(&ok); - if (!ok) // unparseable, return what we have - return result; - - result << v; - start = index + 1; - } - return result; -} - -bool AndroidToolChainFactory::versionCompareLess(const QList &a, const QList &b) -{ - int aend = a.length(); - int bend = b.length(); - int end = qMax(aend, bend); - for (int i = 0; i < end; ++i) { - int an = i < aend ? a.at(i) : 0; - int bn = i < bend ? b.at(i) : 0; - if (an < bn) - return true; - if (bn < an) - return false; - } - return false; -} - -bool AndroidToolChainFactory::versionCompareLess(QList atc, - QList btc) -{ - if (atc.isEmpty() || btc.isEmpty()) - return false; - - 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, Core::Id lang, - const QList &alreadyKnown) -{ - return static_cast( - Utils::findOrDefault(alreadyKnown, [compilerPath, lang](ToolChain *tc) { - return tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID - && tc->language() == lang - && tc->compilerCommand() == compilerPath; - })); -} - -QList -AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath, - const QList &alreadyKnown) +ToolChainList AndroidToolChainFactory::autodetectToolChainsForNdk(CToolChainList &alreadyKnown) { QList result; - if (ndkPath.isEmpty()) + FileName clangPath = AndroidConfigurations::currentConfig().clangPath(); + if (!clangPath.exists()) { + qCDebug(androidTCLog) << "Clang toolchains detection fails. Can not find Clang"<< clangPath; return result; - - QRegExp versionRegExp(NDKGccVersionRegExp); - FileName path = ndkPath; - QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), - QStringList("*"), QDir::Dirs); - QHash> newestToolChainForArch; - - while (it.hasNext()) { - const QString &fileName = FileName::fromString(it.next()).fileName(); - int idx = versionRegExp.indexIn(fileName); - if (idx == -1) - continue; - QString version = fileName.mid(idx + 1); - QString platform = fileName.left(idx); - Abi abi = AndroidConfig::abiForToolChainPrefix(platform); - if (abi.architecture() == Abi::UnknownArchitecture) - continue; - QList toolChainBundle; - for (Core::Id lang : {ProjectExplorer::Constants::CXX_LANGUAGE_ID, ProjectExplorer::Constants::C_LANGUAGE_ID}) { - FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, lang, version); - if (!compilerPath.exists()) - continue; - - AndroidToolChain *tc = findToolChain(compilerPath, lang, alreadyKnown); - if (!tc || tc->originalTargetTriple().isEmpty()) { - tc = new AndroidToolChain(abi, version, lang, - ToolChain::AutoDetection); - tc->resetToolChain(compilerPath); - QTC_ASSERT(!tc->originalTargetTriple().isEmpty(), - delete tc; continue); - } - result.append(tc); - toolChainBundle.append(tc); - } - - if (toolChainBundle.isEmpty()) - continue; - - auto it = newestToolChainForArch.constFind(abi); - if (it == newestToolChainForArch.constEnd()) - newestToolChainForArch.insert(abi, toolChainBundle); - else if (versionCompareLess(it.value(), toolChainBundle)) - newestToolChainForArch[abi] = toolChainBundle; } - foreach (ToolChain *tc, result) { - auto atc = static_cast(tc); - atc->setSecondaryToolChain(!newestToolChainForArch.value(atc->targetAbi()).contains(atc)); + qCDebug(androidTCLog) << "Detecting toolchains from Android NDK:" + << AndroidConfigurations::currentConfig().ndkLocation(); + + for (const Core::Id &lang : LanguageIds) { + FileName compilerCommand = clangPath; + if (lang == ProjectExplorer::Constants::CXX_LANGUAGE_ID) + compilerCommand.appendString("++"); + + 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(); + ToolChain *tc = findToolChain(compilerCommand, lang, targetItr.key(), 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(targetItr.key(), lang); + atc->resetToolChain(compilerCommand); + tc = atc; + } + result << tc; + ++targetItr; + } } return result; } -QList AndroidToolChainFactory::newestToolChainVersionForArch(const Abi &abi) +// for fromMap +AndroidToolChain::AndroidToolChain() + : ClangToolChain(Constants::ANDROID_TOOLCHAIN_ID, ToolChain::ManualDetection) { - if (m_newestVersionForAbi.isEmpty() - || m_ndkLocation != AndroidConfigurations::currentConfig().ndkLocation()) { - QRegExp versionRegExp(NDKGccVersionRegExp); - m_ndkLocation = AndroidConfigurations::currentConfig().ndkLocation(); - FileName path = m_ndkLocation; - QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), - QStringList("*"), QDir::Dirs); - while (it.hasNext()) { - const QString &fileName = FileName::fromString(it.next()).fileName(); - int idx = versionRegExp.indexIn(fileName); - if (idx == -1) - continue; - QList version = versionNumberFromString(fileName.mid(idx + 1)); - QString platform = fileName.left(idx); - Abi abi = AndroidConfig::abiForToolChainPrefix(platform); - if (abi.architecture() == Abi::UnknownArchitecture) - continue; - QHash >::const_iterator it - = m_newestVersionForAbi.constFind(abi); - if (it == m_newestVersionForAbi.constEnd()) - m_newestVersionForAbi.insert(abi, version); - else if (versionCompareLess(it.value(), version)) - m_newestVersionForAbi[abi] = version; - } - } - return m_newestVersionForAbi.value(abi); +} + + +AndroidToolChain::AndroidToolChain(const QString& target, Core::Id languageId) + : ClangToolChain(Constants::ANDROID_TOOLCHAIN_ID, ToolChain::AutoDetection) +{ + setOriginalTargetTriple(target); + setLanguage(languageId); + setTargetAbi(ClangTargets[target]); + setPlatformCodeGenFlags({"-target", target}); + setPlatformLinkerFlags({"-target", target}); + setDisplayName(QString::fromLatin1("Android Clang (%1, %2)") + .arg(ToolChainManager::displayNameOfLanguageId(languageId), + AndroidConfig::displayName(targetAbi()))); } } // namespace Internal diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h index ee54b94e966..b8dbe4c6c22 100644 --- a/src/plugins/android/androidtoolchain.h +++ b/src/plugins/android/androidtoolchain.h @@ -26,71 +26,38 @@ #pragma once #include -#include namespace Android { namespace Internal { -class AndroidToolChain : public ProjectExplorer::GccToolChain +using ToolChainList = QList; +using CToolChainList = const QList; + +class AndroidToolChain : public ProjectExplorer::ClangToolChain { public: ~AndroidToolChain() override; QString typeDisplayName() const override; - bool isValid() const override; - void addToEnvironment(Utils::Environment &env) const override; - bool operator ==(const ProjectExplorer::ToolChain &) const override; - - std::unique_ptr createConfigurationWidget() override; Utils::FileName suggestedDebugger() const override; Utils::FileName suggestedGdbServer() const; - - QVariantMap toMap() const override; - bool fromMap(const QVariantMap &data) override; Utils::FileNameList suggestedMkspecList() const override; QString makeCommand(const Utils::Environment &environment) const override; - - QString ndkToolChainVersion() const; - - bool isSecondaryToolChain() const; - void setSecondaryToolChain(bool b); - - BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner() const override; + bool fromMap(const QVariantMap &data) override; protected: DetectedAbisResult detectSupportedAbis() const override; private: - explicit AndroidToolChain(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion, - Core::Id l, Detection d); - AndroidToolChain(); - AndroidToolChain(const AndroidToolChain &); - - QString m_ndkToolChainVersion; - bool m_secondaryToolChain; + explicit AndroidToolChain(); + AndroidToolChain(const QString &target, Core::Id languageId); friend class AndroidToolChainFactory; }; - -class AndroidToolChainConfigWidget : public ProjectExplorer::ToolChainConfigWidget -{ - Q_OBJECT - -public: - AndroidToolChainConfigWidget(AndroidToolChain *); - -private: - void applyImpl() override {} - void discardImpl() override {} - bool isDirtyImpl() const override { return false; } - void makeReadOnlyImpl() override {} -}; - - class AndroidToolChainFactory : public ProjectExplorer::ToolChainFactory { Q_OBJECT @@ -99,7 +66,7 @@ public: AndroidToolChainFactory(); QSet supportedLanguages() const override; - QList autoDetect(const QList &alreadyKnown) override; + ToolChainList autoDetect(CToolChainList &alreadyKnown) override; bool canRestore(const QVariantMap &data) override; ProjectExplorer::ToolChain *restore(const QVariantMap &data) override; @@ -112,19 +79,7 @@ public: QString version; }; - static QList - autodetectToolChainsForNdk(const Utils::FileName &ndkPath, - const QList &alreadyKnown); - static QList toolchainPathsForNdk(const Utils::FileName &ndkPath); - - static QList versionNumberFromString(const QString &version); - static bool versionCompareLess(const QList &a, const QList &b); - static bool versionCompareLess(QList atc, - QList btc); - static QList newestToolChainVersionForArch(const ProjectExplorer::Abi &abi); -private: - static QHash > m_newestVersionForAbi; - static Utils::FileName m_ndkLocation; + static ToolChainList autodetectToolChainsForNdk(CToolChainList &alreadyKnown); }; } // namespace Internal diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index be82713d4cd..c29b39d2ca4 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1198,6 +1198,10 @@ ClangToolChain::ClangToolChain(Detection d) : GccToolChain(Constants::CLANG_TOOLCHAIN_TYPEID, d) { } +ClangToolChain::ClangToolChain(Core::Id typeId, ToolChain::Detection d) : + GccToolChain(typeId, d) +{ } + QString ClangToolChain::typeDisplayName() const { return ClangToolChainFactory::tr("Clang"); diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index c6e42fe73df..cf8c4f0052b 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -207,6 +207,7 @@ class PROJECTEXPLORER_EXPORT ClangToolChain : public GccToolChain { public: explicit ClangToolChain(Detection d); + ClangToolChain(Core::Id typeId, Detection d); QString typeDisplayName() const override; QString makeCommand(const Utils::Environment &environment) const override;