forked from qt-creator/qt-creator
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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user