diff --git a/doc/qtcreatordev/config/qtcreator-developer.qdocconf b/doc/qtcreatordev/config/qtcreator-developer.qdocconf index 63903e0dcd4..72fd0efb2cd 100644 --- a/doc/qtcreatordev/config/qtcreator-developer.qdocconf +++ b/doc/qtcreatordev/config/qtcreator-developer.qdocconf @@ -13,6 +13,8 @@ sourcedirs = . \ ../../../src/libs/aggregation \ ../../../src/libs/extensionsystem +excludedirs = ../../../src/libs/aggregation/examples + # -- Uncomment following option to generate complete documentation # instead of public API documentation only. #showinternal = true diff --git a/scripts/common.py b/scripts/common.py index 7c2fb13271d..db97ea35616 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -91,7 +91,8 @@ def copytree(src, dst, symlinks=False, ignore=None): def get_qt_install_info(qmake_bin): output = subprocess.check_output([qmake_bin, '-query']) - lines = output.decode(encoding).strip().split('\n') + decoded_output = output.decode(encoding) if encoding else output + lines = decoded_output.strip().split('\n') info = {} for line in lines: (var, sep, value) = line.partition(':') @@ -178,28 +179,37 @@ def is_not_debug(path, filenames): files = [fn for fn in filenames if os.path.isfile(os.path.join(path, fn))] return [fn for fn in files if not is_debug_file(os.path.join(path, fn))] -def codesign(app_path): +def codesign_call(): signing_identity = os.environ.get('SIGNING_IDENTITY') - if is_mac_platform() and signing_identity: - codesign_call = ['codesign', '-o', 'runtime', '--force', '-s', signing_identity, - '-v'] - signing_flags = os.environ.get('SIGNING_FLAGS') - if signing_flags: - codesign_call.extend(signing_flags.split()) + if not signing_identity: + return None + codesign_call = ['codesign', '-o', 'runtime', '--force', '-s', signing_identity, + '-v'] + signing_flags = os.environ.get('SIGNING_FLAGS') + if signing_flags: + codesign_call.extend(signing_flags.split()) + return codesign_call - def conditional_sign_recursive(path, filter): - for r, _, fs in os.walk(path): - for f in fs: - ff = os.path.join(r, f) - if filter(ff): - print('codesign "' + ff + '"') - subprocess.check_call(codesign_call + [ff]) +def os_walk(path, filter, function): + for r, _, fs in os.walk(path): + for f in fs: + ff = os.path.join(r, f) + if filter(ff): + function(ff) - # sign all executables in Resources - conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Resources'), - lambda ff: os.access(ff, os.X_OK)) - # sign all libraries in Imports - conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Imports'), - lambda ff: ff.endswith('.dylib')) +def conditional_sign_recursive(path, filter): + codesign = codesign_call() + if is_mac_platform() and codesign: + os_walk(path, filter, lambda fp: subprocess.check_call(codesign + [fp])) + +def codesign(app_path): + # sign all executables in Resources + conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Resources'), + lambda ff: os.access(ff, os.X_OK)) + # sign all libraries in Imports + conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Imports'), + lambda ff: ff.endswith('.dylib')) + codesign = codesign_call() + if is_mac_platform() and codesign: # sign the whole bundle - subprocess.check_call(codesign_call + ['--deep', app_path]) + subprocess.check_call(codesign + ['--deep', app_path]) diff --git a/scripts/createDistPackage.py b/scripts/createDistPackage.py index 41c36f9ee97..ad23a617e38 100755 --- a/scripts/createDistPackage.py +++ b/scripts/createDistPackage.py @@ -33,8 +33,7 @@ import tempfile import common def parse_arguments(): - parser = argparse.ArgumentParser(description="Create Qt Creator package, filtering out debug information files.", - epilog="To sign the contents before packaging on macOS, set the SIGNING_IDENTITY and optionally the SIGNING_FLAGS environment variables.") + parser = argparse.ArgumentParser(description="Create Qt Creator package, filtering out debug information files.") parser.add_argument('--7z', help='path to 7z binary', default='7z.exe' if common.is_windows_platform() else '7z', metavar='<7z_binary>', dest='sevenzip') @@ -53,9 +52,6 @@ def main(): try: common.copytree(arguments.source_directory, tempdir, symlinks=True, ignore=(common.is_not_debug if arguments.debug else common.is_debug)) - # on macOS we might have to codesign (again) to account for removed debug info - if not arguments.debug: - common.codesign(tempdir) # package zip_source = os.path.join(tempdir, '*') if arguments.exclude_toplevel else tempdir subprocess.check_call([arguments.sevenzip, 'a', '-mmt2', diff --git a/scripts/packagePlugins.py b/scripts/packagePlugins.py index d70de8e33db..5cbace790c3 100755 --- a/scripts/packagePlugins.py +++ b/scripts/packagePlugins.py @@ -28,7 +28,6 @@ import argparse import os import subprocess -import sys import common @@ -45,10 +44,16 @@ def parse_arguments(): if __name__ == "__main__": arguments = parse_arguments() + qt_install_info = common.get_qt_install_info(arguments.qmake_binary) if common.is_linux_platform(): - qt_install_info = common.get_qt_install_info(arguments.qmake_binary) common.fix_rpaths(arguments.source_directory, os.path.join(arguments.source_directory, 'lib', 'Qt', 'lib'), qt_install_info) + if common.is_mac_platform(): + # remove Qt rpath + lib_path = qt_install_info['QT_INSTALL_LIBS'] + common.os_walk(arguments.source_directory, + lambda fp: fp.endswith('.dylib'), + lambda fp: subprocess.call(['install_name_tool', '-delete_rpath', lib_path, fp])) subprocess.check_call([arguments.sevenzip, 'a', '-mx9', arguments.target_file, os.path.join(arguments.source_directory, '*')]) diff --git a/src/libs/aggregation/aggregate.cpp b/src/libs/aggregation/aggregate.cpp index 3c2ea217b13..a4cb2dd436d 100644 --- a/src/libs/aggregation/aggregate.cpp +++ b/src/libs/aggregation/aggregate.cpp @@ -104,7 +104,7 @@ */ /*! - \fn T *Aggregate::component() + \fn template T *Aggregation::Aggregate::component() Template function that returns the component with the given type, if there is one. If there are multiple components with that type, a random one is returned. @@ -113,26 +113,16 @@ */ /*! - \fn QList Aggregate::components() + \fn template QList Aggregation::Aggregate::components() Template function that returns all components with the given type, if there are any. \sa Aggregate::component(), add() */ -/*! - \fn T *Aggregation::query(Aggregate *obj) - \internal -*/ - -/*! - \fn QList Aggregation::query_all(Aggregate *obj) - \internal -*/ - /*! \relates Aggregation::Aggregate - \fn T *Aggregation::query(QObject *obj) + \fn template T *Aggregation::query(QObject *obj) Performs a dynamic cast that is aware of a possible aggregate that \a obj might belong to. If \a obj itself is of the requested type, it is simply cast @@ -144,7 +134,7 @@ /*! \relates Aggregation::Aggregate - \fn QList Aggregation::query_all(QObject *obj) + \fn template QList Aggregation::query_all(QObject *obj) If \a obj belongs to an aggregate, all components that can be cast to the given type are returned. Otherwise, \a obj is returned if it is of the requested type. diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 7ef37b89ca9..25af2c8eca4 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -531,10 +531,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 diff --git a/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp b/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp index 2a516281acf..c37090c1658 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp @@ -49,28 +49,6 @@ namespace Uv { const char kProjectSchema[] = "2.1"; -// Helpers - -QString toolsFilePath(const QString &uVisionFilePath) -{ - const QFileInfo fi(uVisionFilePath); - QDir dir = fi.dir(); - if (!dir.cdUp()) - return {}; - return dir.absoluteFilePath("tools.ini"); -} - -QString targetUVisionPath() -{ - if (const Target *target = SessionManager::startupTarget()) { - if (const Kit *kit = target->kit()) { - const Runnable runnable = DebuggerKitAspect::runnable(kit); - return runnable.executable.toString(); - } - } - return {}; -} - static QString buildToolsetNumber(int number) { return QStringLiteral("0x%1").arg(QString::number(number, 16)); diff --git a/src/plugins/baremetal/debugservers/uvsc/uvproject.h b/src/plugins/baremetal/debugservers/uvsc/uvproject.h index a1ac9fe634e..6642cf6cc3c 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvproject.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvproject.h @@ -39,11 +39,6 @@ class UvscServerProvider; namespace Uv { -// Helpers - -QString toolsFilePath(const QString &uVisionFilePath); -QString targetUVisionPath(); - // UvProject class Project final : public Gen::Xml::Project diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp index cedb22b82d0..bee1f72bad1 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -57,6 +58,7 @@ namespace Internal { using namespace Uv; // Whole software package selection keys. +constexpr char toolsIniKeyC[] = "BareMetal.UvscServerProvider.ToolsIni"; constexpr char deviceSelectionKeyC[] = "BareMetal.UvscServerProvider.DeviceSelection"; constexpr char driverSelectionKeyC[] = "BareMetal.UvscServerProvider.DriverSelection"; @@ -78,6 +80,16 @@ UvscServerProvider::UvscServerProvider(const UvscServerProvider &other) setEngineType(UvscEngineType); } +void UvscServerProvider::setToolsIniFile(const Utils::FilePath &toolsIniFile) +{ + m_toolsIniFile = toolsIniFile; +} + +Utils::FilePath UvscServerProvider::toolsIniFile() const +{ + return m_toolsIniFile; +} + void UvscServerProvider::setDeviceSelection(const DeviceSelection &deviceSelection) { m_deviceSelection = deviceSelection; @@ -123,7 +135,8 @@ bool UvscServerProvider::operator==(const IDebugServerProvider &other) const if (!IDebugServerProvider::operator==(other)) return false; const auto p = static_cast(&other); - return m_deviceSelection == p->m_deviceSelection + return m_toolsIniFile == p->m_toolsIniFile + && m_deviceSelection == p->m_deviceSelection && m_driverSelection == p->m_driverSelection && m_toolsetNumber == p->m_toolsetNumber; } @@ -147,6 +160,7 @@ FilePath UvscServerProvider::buildOptionsFilePath(DebuggerRunTool *runTool) cons QVariantMap UvscServerProvider::toMap() const { QVariantMap data = IDebugServerProvider::toMap(); + data.insert(toolsIniKeyC, m_toolsIniFile.toVariant()); data.insert(deviceSelectionKeyC, m_deviceSelection.toMap()); data.insert(driverSelectionKeyC, m_driverSelection.toMap()); return data; @@ -217,6 +231,7 @@ bool UvscServerProvider::fromMap(const QVariantMap &data) { if (!IDebugServerProvider::fromMap(data)) return false; + m_toolsIniFile = FilePath::fromVariant(data.value(toolsIniKeyC)); m_deviceSelection.fromMap(data.value(deviceSelectionKeyC).toMap()); m_driverSelection.fromMap(data.value(driverSelectionKeyC).toMap()); return true; @@ -257,6 +272,11 @@ UvscServerProviderConfigWidget::UvscServerProviderConfigWidget(UvscServerProvide { m_hostWidget = new HostWidget; m_mainLayout->addRow(tr("Host:"), m_hostWidget); + m_toolsIniChooser = new PathChooser; + m_toolsIniChooser->setExpectedKind(PathChooser::File); + m_toolsIniChooser->setPromptDialogFilter("tools.ini"); + m_toolsIniChooser->setPromptDialogTitle(tr("Choose a Keil toolset configuration file")); + m_mainLayout->addRow(tr("Tools file path:"), m_toolsIniChooser); m_deviceSelector = new DeviceSelector; m_mainLayout->addRow(tr("Target device:"), m_deviceSelector); m_driverSelector = new DriverSelector(provider->supportedDrivers()); @@ -266,15 +286,27 @@ UvscServerProviderConfigWidget::UvscServerProviderConfigWidget(UvscServerProvide connect(m_hostWidget, &HostWidget::dataChanged, this, &UvscServerProviderConfigWidget::dirty); + connect(m_toolsIniChooser, &PathChooser::pathChanged, + this, &UvscServerProviderConfigWidget::dirty); connect(m_deviceSelector, &DeviceSelector::selectionChanged, this, &UvscServerProviderConfigWidget::dirty); connect(m_driverSelector, &DriverSelector::selectionChanged, this, &UvscServerProviderConfigWidget::dirty); + + auto updateSelectors = [this]() { + const FilePath toolsIniFile = m_toolsIniChooser->fileName(); + m_deviceSelector->setToolsIniFile(toolsIniFile); + m_driverSelector->setToolsIniFile(toolsIniFile); + }; + + connect(m_toolsIniChooser, &PathChooser::pathChanged, updateSelectors); + updateSelectors(); } void UvscServerProviderConfigWidget::apply() { const auto p = static_cast(m_provider); + p->setToolsIniFile(toolsIniFile()); p->setDeviceSelection(deviceSelection()); p->setDriverSelection(driverSelection()); IDebugServerProviderConfigWidget::apply(); @@ -286,6 +318,16 @@ void UvscServerProviderConfigWidget::discard() IDebugServerProviderConfigWidget::discard(); } +void UvscServerProviderConfigWidget::setToolsIniFile(const Utils::FilePath &toolsIniFile) +{ + m_toolsIniChooser->setFileName(toolsIniFile); +} + +Utils::FilePath UvscServerProviderConfigWidget::toolsIniFile() const +{ + return m_toolsIniChooser->fileName(); +} + void UvscServerProviderConfigWidget::setDeviceSelection(const DeviceSelection &deviceSelection) { m_deviceSelector->setSelection(deviceSelection); @@ -310,6 +352,7 @@ void UvscServerProviderConfigWidget::setFromProvider() { const auto p = static_cast(m_provider); m_hostWidget->setChannel(p->channel()); + m_toolsIniChooser->setFileName(p->toolsIniFile()); m_deviceSelector->setSelection(p->deviceSelection()); m_driverSelector->setSelection(p->driverSelection()); } diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h index bab1a6c36d0..f4527f03a4e 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h @@ -32,6 +32,8 @@ #include // for RunWorker +namespace Utils { class PathChooser; } + namespace BareMetal { namespace Internal { @@ -54,6 +56,9 @@ public: ArmAdsToolsetNumber = 4 // ARM-ADS toolset }; + void setToolsIniFile(const Utils::FilePath &toolsIniFile); + Utils::FilePath toolsIniFile() const; + void setDeviceSelection(const Uv::DeviceSelection &deviceSelection); Uv::DeviceSelection deviceSelection() const; @@ -91,6 +96,7 @@ protected: virtual Utils::FilePath optionsFilePath(Debugger::DebuggerRunTool *runTool, QString &errorMessage) const = 0; + Utils::FilePath m_toolsIniFile; Uv::DeviceSelection m_deviceSelection; Uv::DriverSelection m_driverSelection; @@ -113,6 +119,8 @@ public: void discard() override; protected: + void setToolsIniFile(const Utils::FilePath &toolsIniFile); + Utils::FilePath toolsIniFile() const; void setDeviceSelection(const Uv::DeviceSelection &deviceSelection); Uv::DeviceSelection deviceSelection() const; void setDriverSelection(const Uv::DriverSelection &driverSelection); @@ -121,6 +129,7 @@ protected: void setFromProvider(); HostWidget *m_hostWidget = nullptr; + Utils::PathChooser *m_toolsIniChooser = nullptr; Uv::DeviceSelector *m_deviceSelector = nullptr; Uv::DriverSelector *m_driverSelector = nullptr; }; diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp b/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp index c6807b61095..391b0a4d158 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.cpp @@ -23,7 +23,6 @@ ** ****************************************************************************/ -#include "uvproject.h" // for toolsFilePath() #include "uvtargetdevicemodel.h" #include @@ -37,9 +36,9 @@ namespace BareMetal { namespace Internal { namespace Uv { -static QString extractPacksPath(const QString &uVisionFilePath) +static QString extractPacksPath(const FilePath &toolsIniFile) { - QFile f(toolsFilePath(uVisionFilePath)); + QFile f(toolsIniFile.toString()); if (!f.open(QIODevice::ReadOnly)) return {}; QTextStream in(&f); @@ -258,15 +257,15 @@ DeviceSelectionModel::DeviceSelectionModel(QObject *parent) setHeader({tr("Name"), tr("Version"), tr("Vendor")}); } -void DeviceSelectionModel::fillAllPacks(const QString &uVisionFilePath) +void DeviceSelectionModel::fillAllPacks(const FilePath &toolsIniFile) { - if (m_uVisionFilePath == uVisionFilePath) + if (m_toolsIniFile == toolsIniFile) return; clear(); - m_uVisionFilePath = uVisionFilePath; - const QString packsPath = extractPacksPath(m_uVisionFilePath); + m_toolsIniFile = toolsIniFile; + const QString packsPath = extractPacksPath(m_toolsIniFile); if (packsPath.isEmpty()) return; diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.h b/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.h index 3bd8e857019..c3a510f36e9 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdevicemodel.h @@ -28,6 +28,7 @@ #include "uvtargetdeviceselection.h" #include +#include #include QT_BEGIN_NAMESPACE @@ -47,7 +48,7 @@ class DeviceSelectionModel final : public Utils::TreeModel public: explicit DeviceSelectionModel(QObject *parent = nullptr); - void fillAllPacks(const QString &uVisionFilePath); + void fillAllPacks(const Utils::FilePath &toolsIniFile); private: void parsePackage(const QString &packageFile); @@ -59,7 +60,7 @@ private: DeviceSelection::Cpu &cpu, DeviceSelection::Memories &memories); void parseDeviceVariant(QXmlStreamReader &in, DeviceSelectionItem *parent); - QString m_uVisionFilePath; + Utils::FilePath m_toolsIniFile; }; // DeviceSelectionView diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp index 69cbd30129f..84436d3b651 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.cpp @@ -124,28 +124,30 @@ DeviceSelector::DeviceSelector(QWidget *parent) setWidget(detailsPanel); connect(toolPanel, &DeviceSelectorToolPanel::clicked, this, [this]() { - const QString uVisionPath = targetUVisionPath(); - if (uVisionPath.isEmpty()) { - QMessageBox::warning(this, - tr("uVision path not found"), - tr("Please open a configured project before\n" - "the target device selection."), - QMessageBox::Ok); - } else { - DeviceSelectionDialog dialog(uVisionPath, this); - const int result = dialog.exec(); - if (result != QDialog::Accepted) - return; - DeviceSelection selection; - selection = dialog.selection(); - setSelection(selection); - } + DeviceSelectionDialog dialog(m_toolsIniFile, this); + const int result = dialog.exec(); + if (result != QDialog::Accepted) + return; + DeviceSelection selection; + selection = dialog.selection(); + setSelection(selection); }); connect(detailsPanel, &DeviceSelectorDetailsPanel::selectionChanged, this, &DeviceSelector::selectionChanged); } +void DeviceSelector::setToolsIniFile(const Utils::FilePath &toolsIniFile) +{ + m_toolsIniFile = toolsIniFile; + setEnabled(m_toolsIniFile.exists()); +} + +Utils::FilePath DeviceSelector::toolsIniFile() const +{ + return m_toolsIniFile; +} + void DeviceSelector::setSelection(const DeviceSelection &selection) { m_selection = selection; @@ -167,7 +169,7 @@ DeviceSelection DeviceSelector::selection() const // DeviceSelectionDialog -DeviceSelectionDialog::DeviceSelectionDialog(const QString &uVisionPath, QWidget *parent) +DeviceSelectionDialog::DeviceSelectionDialog(const Utils::FilePath &toolsIniFile, QWidget *parent) : QDialog(parent), m_model(new DeviceSelectionModel(this)), m_view(new DeviceSelectionView(this)) { setWindowTitle(tr("Available target devices")); @@ -187,7 +189,7 @@ DeviceSelectionDialog::DeviceSelectionDialog(const QString &uVisionPath, QWidget m_selection = selection; }); - m_model->fillAllPacks(uVisionPath); + m_model->fillAllPacks(toolsIniFile); m_view->setModel(m_model); } diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h index eaeb089e790..abc00e9c1c7 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdeviceviewer.h @@ -29,6 +29,7 @@ #include #include +#include #include @@ -55,6 +56,9 @@ class DeviceSelector final : public Utils::DetailsWidget public: explicit DeviceSelector(QWidget *parent = nullptr); + void setToolsIniFile(const Utils::FilePath &toolsIniFile); + Utils::FilePath toolsIniFile() const; + void setSelection(const DeviceSelection &selection); DeviceSelection selection() const; @@ -62,6 +66,7 @@ signals: void selectionChanged(); private: + Utils::FilePath m_toolsIniFile; DeviceSelection m_selection; }; @@ -111,7 +116,7 @@ class DeviceSelectionDialog final : public QDialog Q_OBJECT public: - explicit DeviceSelectionDialog(const QString &uVisionPath, QWidget *parent = nullptr); + explicit DeviceSelectionDialog(const Utils::FilePath &toolsIniFile, QWidget *parent = nullptr); DeviceSelection selection() const; private: diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdrivermodel.cpp b/src/plugins/baremetal/debugservers/uvsc/uvtargetdrivermodel.cpp index c3a737cbc8a..11199aca526 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdrivermodel.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdrivermodel.cpp @@ -23,7 +23,6 @@ ** ****************************************************************************/ -#include "uvproject.h" // for toolsFilePath() #include "uvtargetdrivermodel.h" #include @@ -132,12 +131,12 @@ DriverSelectionModel::DriverSelectionModel(QObject *parent) setHeader({tr("Path")}); } -void DriverSelectionModel::fillDrivers(const QString &uVisionFilePath, +void DriverSelectionModel::fillDrivers(const FilePath &toolsIniFile, const QStringList &supportedDrivers) { clear(); - QFile f(toolsFilePath(uVisionFilePath)); + QFile f(toolsIniFile.toString()); if (!f.open(QIODevice::ReadOnly)) return; diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdrivermodel.h b/src/plugins/baremetal/debugservers/uvsc/uvtargetdrivermodel.h index 845681d0c1a..9d9dda37890 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdrivermodel.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdrivermodel.h @@ -28,6 +28,7 @@ #include "uvtargetdriverselection.h" #include +#include #include namespace BareMetal { @@ -43,7 +44,7 @@ class DriverSelectionModel final : public Utils::TreeModel public: explicit DriverSelectionModel(QObject *parent = nullptr); - void fillDrivers(const QString &uVisionFilePath, const QStringList &supportedDrivers); + void fillDrivers(const Utils::FilePath &toolsIniFile, const QStringList &supportedDrivers); }; // DriverSelectionView diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdriverviewer.cpp b/src/plugins/baremetal/debugservers/uvsc/uvtargetdriverviewer.cpp index 04e6721e566..10baa3b2741 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdriverviewer.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdriverviewer.cpp @@ -105,28 +105,30 @@ DriverSelector::DriverSelector(const QStringList &supportedDrivers, QWidget *par setWidget(detailsPanel); connect(toolPanel, &DriverSelectorToolPanel::clicked, this, [=]() { - const QString uVisionPath = targetUVisionPath(); - if (uVisionPath.isEmpty()) { - QMessageBox::warning(this, - tr("uVision path not found"), - tr("Please open a configured project before\n" - "the target driver selection."), - QMessageBox::Ok); - } else { - DriverSelectionDialog dialog(uVisionPath, supportedDrivers, this); - const int result = dialog.exec(); - if (result != QDialog::Accepted) - return; - DriverSelection selection; - selection = dialog.selection(); - setSelection(selection); - } + DriverSelectionDialog dialog(m_toolsIniFile, supportedDrivers, this); + const int result = dialog.exec(); + if (result != QDialog::Accepted) + return; + DriverSelection selection; + selection = dialog.selection(); + setSelection(selection); }); connect(detailsPanel, &DriverSelectorDetailsPanel::selectionChanged, this, &DriverSelector::selectionChanged); } +void DriverSelector::setToolsIniFile(const Utils::FilePath &toolsIniFile) +{ + m_toolsIniFile = toolsIniFile; + setEnabled(m_toolsIniFile.exists()); +} + +Utils::FilePath DriverSelector::toolsIniFile() const +{ + return m_toolsIniFile; +} + void DriverSelector::setSelection(const DriverSelection &selection) { m_selection = selection; @@ -148,7 +150,7 @@ DriverSelection DriverSelector::selection() const // DriverSelectionDialog -DriverSelectionDialog::DriverSelectionDialog(const QString &uVisionPath, +DriverSelectionDialog::DriverSelectionDialog(const Utils::FilePath &toolsIniFile, const QStringList &supportedDrivers, QWidget *parent) : QDialog(parent), m_model(new DriverSelectionModel(this)), @@ -171,7 +173,7 @@ DriverSelectionDialog::DriverSelectionDialog(const QString &uVisionPath, m_selection = selection; }); - m_model->fillDrivers(uVisionPath, supportedDrivers); + m_model->fillDrivers(toolsIniFile, supportedDrivers); m_view->setModel(m_model); } diff --git a/src/plugins/baremetal/debugservers/uvsc/uvtargetdriverviewer.h b/src/plugins/baremetal/debugservers/uvsc/uvtargetdriverviewer.h index a72d3baf69f..c8c390318ce 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvtargetdriverviewer.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvtargetdriverviewer.h @@ -29,6 +29,7 @@ #include #include +#include #include @@ -52,6 +53,10 @@ class DriverSelector final : public Utils::DetailsWidget public: explicit DriverSelector(const QStringList &supportedDrivers, QWidget *parent = nullptr); + + void setToolsIniFile(const Utils::FilePath &toolsIniFile); + Utils::FilePath toolsIniFile() const; + void setSelection(const DriverSelection &selection); DriverSelection selection() const; @@ -59,6 +64,7 @@ signals: void selectionChanged(); private: + Utils::FilePath m_toolsIniFile; DriverSelection m_selection; }; @@ -105,7 +111,7 @@ class DriverSelectionDialog final : public QDialog Q_OBJECT public: - explicit DriverSelectionDialog(const QString &uVisionPath, + explicit DriverSelectionDialog(const Utils::FilePath &toolsIniFile, const QStringList &supportedDrivers, QWidget *parent = nullptr); DriverSelection selection() const; diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index cafad5f89cc..5d62cdfeb9a 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -392,8 +392,10 @@ void Client::deactivateDocument(TextEditor::TextDocument *document) hideDiagnostics(document); resetAssistProviders(document); document->setFormatter(nullptr); - if (TextEditor::SyntaxHighlighter *highlighter = document->syntaxHighlighter()) - highlighter->clearAllExtraFormats(); + if (m_serverCapabilities.semanticHighlighting().has_value()) { + if (TextEditor::SyntaxHighlighter *highlighter = document->syntaxHighlighter()) + highlighter->clearAllExtraFormats(); + } for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(document)) { if (auto textEditor = qobject_cast(editor)) textEditor->editorWidget()->removeHoverHandler(&m_hoverHandler); diff --git a/src/plugins/languageclient/semantichighlightsupport.cpp b/src/plugins/languageclient/semantichighlightsupport.cpp index 59b415455f7..8f333ea1838 100644 --- a/src/plugins/languageclient/semantichighlightsupport.cpp +++ b/src/plugins/languageclient/semantichighlightsupport.cpp @@ -151,10 +151,12 @@ void applyHighlight(TextEditor::TextDocument *doc, } } - TextEditor::SemanticHighlighter::setExtraAdditionalFormats( - doc->syntaxHighlighter(), - results, - scopesToFormatHash(highlightScopes(capabilities), doc->fontSettings())); + if (capabilities.semanticHighlighting().has_value()) { + TextEditor::SemanticHighlighter::setExtraAdditionalFormats( + doc->syntaxHighlighter(), + results, + scopesToFormatHash(highlightScopes(capabilities), doc->fontSettings())); + } } } // namespace SemanticHighligtingSupport diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 5eaf0b19567..03c908a8596 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -561,8 +561,10 @@ RunConfiguration *RunConfigurationFactory::restore(Target *parent, const QVarian const Core::Id id = idFromMap(map); if (id.name().startsWith(factory->m_runConfigBaseId.name())) { RunConfiguration *rc = factory->create(parent); - if (rc->fromMap(map)) + if (rc->fromMap(map)) { + rc->update(); return rc; + } delete rc; return nullptr; } diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index ca2605877e2..1e8fcdc48aa 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -386,6 +386,7 @@ extend_qtc_plugin(QmlDesigner include/abstractproperty.h include/abstractview.h include/anchorline.h + include/annotation.h include/basetexteditmodifier.h include/bindingproperty.h include/bytearraymodifier.h @@ -475,6 +476,7 @@ extend_qtc_plugin(QmlDesigner model/abstractproperty.cpp model/abstractview.cpp model/anchorline.cpp + model/annotation.cpp model/basetexteditmodifier.cpp model/bindingproperty.cpp model/componenttextmodifier.cpp @@ -541,8 +543,7 @@ extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/annotationeditor - SOURCES annotation.cpp annotation.h - annotationcommenttab.cpp annotationcommenttab.h annotationcommenttab.ui + SOURCES annotationcommenttab.cpp annotationcommenttab.h annotationcommenttab.ui annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui annotationeditor.cpp annotationeditor.h annotationtool.cpp annotationtool.h diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri index 3cc6c6f856b..e221b3bb615 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri @@ -1,10 +1,8 @@ -HEADERS += $$PWD/annotation.h HEADERS += $$PWD/annotationtool.h HEADERS += $$PWD/annotationcommenttab.h HEADERS += $$PWD/annotationeditordialog.h HEADERS += $$PWD/annotationeditor.h -SOURCES += $$PWD/annotation.cpp SOURCES += $$PWD/annotationtool.cpp SOURCES += $$PWD/annotationcommenttab.cpp SOURCES += $$PWD/annotationeditordialog.cpp diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp index ec99af6498f..ca91f308ea9 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp @@ -30,14 +30,13 @@ #include "ui_annotationcommenttab.h" +#include //replace timeline icons with our own? + #include #include #include #include - -#include "timelineicons.h" //replace timeline icons with our own? - namespace QmlDesigner { AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation) diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp index 367635d59f0..20e2a1dfe6c 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.h b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.h index c11ea5a3b77..4b8c804b2a5 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.h @@ -25,17 +25,13 @@ #pragma once -#include +#include +#include #include #include #include #include -#include - -QT_BEGIN_NAMESPACE -QT_END_NAMESPACE - namespace QmlDesigner { diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp index f4af3f481f7..fd8ff4cd560 100644 --- a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp +++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp @@ -25,8 +25,8 @@ #include "selectionindicator.h" +#include "annotation.h" #include -#include "annotationeditor/annotation.h" #include #include diff --git a/src/plugins/qmldesigner/designercore/designercore-lib.pri b/src/plugins/qmldesigner/designercore/designercore-lib.pri index cb636bb70b7..5e99009cdb3 100644 --- a/src/plugins/qmldesigner/designercore/designercore-lib.pri +++ b/src/plugins/qmldesigner/designercore/designercore-lib.pri @@ -82,7 +82,8 @@ SOURCES += $$PWD/model/abstractview.cpp \ $$PWD/model/anchorline.cpp \ $$PWD/instances/puppetdialog.cpp \ $$PWD/model/qmltimeline.cpp \ - $$PWD/model/qmltimelinekeyframegroup.cpp + $$PWD/model/qmltimelinekeyframegroup.cpp \ + $$PWD/model/annotation.cpp HEADERS += $$PWD/include/qmldesignercorelib_global.h \ $$PWD/include/abstractview.h \ @@ -158,7 +159,8 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \ $$PWD/include/anchorline.h \ $$PWD/instances/puppetdialog.h \ $$PWD/include/qmltimeline.h \ - $$PWD/include/qmltimelinekeyframegroup.h + $$PWD/include/qmltimelinekeyframegroup.h \ + $$PWD/include/annotation.h FORMS += \ $$PWD/instances/puppetdialog.ui diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotation.h b/src/plugins/qmldesigner/designercore/include/annotation.h similarity index 100% rename from src/plugins/qmldesigner/components/annotationeditor/annotation.h rename to src/plugins/qmldesigner/designercore/include/annotation.h diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotation.cpp b/src/plugins/qmldesigner/designercore/model/annotation.cpp similarity index 100% rename from src/plugins/qmldesigner/components/annotationeditor/annotation.cpp rename to src/plugins/qmldesigner/designercore/model/annotation.cpp diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp index 7a77044e13c..e8283c4b4c6 100644 --- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp @@ -41,7 +41,7 @@ #include "nodelistproperty.h" #include "nodeproperty.h" #include -#include "annotationeditor/annotation.h" +#include "annotation.h" #include diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index b6939808f2a..477ebd83888 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -55,7 +55,8 @@ Project { "components/navigator", "components/pluginmanager", "components/stateseditor", - "components/texteditor" + "components/texteditor", + "components/timelineeditor", ]) Properties { @@ -245,6 +246,7 @@ Project { "include/abstractproperty.h", "include/abstractview.h", "include/anchorline.h", + "include/annotation.h", "include/basetexteditmodifier.h", "include/bindingproperty.h", "include/componenttextmodifier.h", @@ -321,6 +323,7 @@ Project { "model/abstractproperty.cpp", "model/abstractview.cpp", "model/anchorline.cpp", + "model/annotation.cpp", "model/basetexteditmodifier.cpp", "model/bindingproperty.cpp", "model/componenttextmodifier.cpp", @@ -638,8 +641,6 @@ Project { name: "extension" prefix: "components/" files: [ - "annotationeditor/annotation.cpp", - "annotationeditor/annotation.h", "annotationeditor/annotationcommenttab.cpp", "annotationeditor/annotationcommenttab.h", "annotationeditor/annotationcommenttab.ui", @@ -647,7 +648,7 @@ Project { "annotationeditor/annotationeditor.h", "annotationeditor/annotationeditordialog.cpp", "annotationeditor/annotationeditordialog.h", - "annotationeditor/annotationeditordialog.ui + "annotationeditor/annotationeditordialog.ui", "annotationeditor/annotationtool.cpp", "annotationeditor/annotationtool.h", "bindingeditor/bindingeditor.cpp", diff --git a/src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp b/src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp index 292c46ccccf..6abdeff6087 100644 --- a/src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp +++ b/src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp @@ -292,8 +292,6 @@ bool FunctionHintProposalWidget::eventFilter(QObject *obj, QEvent *e) if (d->m_model && d->m_model->size() > 1) return false; } - if (QTC_GUARD(d->m_assistant)) - d->m_assistant->notifyChange(); } break; case QEvent::WindowDeactivate: diff --git a/src/plugins/texteditor/codeassist/genericproposalwidget.cpp b/src/plugins/texteditor/codeassist/genericproposalwidget.cpp index 92f3e9a3b91..241a98951d5 100644 --- a/src/plugins/texteditor/codeassist/genericproposalwidget.cpp +++ b/src/plugins/texteditor/codeassist/genericproposalwidget.cpp @@ -665,8 +665,6 @@ bool GenericProposalWidget::eventFilter(QObject *o, QEvent *e) } QApplication::sendEvent(const_cast(d->m_underlyingWidget), e); - if (isVisible()) - d->m_assistant->notifyChange(); return true; } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 635acd6e661..361419db7fb 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -741,7 +741,6 @@ public: QTimer m_highlightBlocksTimer; CodeAssistant m_codeAssistant; - bool m_assistRelevantContentAdded = false; QList m_hoverHandlers; // Not owned HoverHandlerRunner m_hoverHandlerRunner; @@ -1502,8 +1501,8 @@ void TextEditorWidgetPrivate::editorContentsChange(int position, int charsRemove snippetCheckCursor(cursor); } - if (charsAdded != 0 && q->document()->characterAt(position + charsAdded - 1).isPrint()) - m_assistRelevantContentAdded = true; + if ((charsAdded != 0 && q->document()->characterAt(position + charsAdded - 1).isPrint()) || charsRemoved != 0) + m_codeAssistant.notifyChange(); int newBlockCount = doc->blockCount(); if (!q->hasFocus() && newBlockCount != m_blockCount) { diff --git a/src/plugins/vcsbase/vcsoutputformatter.cpp b/src/plugins/vcsbase/vcsoutputformatter.cpp index 2b0aa920295..4b09ed06eb7 100644 --- a/src/plugins/vcsbase/vcsoutputformatter.cpp +++ b/src/plugins/vcsbase/vcsoutputformatter.cpp @@ -31,40 +31,33 @@ namespace VcsBase { VcsOutputFormatter::VcsOutputFormatter() : - m_urlRegexp("https?://\\S*"), - m_referenceRegexp("(v[0-9]+\\.[0-9]+\\.[0-9]+[\\-A-Za-z0-9]*)" // v0.1.2-beta3 - "|([0-9a-f]{6,}(?:\\.\\.[0-9a-f]{6,})?)") // 789acf or 123abc..456cde + m_regexp( + "(https?://\\S*)" // https://codereview.org/c/1234 + "|(v[0-9]+\\.[0-9]+\\.[0-9]+[\\-A-Za-z0-9]*)" // v0.1.2-beta3 + "|([0-9a-f]{6,}(?:\\.\\.[0-9a-f]{6,})?)") // 789acf or 123abc..456cde { } void VcsOutputFormatter::appendMessage(const QString &text, Utils::OutputFormat format) { - const QRegularExpressionMatch urlMatch = m_urlRegexp.match(text); - const QRegularExpressionMatch referenceMatch = m_referenceRegexp.match(text); - - auto append = [this](const QRegularExpressionMatch &match, - QString text, Utils::OutputFormat format) { + QRegularExpressionMatchIterator it = m_regexp.globalMatch(text); + int begin = 0; + while (it.hasNext()) { + const QRegularExpressionMatch match = it.next(); const QTextCharFormat normalFormat = charFormat(format); - OutputFormatter::appendMessage(text.left(match.capturedStart()), format); + OutputFormatter::appendMessage(text.mid(begin, match.capturedStart() - begin), format); QTextCursor tc = plainTextEdit()->textCursor(); QStringView url = match.capturedView(); - int end = match.capturedEnd(); + begin = match.capturedEnd(); while (url.rbegin()->isPunct()) { url.chop(1); - --end; + --begin; } - tc.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); + tc.movePosition(QTextCursor::End); tc.insertText(url.toString(), linkFormat(normalFormat, url.toString())); - tc.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); - OutputFormatter::appendMessage(text.mid(end), format); - }; - - if (urlMatch.hasMatch()) - append(urlMatch, text, format); - else if (referenceMatch.hasMatch()) - append(referenceMatch, text, format); - else - OutputFormatter::appendMessage(text, format); + tc.movePosition(QTextCursor::End); + } + OutputFormatter::appendMessage(text.mid(begin), format); } void VcsOutputFormatter::handleLink(const QString &href) diff --git a/src/plugins/vcsbase/vcsoutputformatter.h b/src/plugins/vcsbase/vcsoutputformatter.h index d1c99b0087f..d1d508b895f 100644 --- a/src/plugins/vcsbase/vcsoutputformatter.h +++ b/src/plugins/vcsbase/vcsoutputformatter.h @@ -42,8 +42,7 @@ signals: void referenceClicked(const QString &reference); private: - const QRegularExpression m_urlRegexp; - const QRegularExpression m_referenceRegexp; + const QRegularExpression m_regexp; }; } diff --git a/tests/system/objects.map b/tests/system/objects.map index 1cc9fc2fd61..1144af6ce21 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -210,7 +210,7 @@ :qdesigner_internal::WidgetBoxCategoryListView {container=':Widget Box_qdesigner_internal::WidgetBoxTreeWidget' occurrence='3' type='qdesigner_internal::WidgetBoxCategoryListView' unnamed='1' visible='1'} :qmakeCallEdit {container=':Qt Creator.scrollArea_QScrollArea' text?='qmake: qmake*' type='QLabel' unnamed='1' visible='1'} :qt_tabwidget_stackedwidget.Core__Internal__GeneralSettings_QWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='Core__Internal__GeneralSettings' type='QWidget' visible='1'} -:qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='QtSupport__Internal__QtVersionManager' type='QtSupport::Internal::QtOptionsPageWidget' visible='1'} +:qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' type='QScrollArea' unnamed='1' visible='1'} :qt_tabwidget_stackedwidget_QScrollArea {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' type='QScrollArea' unnamed='1' visible='1'} :qt_tabwidget_stackedwidget_QWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' type='QWidget' unnamed='1' visible='1'} :qtdirList_QTreeView {container=':qt_tabwidget_stackedwidget_QScrollArea' name='qtdirList' type='QTreeView' visible='1'} diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 48656c38dc8..39cdda43518 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -419,7 +419,7 @@ def __chooseTargets__(targets, availableTargets=None, additionalFunc=None): if additionalFunc: detailsWidget = waitForObject("{type='Utils::DetailsWidget' unnamed='1' " "window=':Qt Creator_Core::Internal::MainWindow' " - "toolTip?='

%s

*' visible='1'}" + "summaryText='%s' visible='1'}" % Targets.getStringForTarget(current)) detailsButton = getChildByClass(detailsWidget, "Utils::DetailsButton") clickButton(detailsButton) diff --git a/tests/system/shared/project_explorer.py b/tests/system/shared/project_explorer.py index ba022dcfed5..880b37a64d4 100644 --- a/tests/system/shared/project_explorer.py +++ b/tests/system/shared/project_explorer.py @@ -147,9 +147,9 @@ def invokeContextMenuOnProject(projectName, menuItem): return projItem def addAndActivateKit(kit): - clickToActivate = "

Click to activate:

" bAndRIndex = getQModelIndexStr("text='Build & Run'", ":Projects.ProjectNavigationTreeView") kitString = Targets.getStringForTarget(kit) + clickToActivate = "

%s

Click to activate

" % kitString switchViewTo(ViewConstants.PROJECTS) try: waitForObject(":Projects.ProjectNavigationTreeView")