diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2020-01-24 18:04:19 +0300 |
---|---|---|
committer | Denis Shienkov <denis.shienkov@gmail.com> | 2020-01-27 12:48:00 +0000 |
commit | de2fc39aa11aba1f94646f055b71bf42ad711f0b (patch) | |
tree | 8e8381c4d1e1b490e7100b514d302a77e4d15394 | |
parent | 5f1fd0caeea9a78a521ecc88d5315f2829da28d8 (diff) | |
download | qt-creator-de2fc39aa11aba1f94646f055b71bf42ad711f0b.tar.gz |
BareMetal: Fix Keil toolchains detection on Windows
A problem is that a latest installed toolchain overrides a previous
installed toolchain. In this case a previous toolchain will be skipped
from the search.
We need to fetch an information from the 'uninstall' registry entry,
which describes all installed toolchains.
Change-Id: I662e2696900909607d5ce618a728804e3683c856
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r-- | src/plugins/baremetal/keiltoolchain.cpp | 99 |
1 files changed, 70 insertions, 29 deletions
diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index eb6afe8e0e..ce3da730a1 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -401,48 +401,89 @@ KeilToolchainFactory::KeilToolchainFactory() setUserCreatable(true); } +// Parse the 'tools.ini' file to fetch a toolchain version. +// Note: We can't use QSettings here! +static QString extractVersion(const QString &toolsFile, const QString §ion) +{ + QFile f(toolsFile); + if (!f.open(QIODevice::ReadOnly)) + return {}; + QTextStream in(&f); + enum State { Enter, Lookup, Exit } state = Enter; + while (!in.atEnd()) { + const QString line = in.readLine().trimmed(); + // Search for section. + const int firstBracket = line.indexOf('['); + const int lastBracket = line.lastIndexOf(']'); + const bool hasSection = (firstBracket == 0 && lastBracket != -1 + && (lastBracket + 1) == line.size()); + switch (state) { + case Enter: + if (hasSection) { + const auto content = line.midRef(firstBracket + 1, + lastBracket - firstBracket - 1); + if (content == section) + state = Lookup; + } + break; + case Lookup: { + if (hasSection) + return {}; // Next section found. + const int versionIndex = line.indexOf("VERSION="); + if (versionIndex < 0) + continue; + QString version = line.mid(8); + if (version.startsWith('V')) + version.remove(0, 1); + return version; + } + break; + default: + return {}; + } + } + return {}; +} + QList<ToolChain *> KeilToolchainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) { #ifdef Q_OS_WIN64 - static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Keil\\Products"; + static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\" \ + "Windows\\CurrentVersion\\Uninstall\\Keil µVision4" #else - static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Keil\\Products"; + static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" \ + "Windows\\CurrentVersion\\Uninstall\\Keil µVision4"; #endif - struct Entry { - QString productKey; - QString subExePath; - }; - - // Dictionary for know toolchains. - static const std::array<Entry, 2> knowToolchains = {{ - {QString("MDK"), QString("\\ARMCC\\bin\\armcc.exe")}, - {QString("C51"), QString("\\BIN\\c51.exe")}, - }}; - Candidates candidates; QSettings registry(kRegistryNode, QSettings::NativeFormat); const auto productGroups = registry.childGroups(); for (const QString &productKey : productGroups) { - const Entry entry = Utils::findOrDefault(knowToolchains, - [productKey](const Entry &entry) { - return entry.productKey == productKey; }); - - if (entry.productKey.isEmpty()) + if (!productKey.startsWith("App")) continue; - registry.beginGroup(productKey); - QString compilerPath = registry.value("Path").toString(); - if (!compilerPath.isEmpty()) { - // Build full compiler path. - compilerPath += entry.subExePath; - const FilePath fn = FilePath::fromString(compilerPath); - if (compilerExists(fn)) { - QString version = registry.value("Version").toString(); - if (version.startsWith('V')) - version.remove(0, 1); - candidates.push_back({fn, version}); + const FilePath productPath(FilePath::fromString(registry.value("ProductDir") + .toString())); + // Fetch the toolchain executable path. + FilePath compilerPath; + if (productPath.endsWith("ARM")) + compilerPath = productPath.pathAppended("\\ARMCC\\bin\\armcc.exe"); + else if (productPath.endsWith("C51")) + compilerPath = productPath.pathAppended("\\BIN\\c51.exe"); + + if (compilerPath.exists()) { + // Fetch the toolchain version. + const QDir rootDir(registry.value("Directory").toString()); + const QString toolsFilePath = rootDir.absoluteFilePath("tools.ini"); + for (auto index = 1; index <= 2; ++index) { + const QString section = registry.value( + QStringLiteral("Section %1").arg(index)).toString(); + const QString version = extractVersion(toolsFilePath, section); + if (!version.isEmpty()) { + candidates.push_back({compilerPath, version}); + break; + } } } registry.endGroup(); |