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>
This commit is contained in:
Denis Shienkov
2020-01-24 18:04:19 +03:00
parent 5f1fd0caee
commit de2fc39aa1
+70 -29
View File
@@ -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 &section)
{
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();