diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 889d1a46309..ee4c7198eec 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1233,21 +1233,15 @@ static bool equalKits(Kit *a, Kit *b) void AndroidConfigurations::registerNewToolChains() { - QList existingToolChains = ToolChainManager::toolChains(); - QList toolchains = AndroidToolChainFactory::createToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation()); - foreach (ToolChain *tc, toolchains) { - bool found = false; - for (int i = 0; i < existingToolChains.count(); ++i) { - if (*(existingToolChains.at(i)) == *tc) { - found = true; - break; - } - } - if (found) - delete tc; - else + const QList existingAndroidToolChains + = Utils::filtered(ToolChainManager::toolChains(), + Utils::equal(&ToolChain::typeId, Core::Id(Constants::ANDROID_TOOLCHAIN_ID))); + + const QList newToolchains + = AndroidToolChainFactory::autodetectToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation(), + existingAndroidToolChains); + foreach (ToolChain *tc, newToolchains) ToolChainManager::registerToolChain(tc); - } } void AndroidConfigurations::removeOldToolChains() diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index ab7f362c586..76b1d7bad3f 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -42,6 +42,7 @@ #include #include +#include #include #include @@ -260,8 +261,7 @@ AndroidToolChainFactory::AndroidToolChainFactory() QList AndroidToolChainFactory::autoDetect(const QList &alreadyKnown) { - Q_UNUSED(alreadyKnown); - return createToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation()); + return autodetectToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation(), alreadyKnown); } bool AndroidToolChainFactory::canRestore(const QVariantMap &data) @@ -352,11 +352,23 @@ bool AndroidToolChainFactory::versionCompareLess(AndroidToolChain *atc, AndroidT return versionCompareLess(a, b); } -QList AndroidToolChainFactory::createToolChainsForNdk(const FileName &ndkPath) +static AndroidToolChain *findToolChain(Utils::FileName &compilerPath, const QList &alreadyKnown) +{ + return static_cast( + Utils::findOrDefault(alreadyKnown, [compilerPath](ToolChain *tc) { + return tc->compilerCommand() == compilerPath + && tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID; + })); +} + +QList +AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath, + const QList &alreadyKnown) { QList result; if (ndkPath.isEmpty()) return result; + QRegExp versionRegExp(NDKGccVersionRegExp); FileName path = ndkPath; QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), @@ -373,13 +385,16 @@ QList AndroidToolChainFactory::createToolChainsForNdk(const FileNam Abi abi = AndroidConfig::abiForToolChainPrefix(platform); if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported continue; - AndroidToolChain *tc = new AndroidToolChain(abi, version, ToolChain::AutoDetection); FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, version); - tc->resetToolChain(compilerPath); + + AndroidToolChain *tc = findToolChain(compilerPath, alreadyKnown); + if (!tc) { + tc = new AndroidToolChain(abi, version, ToolChain::AutoDetection); + tc->resetToolChain(compilerPath); + } result.append(tc); - QHash::const_iterator it - = newestToolChainForArch.constFind(abi); + auto it = newestToolChainForArch.constFind(abi); if (it == newestToolChainForArch.constEnd()) newestToolChainForArch.insert(abi, tc); else if (versionCompareLess(it.value(), tc)) @@ -388,8 +403,7 @@ QList AndroidToolChainFactory::createToolChainsForNdk(const FileNam foreach (ToolChain *tc, result) { AndroidToolChain *atc = static_cast(tc); - if (newestToolChainForArch.value(atc->targetAbi()) != atc) - atc->setSecondaryToolChain(true); + atc->setSecondaryToolChain(newestToolChainForArch.value(atc->targetAbi()) != atc); } return result; diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h index a17bfb810e0..dae082dcc41 100644 --- a/src/plugins/android/androidtoolchain.h +++ b/src/plugins/android/androidtoolchain.h @@ -113,7 +113,9 @@ public: QString version; }; - static QList createToolChainsForNdk(const Utils::FileName &ndkPath); + static QList + autodetectToolChainsForNdk(const Utils::FileName &ndkPath, + const QList &alreadyKnown); static QList toolchainPathsForNdk(const Utils::FileName &ndkPath); static QList versionNumberFromString(const QString &version); diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 362160018ac..9bf56c2a6ee 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -375,10 +375,10 @@ QList IosToolChainFactory::autoDetect(const QList &exi foreach (const Platform &platform, platforms) { ClangToolChain *toolChain = findToolChainForPlatform(platform, existingClangToolChains); if (!toolChain) { - ClangToolChain *newToolChain = createToolChain(platform); - toolChains.append(newToolChain); - existingClangToolChains.append(newToolChain); + toolChain = createToolChain(platform); + existingClangToolChains.append(toolChain); } + toolChains.append(toolChain); } return Utils::transform(toolChains, [](ClangToolChain *tc) -> ToolChain * { return tc; }); } diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index f5da4d4dacb..22675549e18 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -819,7 +819,8 @@ QList GccToolChainFactory::autoDetectToolchains(const QString &comp if (compilerPath.isEmpty()) return result; - if (Utils::findOrDefault(alreadyKnown, Utils::equal(&ToolChain::compilerCommand, compilerPath))) + result = Utils::filtered(alreadyKnown, Utils::equal(&ToolChain::compilerCommand, compilerPath)); + if (!result.isEmpty()) return result; GccToolChain::addCommandPathToEnvironment(compilerPath, systemEnvironment); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 08bd7954c21..16633ecc4e2 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -33,6 +33,7 @@ #include "msvcparser.h" #include "projectexplorerconstants.h" +#include #include #include #include @@ -526,9 +527,26 @@ QString MsvcToolChainFactory::vcVarsBatFor(const QString &basePath, MsvcToolChai return vcVarsBatFor(basePath, platformName(platform)); } +static ToolChain *findOrCreateToolChain(const QList &alreadyKnown, + const QString &name, const Abi &abi, + const QString &varsBat, const QString &varsBatArg, + ToolChain::Detection d = ToolChain::ManualDetection) +{ + ToolChain *tc = Utils::findOrDefault(alreadyKnown, + [&varsBat, &varsBatArg](ToolChain *tc) -> bool { + if (tc->typeId() != Constants::MSVC_TOOLCHAIN_TYPEID) + return false; + auto mtc = static_cast(tc); + return mtc->varsBat() == varsBat + && mtc->varsBatArg() == varsBatArg; + }); + if (!tc) + tc = new MsvcToolChain(name, abi, varsBat, varsBatArg, d); + return tc; +} + QList MsvcToolChainFactory::autoDetect(const QList &alreadyKnown) { - Q_UNUSED(alreadyKnown); QList results; // 1) Installed SDKs preferred over standalone Visual studio @@ -550,16 +568,19 @@ QList MsvcToolChainFactory::autoDetect(const QList &al continue; QList tmp; - tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::x86), - findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::x86, sdkKey), - fi.absoluteFilePath(), QLatin1String("/x86"), ToolChain::AutoDetection)); + tmp.append(findOrCreateToolChain(alreadyKnown, + generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::x86), + findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::x86, sdkKey), + fi.absoluteFilePath(), QLatin1String("/x86"), ToolChain::AutoDetection)); // Add all platforms, cross-compiler is automatically selected by SetEnv.cmd if needed - tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::amd64), - findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::amd64, sdkKey), - fi.absoluteFilePath(), QLatin1String("/x64"), ToolChain::AutoDetection)); - tmp.append(new MsvcToolChain(generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::ia64), - findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::ia64, sdkKey), - fi.absoluteFilePath(), QLatin1String("/ia64"), ToolChain::AutoDetection)); + tmp.append(findOrCreateToolChain(alreadyKnown, + generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::amd64), + findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::amd64, sdkKey), + fi.absoluteFilePath(), QLatin1String("/x64"), ToolChain::AutoDetection)); + tmp.append(findOrCreateToolChain(alreadyKnown, + generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::ia64), + findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::ia64, sdkKey), + fi.absoluteFilePath(), QLatin1String("/ia64"), ToolChain::AutoDetection)); // Make sure the default is front. if (folder == defaultSdkPath) results = tmp + results; @@ -601,11 +622,11 @@ QList MsvcToolChainFactory::autoDetect(const QList &al foreach (const MsvcToolChain::Platform &platform, platforms) { if (hostSupportsPlatform(platform) && QFileInfo(vcVarsBatFor(path, platform)).isFile()) { - results.append(new MsvcToolChain( + results.append(findOrCreateToolChain( + alreadyKnown, generateDisplayName(vsName, MsvcToolChain::VS, platform), findAbiOfMsvc(MsvcToolChain::VS, platform, vsName), - vcvarsAllbat, - platformName(platform), + vcvarsAllbat, platformName(platform), ToolChain::AutoDetection)); } } diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp index afcf7567b8f..b26d0ceaa76 100644 --- a/src/plugins/projectexplorer/toolchainmanager.cpp +++ b/src/plugins/projectexplorer/toolchainmanager.cpp @@ -50,7 +50,6 @@ static const char TOOLCHAIN_DATA_KEY[] = "ToolChain."; static const char TOOLCHAIN_COUNT_KEY[] = "ToolChain.Count"; static const char TOOLCHAIN_FILE_VERSION_KEY[] = "Version"; static const char TOOLCHAIN_FILENAME[] = "/qtcreator/toolchains.xml"; -static const char LEGACY_TOOLCHAIN_FILENAME[] = "/toolChains.xml"; using namespace Utils; @@ -167,98 +166,146 @@ static QList restoreFromFile(const FileName &fileName) return result; } +static QList autoDetectToolChains(const QList alreadyKnownTcs) +{ + QList result; + const QList factories + = ExtensionSystem::PluginManager::getObjects(); + foreach (ToolChainFactory *f, factories) + result.append(f->autoDetect(alreadyKnownTcs)); + + return result; +} + +static QList subtractByEqual(const QList &a, const QList &b) +{ + return Utils::filtered(a, [&b](ToolChain *atc) { + return !Utils::anyOf(b, [atc](ToolChain *btc) { return *atc == *btc; }); + }); +} + +static QList subtractByPointerEqual(const QList &a, const QList &b) +{ + return Utils::filtered(a, [&b](ToolChain *atc) { return !b.contains(atc); }); +} + +static QList subtractById(const QList &a, const QList &b) +{ + return Utils::filtered(a, [&b](ToolChain *atc) { + return !Utils::anyOf(b, Utils::equal(&ToolChain::id, atc->id())); + }); +} + +static QList intersectByEqual(const QList &a, const QList &b) +{ + return Utils::filtered(a, [&b](ToolChain *atc) { + return Utils::anyOf(b, [atc](ToolChain *btc) { return *atc == *btc; }); + }); +} + +static QList makeUnique(const QList &a) +{ + return QSet::fromList(a).toList(); +} + +namespace { + +struct ToolChainOperations +{ + QList toDemote; + QList toRegister; + QList toDelete; +}; + +} // namespace + +static ToolChainOperations mergeToolChainLists(const QList &systemFileTcs, + const QList &userFileTcs, + const QList &autodetectedTcs) +{ + const QList manualUserTcs + = Utils::filtered(userFileTcs, [](ToolChain *t) { return !t->isAutoDetected(); }); + + // Remove systemFileTcs from autodetectedUserTcs based on id-matches: + const QList autodetectedUserFileTcs + = Utils::filtered(userFileTcs, &ToolChain::isAutoDetected); + const QList autodetectedUserTcs = subtractById(autodetectedUserFileTcs, systemFileTcs); + + // Calculate a set of Tcs that were detected before (and saved to userFile) and that + // got re-detected again. Take the userTcs (to keep Ids) over the same in autodetectedTcs. + const QList redetectedUserTcs + = intersectByEqual(autodetectedUserTcs, autodetectedTcs); + + // Remove redetected tcs from autodetectedUserTcs: + const QList notRedetectedUserTcs + = subtractByPointerEqual(autodetectedUserTcs, redetectedUserTcs); + + // Remove redetected tcs from autodetectedTcs: + const QList newlyAutodetectedTcs + = subtractByEqual(autodetectedTcs, redetectedUserTcs); + + const QList notRedetectedButValidUserTcs + = Utils::filtered(notRedetectedUserTcs, &ToolChain::isValid); + + const QList validManualUserTcs + = Utils::filtered(manualUserTcs, &ToolChain::isValid); + + ToolChainOperations result; + result.toDemote = notRedetectedButValidUserTcs; + result.toRegister = result.toDemote + systemFileTcs + redetectedUserTcs + newlyAutodetectedTcs + + validManualUserTcs; + + result.toDelete = makeUnique(subtractByPointerEqual(systemFileTcs + userFileTcs + autodetectedTcs, + result.toRegister)); + return result; +} + void ToolChainManager::restoreToolChains() { QTC_ASSERT(!d->m_writer, return); d->m_writer = - new PersistentSettingsWriter(settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)), QLatin1String("QtCreatorToolChains")); - - QList tcsToRegister; - QList tcsToCheck; + new PersistentSettingsWriter(settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)), + QLatin1String("QtCreatorToolChains")); // read all tool chains from SDK - QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName()); - QList readTcs = - restoreFromFile(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(TOOLCHAIN_FILENAME))); - // make sure we mark these as autodetected! - foreach (ToolChain *tc, readTcs) - tc->setDetection(ToolChain::AutoDetection); - - tcsToRegister = readTcs; // SDK TCs are always considered to be up-to-date, so no need to - // recheck them. + const QList systemFileTcs = readSystemFileToolChains(); // read all tool chains from user file. - // Read legacy settings once and keep them around... - FileName fileName = settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)); - if (!fileName.exists()) - fileName = settingsFileName(QLatin1String(LEGACY_TOOLCHAIN_FILENAME)); - readTcs = restoreFromFile(fileName); + const QList userFileTcs + = restoreFromFile(settingsFileName(QLatin1String(TOOLCHAIN_FILENAME))); - foreach (ToolChain *tc, readTcs) { - if (tc->isAutoDetected()) - tcsToCheck.append(tc); - else - tcsToRegister.append(tc); - } - readTcs.clear(); + // Autodetect: Pass autodetected toolchains from user file so the information can be reused: + const QList autodetectedUserFileTcs + = Utils::filtered(userFileTcs, &ToolChain::isAutoDetected); + const QList autodetectedTcs = autoDetectToolChains(autodetectedUserFileTcs); - // Remove TCs configured by the SDK: - foreach (ToolChain *tc, tcsToRegister) { - for (int i = tcsToCheck.count() - 1; i >= 0; --i) { - if (tcsToCheck.at(i)->id() == tc->id()) { - delete tcsToCheck.at(i); - tcsToCheck.removeAt(i); - } - } - } + // merge tool chains and register those that we need to keep: + ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs); - // Then auto detect - QList detectedTcs = tcsToCheck; - QList factories = ExtensionSystem::PluginManager::getObjects(); - foreach (ToolChainFactory *f, factories) - detectedTcs.append(f->autoDetect(tcsToCheck)); + // Process ops: + foreach (ToolChain *tc, ops.toDemote) + tc->setDetection(ToolChain::ManualDetection); - // Find/update autodetected tool chains: - ToolChain *toStore = 0; - foreach (ToolChain *currentDetected, detectedTcs) { - toStore = currentDetected; - - // Check whether we had this TC stored and prefer the old one with the old id, marked - // as auto-detection. - for (int i = 0; i < tcsToCheck.count(); ++i) { - if (tcsToCheck.at(i) == currentDetected) { - tcsToCheck.removeAt(i); - break; - } else if (*(tcsToCheck.at(i)) == *currentDetected) { - toStore = tcsToCheck.at(i); - toStore->setDetection(ToolChain::AutoDetection); - tcsToCheck.removeAt(i); - delete currentDetected; - break; - } - } - tcsToRegister += toStore; - } - - // Keep toolchains that were not rediscovered but are still executable and delete the rest - foreach (ToolChain *tc, tcsToCheck) { - if (!tc->isValid()) { - qWarning() << QString::fromLatin1("ToolChain \"%1\" (%2) dropped since it is not valid") - .arg(tc->displayName()).arg(QString::fromUtf8(tc->id())); - delete tc; - } else { - tc->setDetection(ToolChain::ManualDetection); // "demote" to manual toolchain - tcsToRegister += tc; - } - } - - // Store manual tool chains - foreach (ToolChain *tc, tcsToRegister) + foreach (ToolChain *tc, ops.toRegister) registerToolChain(tc); + qDeleteAll(ops.toDelete); + emit m_instance->toolChainsLoaded(); } +QList ToolChainManager::readSystemFileToolChains() +{ + QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName()); + QList systemTcs + = restoreFromFile(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(TOOLCHAIN_FILENAME))); + + foreach (ToolChain *tc, systemTcs) + tc->setDetection(ToolChain::AutoDetection); + + return systemTcs; +} + void ToolChainManager::saveToolChains() { QVariantMap data; diff --git a/src/plugins/projectexplorer/toolchainmanager.h b/src/plugins/projectexplorer/toolchainmanager.h index f787272a350..9214ac30109 100644 --- a/src/plugins/projectexplorer/toolchainmanager.h +++ b/src/plugins/projectexplorer/toolchainmanager.h @@ -87,6 +87,9 @@ private: // Make sure the this is only called after all // Tool chain Factories are registered! static void restoreToolChains(); + + static QList readSystemFileToolChains(); + static void notifyAboutUpdate(ToolChain *); friend class ProjectExplorerPlugin; // for constructor diff --git a/src/plugins/projectexplorer/wincetoolchain.cpp b/src/plugins/projectexplorer/wincetoolchain.cpp index e83e75947c7..5b6a73301fc 100644 --- a/src/plugins/projectexplorer/wincetoolchain.cpp +++ b/src/plugins/projectexplorer/wincetoolchain.cpp @@ -33,6 +33,7 @@ #include "msvcparser.h" #include "projectexplorerconstants.h" +#include #include #include @@ -352,10 +353,33 @@ WinCEToolChainFactory::WinCEToolChainFactory() setDisplayName(tr("WinCE")); } +static ToolChain *findOrCreateToolChain(const QList &alreadyKnown, + const QString &name, const Abi &abi, + const QString &vcvarsBat, const QString &msvcVer, + const QString &ceVer, const QString &binPath, + const QString &includePath, const QString &libPath, + ToolChain::Detection d = ToolChain::ManualDetection) +{ + ToolChain *tc + = Utils::findOrDefault(alreadyKnown, [&](ToolChain *tc) -> bool { + if (tc->typeId() != Constants::WINCE_TOOLCHAIN_TYPEID) + return false; + auto cetc = static_cast(tc); + return cetc->targetAbi() == abi + && cetc->varsBat() == vcvarsBat + && cetc->msvcVer() == msvcVer + && cetc->ceVer() == ceVer + && cetc->binPath() == binPath + && cetc->includePath() == includePath + && cetc->libPath() == libPath; + }); + if (!tc) + tc = new WinCEToolChain(name, abi, vcvarsBat, msvcVer, ceVer, binPath, includePath, libPath, d); + return tc; +} QList WinCEToolChainFactory::autoDetect(const QList &alreadyKnown) { - Q_UNUSED(alreadyKnown); QList results; // 1) Installed WinCEs @@ -398,16 +422,16 @@ QList WinCEToolChainFactory::autoDetect(const QList &a QString ceVer; if (parseSDK(platformReader, theArch, thePlat, ceVer, binPath, includePath, libPath)) { - WinCEToolChain *pChain = new WinCEToolChain(thePlat, - Abi(theArch, Abi::WindowsOS, Abi::WindowsCEFlavor, Abi::PEFormat, 32), - vcvars32bat, - msvcVer, - ceVer, - binPath, - includePath, - libPath, - ToolChain::AutoDetection); - results.append(pChain); + results.append(findOrCreateToolChain(alreadyKnown, + thePlat, + Abi(theArch, Abi::WindowsOS, Abi::WindowsCEFlavor, Abi::PEFormat, 32), + vcvars32bat, + msvcVer, + ceVer, + binPath, + includePath, + libPath, + ToolChain::AutoDetection)); } } } diff --git a/src/plugins/projectexplorer/wincetoolchain.h b/src/plugins/projectexplorer/wincetoolchain.h index 221d4ced45f..44c0e3f3c68 100644 --- a/src/plugins/projectexplorer/wincetoolchain.h +++ b/src/plugins/projectexplorer/wincetoolchain.h @@ -57,8 +57,13 @@ public: QString typeDisplayName() const override; + QString msvcVer() const { return m_msvcVer; } QString ceVer() const; + QString binPath() const { return m_binPath; } + QString includePath() const { return m_includePath; } + QString libPath() const { return m_libPath; } + QVariantMap toMap() const override; bool fromMap(const QVariantMap &data) override;