diff options
Diffstat (limited to 'src/app/qbs-setup-toolchains')
-rw-r--r-- | src/app/qbs-setup-toolchains/clangclprobe.cpp | 108 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/clangclprobe.h | 6 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/gccprobe.cpp | 32 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/gccprobe.h | 4 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/iarewprobe.cpp | 29 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/iarewprobe.h | 2 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/keilprobe.cpp | 337 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/keilprobe.h | 2 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/main.cpp | 1 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/msvcprobe.cpp | 284 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/msvcprobe.h | 12 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/probe.cpp | 46 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/probe.h | 2 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/sdccprobe.cpp | 37 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/sdccprobe.h | 4 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/xcodeprobe.cpp | 12 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/xcodeprobe.h | 2 |
17 files changed, 375 insertions, 545 deletions
diff --git a/src/app/qbs-setup-toolchains/clangclprobe.cpp b/src/app/qbs-setup-toolchains/clangclprobe.cpp index 816d28546..d1a3a9ac5 100644 --- a/src/app/qbs-setup-toolchains/clangclprobe.cpp +++ b/src/app/qbs-setup-toolchains/clangclprobe.cpp @@ -44,7 +44,9 @@ #include "../shared/logging/consolelogger.h" #include <logging/translator.h> +#include <tools/clangclinfo.h> #include <tools/hostosinfo.h> +#include <tools/msvcinfo.h> #include <tools/profile.h> #include <tools/qttools.h> #include <tools/settings.h> @@ -54,17 +56,13 @@ using qbs::Settings; using qbs::Profile; +using qbs::Internal::ClangClInfo; using qbs::Internal::HostOsInfo; using qbs::Internal::Tr; namespace { -QString getToolchainInstallPath(const QFileInfo &compiler) -{ - return compiler.path(); // 1 level up -} - Profile createProfileHelper( Settings *settings, const QString &profileName, @@ -75,9 +73,7 @@ Profile createProfileHelper( Profile profile(profileName, settings); profile.removeProfile(); profile.setValue(QStringLiteral("qbs.architecture"), architecture); - profile.setValue( - QStringLiteral("qbs.toolchain"), - QStringList{QStringLiteral("clang-cl"), QStringLiteral("msvc")}); + profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("clang-cl")); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), toolchainInstallPath); profile.setValue(QStringLiteral("cpp.vcvarsallPath"), vcvarsallPath); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") @@ -85,47 +81,6 @@ Profile createProfileHelper( return profile; } -std::vector<MSVCInstallInfo> compatibleMsvcs() -{ - auto msvcs = installedMSVCs(); - auto filter = [](const MSVCInstallInfo &info) - { - const auto versions = info.version.split(QLatin1Char('.')); - if (versions.empty()) - return true; - bool ok = false; - const int major = versions.at(0).toInt(&ok); - return !(ok && major >= 15); // support MSVC2017 and above - }; - const auto it = std::remove_if(msvcs.begin(), msvcs.end(), filter); - msvcs.erase(it, msvcs.end()); - for (const auto &msvc: msvcs) { - auto vcvarsallPath = msvc.findVcvarsallBat(); - if (vcvarsallPath.isEmpty()) - continue; - } - return msvcs; -} - -QString findCompatibleVcsarsallBat() -{ - for (const auto &msvc: compatibleMsvcs()) { - const auto vcvarsallPath = msvc.findVcvarsallBat(); - if (!vcvarsallPath.isEmpty()) - return vcvarsallPath; - } - return {}; -} - -QString wow6432Key() -{ -#ifdef Q_OS_WIN64 - return QStringLiteral("\\Wow6432Node"); -#else - return {}; -#endif -} - QString findClangCl() { const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl")); @@ -133,27 +88,6 @@ QString findClangCl() if (!compilerFromPath.isEmpty()) return compilerFromPath; - const QSettings registry( - QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\LLVM\\LLVM").arg(wow6432Key()), - QSettings::NativeFormat); - const auto key = QStringLiteral("."); - if (registry.contains(key)) { - const auto compilerPath = QDir::fromNativeSeparators(registry.value(key).toString()) - + QStringLiteral("/bin/") + compilerName; - if (QFileInfo(compilerPath).exists()) - return compilerPath; - } - - // this branch can be useful in case user had two LLVM installations (e.g. 32bit & 64bit) - // but uninstalled one - in that case, registry will be empty - static const char * const envVarCandidates[] = {"ProgramFiles", "ProgramFiles(x86)"}; - for (const auto &envVar : envVarCandidates) { - const auto value - = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar))); - const auto compilerPath = value + QStringLiteral("/LLVM/bin/") + compilerName; - if (QFileInfo(compilerPath).exists()) - return compilerPath; - } return {}; } @@ -162,51 +96,39 @@ QString findClangCl() void createClangClProfile(const QFileInfo &compiler, Settings *settings, const QString &profileName) { - const auto compilerName = QStringLiteral("clang-cl"); - const auto vcvarsallPath = findCompatibleVcsarsallBat(); - if (vcvarsallPath.isEmpty()) { - qbsWarning() - << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") - .arg(compilerName); + const auto clangCl = ClangClInfo::fromCompilerFilePath( + compiler.filePath(), ConsoleLogger::instance()); + if (clangCl.isEmpty()) return; - } - - const auto toolchainInstallPath = getToolchainInstallPath(compiler); const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture()); - createProfileHelper(settings, profileName, toolchainInstallPath, vcvarsallPath, hostArch); + createProfileHelper( + settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, hostArch); } /*! \brief Creates a clang-cl profile based on auto-detected vsversion. \internal */ -void clangClProbe(Settings *settings, QList<Profile> &profiles) +void clangClProbe(Settings *settings, std::vector<Profile> &profiles) { const auto compilerName = QStringLiteral("clang-cl"); qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName); - const QString compilerFilePath = findClangCl(); - if (compilerFilePath.isEmpty()) { + const auto clangCls = ClangClInfo::installedCompilers( + {findClangCl()}, ConsoleLogger::instance()); + if (clangCls.empty()) { qbsInfo() << Tr::tr("%1 was not found.").arg(compilerName); return; } - const QFileInfo compiler(compilerFilePath); - const auto vcvarsallPath = findCompatibleVcsarsallBat(); - if (vcvarsallPath.isEmpty()) { - qbsWarning() - << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") - .arg(compilerName); - return; - } + const auto clangCl = clangCls.front(); const QString architectures[] = { QStringLiteral("x86_64"), QStringLiteral("x86") }; - const auto toolchainInstallPath = getToolchainInstallPath(compiler); for (const auto &arch: architectures) { const auto profileName = QStringLiteral("clang-cl-%1").arg(arch); auto profile = createProfileHelper( - settings, profileName, toolchainInstallPath, vcvarsallPath, arch); + settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, arch); profiles.push_back(std::move(profile)); } } diff --git a/src/app/qbs-setup-toolchains/clangclprobe.h b/src/app/qbs-setup-toolchains/clangclprobe.h index 1afbbb1b8..2de1c0a64 100644 --- a/src/app/qbs-setup-toolchains/clangclprobe.h +++ b/src/app/qbs-setup-toolchains/clangclprobe.h @@ -40,7 +40,9 @@ #ifndef QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H #define QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H -#include <QtCore/qlist.h> +#include <QString> + +#include <vector> QT_BEGIN_NAMESPACE class QFileInfo; @@ -54,6 +56,6 @@ class Settings; void createClangClProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName); -void clangClProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles); +void clangClProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles); #endif // Header guard diff --git a/src/app/qbs-setup-toolchains/gccprobe.cpp b/src/app/qbs-setup-toolchains/gccprobe.cpp index 78439cbcb..6cbe246a5 100644 --- a/src/app/qbs-setup-toolchains/gccprobe.cpp +++ b/src/app/qbs-setup-toolchains/gccprobe.cpp @@ -111,7 +111,7 @@ class ToolchainDetails public: explicit ToolchainDetails(const QFileInfo &compiler) { - auto baseName = compiler.completeBaseName(); + auto baseName = HostOsInfo::stripExecutableSuffix(compiler.fileName()); // Extract the version sub-string if it exists. We assume that a version // sub-string located after the compiler prefix && suffix. E.g. this code // parses a version from the compiler names, like this: @@ -138,9 +138,9 @@ public: }; static void setCommonProperties(Profile &profile, const QFileInfo &compiler, - const QStringList &toolchainTypes, const ToolchainDetails &details) + const QString &toolchainType, const ToolchainDetails &details) { - if (toolchainTypes.contains(QStringLiteral("mingw"))) + if (toolchainType == QStringLiteral("mingw")) profile.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("windows")); @@ -149,7 +149,7 @@ static void setCommonProperties(Profile &profile, const QFileInfo &compiler, profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); - profile.setValue(QStringLiteral("qbs.toolchain"), toolchainTypes); + profile.setValue(QStringLiteral("qbs.toolchainType"), toolchainType); if (!standardCompilerFileNames().contains( HostOsInfo::appendExecutableSuffix(details.suffix))) { @@ -453,12 +453,12 @@ static QStringList mplabX32RegistrySearchPaths() } Profile createGccProfile(const QFileInfo &compiler, Settings *settings, - const QStringList &toolchainTypes, + const QString &toolchainType, const QString &profileName) { const QString machineName = gccMachineName(compiler); - if (toolchainTypes.contains(QLatin1String("mingw"))) { + if (toolchainType == QLatin1String("mingw")) { if (!validMinGWMachines().contains(machineName)) { throw ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.") .arg(machineName)); @@ -470,9 +470,9 @@ Profile createGccProfile(const QFileInfo &compiler, Settings *settings, const ToolchainDetails details(compiler); - setCommonProperties(profile, compiler, toolchainTypes, details); + setCommonProperties(profile, compiler, toolchainType, details); - if (HostOsInfo::isWindowsHost() && toolchainTypes.contains(QLatin1String("clang"))) { + if (HostOsInfo::isWindowsHost() && toolchainType == QLatin1String("clang")) { const QStringList profileNames = settings->profiles(); bool foundMingw = false; for (const QString &profileName : profileNames) { @@ -497,7 +497,7 @@ Profile createGccProfile(const QFileInfo &compiler, Settings *settings, } } - if (!toolchainTypes.contains(QLatin1String("clang"))) { + if (toolchainType != QLatin1String("clang")) { // Check whether auxiliary tools reside within the toolchain's install path. // This might not be the case when using icecc or another compiler wrapper. const QString compilerDirPath = compiler.absolutePath(); @@ -520,7 +520,7 @@ Profile createGccProfile(const QFileInfo &compiler, Settings *settings, return profile; } -void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName) +void gccProbe(Settings *settings, std::vector<Profile> &profiles, const QString &compilerName) { qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName); @@ -582,11 +582,15 @@ void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compi } for (const auto &candidate : qAsConst(candidates)) { - const QStringList toolchainTypes = toolchainTypeFromCompilerName( + const QString toolchainType = toolchainTypeFromCompilerName( candidate.baseName()); const QString profileName = buildProfileName(candidate); - auto profile = createGccProfile(candidate, settings, - toolchainTypes, profileName); - profiles.push_back(std::move(profile)); + try { + auto profile = createGccProfile(candidate, settings, + toolchainType, profileName); + profiles.push_back(std::move(profile)); + } catch (const qbs::ErrorInfo &info) { + qbsWarning() << Tr::tr("Skipping %1: %2").arg(profileName, info.toString()); + } } } diff --git a/src/app/qbs-setup-toolchains/gccprobe.h b/src/app/qbs-setup-toolchains/gccprobe.h index 4344c5836..98e7eaa1f 100644 --- a/src/app/qbs-setup-toolchains/gccprobe.h +++ b/src/app/qbs-setup-toolchains/gccprobe.h @@ -53,10 +53,10 @@ class Settings; qbs::Profile createGccProfile(const QFileInfo &compiler, qbs::Settings *settings, - const QStringList &toolchainTypes, + const QString &toolchainType, const QString &profileName = QString()); -void gccProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles, +void gccProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles, const QString &compilerName); #endif // Header guard diff --git a/src/app/qbs-setup-toolchains/iarewprobe.cpp b/src/app/qbs-setup-toolchains/iarewprobe.cpp index 26ee57da9..de7b62574 100644 --- a/src/app/qbs-setup-toolchains/iarewprobe.cpp +++ b/src/app/qbs-setup-toolchains/iarewprobe.cpp @@ -59,7 +59,9 @@ static QStringList knownIarCompilerNames() { return {QStringLiteral("icc8051"), QStringLiteral("iccarm"), QStringLiteral("iccavr"), QStringLiteral("iccstm8"), - QStringLiteral("icc430"), QStringLiteral("iccrl78")}; + QStringLiteral("icc430"), QStringLiteral("iccrl78"), + QStringLiteral("iccrx"), QStringLiteral("iccrh850"), + QStringLiteral("iccv850"), QStringLiteral("icc78k")}; } static QString guessIarArchitecture(const QFileInfo &compiler) @@ -77,6 +79,14 @@ static QString guessIarArchitecture(const QFileInfo &compiler) return QStringLiteral("msp430"); if (baseName == QLatin1String("iccrl78")) return QStringLiteral("rl78"); + if (baseName == QLatin1String("iccrx")) + return QStringLiteral("rx"); + if (baseName == QLatin1String("iccrh850")) + return QStringLiteral("rh850"); + if (baseName == QLatin1String("iccv850")) + return QStringLiteral("v850"); + if (baseName == QLatin1String("icc78k")) + return QStringLiteral("78k"); return {}; } @@ -148,7 +158,11 @@ static Version dumpIarCompilerVersion(const QFileInfo &compiler) || arch == QLatin1String("mcs51") || arch == QLatin1String("stm8") || arch == QLatin1String("msp430") - || arch == QLatin1String("rl78")) { + || arch == QLatin1String("rl78") + || arch == QLatin1String("rx") + || arch == QLatin1String("rh850") + || arch == QLatin1String("v850") + || arch == QLatin1String("78k")) { return Version{verCode / 100, verCode % 100}; } @@ -195,6 +209,10 @@ static std::vector<ToolchainInstallInfo> installedIarsFromRegistry() {QStringLiteral("EWSTM8"), QStringLiteral("\\stm8\\bin\\iccstm8.exe")}, {QStringLiteral("EW430"), QStringLiteral("\\430\\bin\\icc430.exe")}, {QStringLiteral("EWRL78"), QStringLiteral("\\rl78\\bin\\iccrl78.exe")}, + {QStringLiteral("EWRX"), QStringLiteral("\\rx\\bin\\iccrx.exe")}, + {QStringLiteral("EWRH850"), QStringLiteral("\\rh850\\bin\\iccrh850.exe")}, + {QStringLiteral("EWV850"), QStringLiteral("\\v850\\bin\\iccv850.exe")}, + {QStringLiteral("EW78K"), QStringLiteral("\\78k\\bin\\icc78k.exe")}, }; QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat); @@ -215,8 +233,7 @@ static std::vector<ToolchainInstallInfo> installedIarsFromRegistry() const QFileInfo iarPath(rootPath + entry.subExePath); if (iarPath.exists()) { // Note: threeLevelKey is a guessed toolchain version. - const QString version = threeLevelKey; - infos.push_back({iarPath, Version::fromString(version)}); + infos.push_back({iarPath, Version::fromString(threeLevelKey)}); } } registry.endGroup(); @@ -245,10 +262,10 @@ void createIarProfile(const QFileInfo &compiler, Settings *settings, QString profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; - createIarProfileHelper(info, settings, profileName); + createIarProfileHelper(info, settings, std::move(profileName)); } -void iarProbe(Settings *settings, QList<Profile> &profiles) +void iarProbe(Settings *settings, std::vector<Profile> &profiles) { qbsInfo() << Tr::tr("Trying to detect IAR toolchains..."); diff --git a/src/app/qbs-setup-toolchains/iarewprobe.h b/src/app/qbs-setup-toolchains/iarewprobe.h index b604d6c6b..a1a51daa4 100644 --- a/src/app/qbs-setup-toolchains/iarewprobe.h +++ b/src/app/qbs-setup-toolchains/iarewprobe.h @@ -56,6 +56,6 @@ bool isIarCompiler(const QString &compilerName); void createIarProfile(const QFileInfo &compiler, qbs::Settings *settings, QString profileName); -void iarProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles); +void iarProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles); #endif // Header guard diff --git a/src/app/qbs-setup-toolchains/keilprobe.cpp b/src/app/qbs-setup-toolchains/keilprobe.cpp index 08f0f2167..67b14a802 100644 --- a/src/app/qbs-setup-toolchains/keilprobe.cpp +++ b/src/app/qbs-setup-toolchains/keilprobe.cpp @@ -47,6 +47,7 @@ #include <tools/hostosinfo.h> #include <tools/profile.h> +#include <QtCore/qdir.h> #include <QtCore/qprocess.h> #include <QtCore/qsettings.h> #include <QtCore/qtemporaryfile.h> @@ -57,7 +58,8 @@ using Internal::HostOsInfo; static QStringList knownKeilCompilerNames() { - return {QStringLiteral("c51"), QStringLiteral("armcc")}; + return {QStringLiteral("c51"), QStringLiteral("c251"), + QStringLiteral("c166"), QStringLiteral("armcc")}; } static QString guessKeilArchitecture(const QFileInfo &compiler) @@ -65,6 +67,10 @@ static QString guessKeilArchitecture(const QFileInfo &compiler) const auto baseName = compiler.baseName(); if (baseName == QLatin1String("c51")) return QStringLiteral("mcs51"); + if (baseName == QLatin1String("c251")) + return QStringLiteral("mcs251"); + if (baseName == QLatin1String("c166")) + return QStringLiteral("c166"); if (baseName == QLatin1String("armcc")) return QStringLiteral("arm"); return {}; @@ -100,74 +106,173 @@ static Profile createKeilProfileHelper(const ToolchainInstallInfo &info, return profile; } -static Version dumpKeilCompilerVersion(const QFileInfo &compiler) +static Version dumpMcsCompilerVersion(const QFileInfo &compiler) { - const QString arch = guessKeilArchitecture(compiler); - if (arch == QLatin1String("mcs51")) { - QTemporaryFile fakeIn; - if (!fakeIn.open()) { - qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") - .arg(fakeIn.fileName(), fakeIn.errorString()); - return Version{}; - } - fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); - fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); - fakeIn.write("#define VAR_NAME_VALUE(var) \"\"\"|\"#var\"|\"VALUE(var)\n"); - fakeIn.write("#ifdef __C51__\n"); - fakeIn.write("#pragma message(VAR_NAME_VALUE(__C51__))\n"); - fakeIn.write("#endif\n"); - fakeIn.write("#ifdef __CX51__\n"); - fakeIn.write("#pragma message(VAR_NAME_VALUE(__CX51__))\n"); - fakeIn.write("#endif\n"); - fakeIn.close(); - - const QStringList args = {fakeIn.fileName()}; - QProcess p; - p.start(compiler.absoluteFilePath(), args); - p.waitForFinished(3000); - const auto es = p.exitStatus(); - if (es != QProcess::NormalExit) { - const QByteArray out = p.readAll(); - qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") - .arg(QString::fromUtf8(out)); - return Version{}; - } + QTemporaryFile fakeIn; + if (!fakeIn.open()) { + qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") + .arg(fakeIn.fileName(), fakeIn.errorString()); + return Version{}; + } - const QByteArray dump = p.readAllStandardOutput(); - const int verCode = extractVersion(dump, "\"__C51__\"|\""); - if (verCode < 0) { - qbsWarning() << Tr::tr("No '__C51__' token was found" - " in the compiler dump:\n%1") - .arg(QString::fromUtf8(dump)); - return Version{}; - } - return Version{verCode / 100, verCode % 100}; - } else if (arch == QLatin1String("arm")) { - const QStringList args = {QStringLiteral("-E"), - QStringLiteral("--list-macros"), - QStringLiteral("nul")}; - QProcess p; - p.start(compiler.absoluteFilePath(), args); - p.waitForFinished(3000); - const auto es = p.exitStatus(); - if (es != QProcess::NormalExit) { - const QByteArray out = p.readAll(); - qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") - .arg(QString::fromUtf8(out)); - return Version{}; + fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); + fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); + + // Prepare for C51 compiler. + fakeIn.write("#if defined(__C51__) || defined(__CX51__)\n"); + fakeIn.write("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\"\n"); + fakeIn.write("# if defined (__C51__)\n"); + fakeIn.write("# pragma message (VAR_NAME_VALUE(__C51__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("# if defined(__CX51__)\n"); + fakeIn.write("# pragma message (VAR_NAME_VALUE(__CX51__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("#endif\n"); + + // Prepare for C251 compiler. + fakeIn.write("#if defined(__C251__)\n"); + fakeIn.write("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\"\n"); + fakeIn.write("# if defined(__C251__)\n"); + fakeIn.write("# warning (VAR_NAME_VALUE(__C251__))\n"); + fakeIn.write("# endif\n"); + fakeIn.write("#endif\n"); + + fakeIn.close(); + + const QStringList args = {fakeIn.fileName()}; + QProcess p; + p.start(compiler.absoluteFilePath(), args); + p.waitForFinished(3000); + + const QStringList knownKeys = {QStringLiteral("__C51__"), + QStringLiteral("__CX51__"), + QStringLiteral("__C251__")}; + + auto extractVersion = [&knownKeys](const QByteArray &output) { + QTextStream stream(output); + QString line; + while (stream.readLineInto(&line)) { + if (!line.startsWith(QLatin1String("***"))) + continue; + enum { KEY_INDEX = 1, VALUE_INDEX = 2, ALL_PARTS = 4 }; + const QStringList parts = line.split(QLatin1String("\"|\"")); + if (parts.count() != ALL_PARTS) + continue; + if (!knownKeys.contains(parts.at(KEY_INDEX))) + continue; + return parts.at(VALUE_INDEX).toInt(); } + return -1; + }; + + const QByteArray dump = p.readAllStandardOutput(); + const int verCode = extractVersion(dump); + if (verCode < 0) { + qbsWarning() << Tr::tr("No %1 tokens was found" + " in the compiler dump:\n%2") + .arg(knownKeys.join(QLatin1Char(','))) + .arg(QString::fromUtf8(dump)); + return Version{}; + } + return Version{verCode / 100, verCode % 100}; +} - const QByteArray dump = p.readAll(); - const int verCode = extractVersion(dump, "__ARMCC_VERSION "); - if (verCode < 0) { - qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found " - "in the compiler dump:\n%1") - .arg(QString::fromUtf8(dump)); - return Version{}; +static Version dumpC166CompilerVersion(const QFileInfo &compiler) +{ + QTemporaryFile fakeIn; + if (!fakeIn.open()) { + qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") + .arg(fakeIn.fileName(), fakeIn.errorString()); + return Version{}; + } + + fakeIn.write("#if defined(__C166__)\n"); + fakeIn.write("# warning __C166__\n"); + fakeIn.write("# pragma __C166__\n"); + fakeIn.write("#endif\n"); + + fakeIn.close(); + + const QStringList args = {fakeIn.fileName()}; + QProcess p; + p.start(compiler.absoluteFilePath(), args); + p.waitForFinished(3000); + + // Extract the compiler version pattern in the form, like: + // + // *** WARNING C320 IN LINE 41 OF c51.c: __C166__ + // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored + // + // where the '__C166__' is a key, and the '757' is a value (aka version). + auto extractVersion = [](const QString &output) { + const QStringList lines = output.split(QStringLiteral("\r\n")); + for (auto it = lines.cbegin(); it != lines.cend();) { + if (it->startsWith(QLatin1String("***")) && it->endsWith(QLatin1String("__C166__"))) { + ++it; + if (it == lines.cend() || !it->startsWith(QLatin1String("***"))) + break; + const int startIndex = it->indexOf(QLatin1Char('\'')); + if (startIndex == -1) + break; + const int stopIndex = it->indexOf(QLatin1Char('\''), startIndex + 1); + if (stopIndex == -1) + break; + const QString v = it->mid(startIndex + 1, stopIndex - startIndex - 1); + return v.toInt(); + } + ++it; } - return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000}; + return -1; + }; + + const QByteArray dump = p.readAllStandardOutput(); + const int verCode = extractVersion(QString::fromUtf8(dump)); + if (verCode < 0) { + qbsWarning() << Tr::tr("No __C166__ token was found" + " in the compiler dump:\n%1") + .arg(QString::fromUtf8(dump)); + return Version{}; } + return Version{verCode / 100, verCode % 100}; +} +static Version dumpArmCompilerVersion(const QFileInfo &compiler) +{ + const QStringList args = {QStringLiteral("-E"), + QStringLiteral("--list-macros"), + QStringLiteral("nul")}; + QProcess p; + p.start(compiler.absoluteFilePath(), args); + p.waitForFinished(3000); + const auto es = p.exitStatus(); + if (es != QProcess::NormalExit) { + const QByteArray out = p.readAll(); + qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") + .arg(QString::fromUtf8(out)); + return Version{}; + } + + const QByteArray dump = p.readAll(); + const int verCode = extractVersion(dump, "__ARMCC_VERSION "); + if (verCode < 0) { + qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found " + "in the compiler dump:\n%1") + .arg(QString::fromUtf8(dump)); + return Version{}; + } + return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000}; +} + +static Version dumpKeilCompilerVersion(const QFileInfo &compiler) +{ + const QString arch = guessKeilArchitecture(compiler); + if (arch == QLatin1String("mcs51") || arch == QLatin1String("mcs251")) { + return dumpMcsCompilerVersion(compiler); + } else if (arch == QLatin1String("c166")) { + return dumpC166CompilerVersion(compiler); + } else if (arch == QLatin1String("arm")) { + return dumpArmCompilerVersion(compiler); + } return Version{}; } @@ -188,6 +293,51 @@ static std::vector<ToolchainInstallInfo> installedKeilsFromPath() return infos; } +// Parse the 'tools.ini' file to fetch a toolchain version. +// Note: We can't use QSettings here! +static QString extractVersion(const QString &toolsIniFile, const QString §ion) +{ + QFile f(toolsIniFile); + 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(QLatin1Char('[')); + const int lastBracket = line.lastIndexOf(QLatin1Char(']')); + 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(QLatin1String("VERSION=")); + if (versionIndex < 0) + continue; + QString version = line.mid(8); + if (version.startsWith(QLatin1Char('V'))) + version.remove(0, 1); + return version; + } + break; + default: + return {}; + } + } + return {}; +} + static std::vector<ToolchainInstallInfo> installedKeilsFromRegistry() { std::vector<ToolchainInstallInfo> infos; @@ -195,48 +345,49 @@ static std::vector<ToolchainInstallInfo> installedKeilsFromRegistry() if (HostOsInfo::isWindowsHost()) { #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 \u00B5Vision4"; #else - static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Keil\\Products"; + static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" \ + "Windows\\CurrentVersion\\Uninstall\\Keil \u00B5Vision4"; #endif - // Dictionary for know toolchains. - static const struct Entry { - QString productKey; - QString subExePath; - } knowToolchains[] = { - {QStringLiteral("MDK"), QStringLiteral("\\ARMCC\\bin\\armcc.exe")}, - {QStringLiteral("C51"), QStringLiteral("\\BIN\\c51.exe")}, - }; - QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat); const auto productGroups = registry.childGroups(); for (const QString &productKey : productGroups) { - const auto entryEnd = std::end(knowToolchains); - const auto entryIt = std::find_if(std::begin(knowToolchains), entryEnd, - [productKey](const Entry &entry) { - return entry.productKey == productKey; - }); - if (entryIt == entryEnd) + if (!productKey.startsWith(QStringLiteral("App"))) continue; - registry.beginGroup(productKey); - const QString rootPath = registry.value(QStringLiteral("Path")) + const QString productPath = registry.value(QStringLiteral("ProductDir")) .toString(); - if (!rootPath.isEmpty()) { - // Build full compiler path. - const QFileInfo keilPath(rootPath + entryIt->subExePath); - if (keilPath.exists()) { - QString version = registry.value(QStringLiteral("Version")) - .toString(); - if (version.startsWith(QLatin1Char('V'))) - version.remove(0, 1); - infos.push_back({keilPath, Version::fromString(version)}); + // Fetch the toolchain executable path. + QFileInfo keilPath; + if (productPath.endsWith(QStringLiteral("ARM"))) + keilPath.setFile(productPath + QStringLiteral("\\ARMCC\\bin\\armcc.exe")); + else if (productPath.endsWith(QStringLiteral("C51"))) + keilPath.setFile(productPath + QStringLiteral("\\BIN\\c51.exe")); + else if (productPath.endsWith(QStringLiteral("C251"))) + keilPath.setFile(productPath + QStringLiteral("\\BIN\\c251.exe")); + else if (productPath.endsWith(QStringLiteral("C166"))) + keilPath.setFile(productPath + QStringLiteral("\\BIN\\c166.exe")); + + if (keilPath.exists()) { + // Fetch the toolchain version. + const QDir rootPath(registry.value(QStringLiteral("Directory")).toString()); + const QString toolsIniFilePath = rootPath.absoluteFilePath( + QStringLiteral("tools.ini")); + for (auto index = 1; index <= 2; ++index) { + const QString section = registry.value( + QStringLiteral("Section %1").arg(index)).toString(); + const QString version = extractVersion(toolsIniFilePath, section); + if (!version.isEmpty()) { + infos.push_back({keilPath, Version::fromString(version)}); + break; + } } } registry.endGroup(); } - } std::sort(infos.begin(), infos.end()); @@ -255,10 +406,10 @@ void createKeilProfile(const QFileInfo &compiler, Settings *settings, QString profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; - createKeilProfileHelper(info, settings, profileName); + createKeilProfileHelper(info, settings, std::move(profileName)); } -void keilProbe(Settings *settings, QList<Profile> &profiles) +void keilProbe(Settings *settings, std::vector<Profile> &profiles) { qbsInfo() << Tr::tr("Trying to detect KEIL toolchains..."); diff --git a/src/app/qbs-setup-toolchains/keilprobe.h b/src/app/qbs-setup-toolchains/keilprobe.h index c7e66ee24..fec650ab0 100644 --- a/src/app/qbs-setup-toolchains/keilprobe.h +++ b/src/app/qbs-setup-toolchains/keilprobe.h @@ -56,6 +56,6 @@ bool isKeilCompiler(const QString &compilerName); void createKeilProfile(const QFileInfo &compiler, qbs::Settings *settings, QString profileName); -void keilProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles); +void keilProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles); #endif // Header guard diff --git a/src/app/qbs-setup-toolchains/main.cpp b/src/app/qbs-setup-toolchains/main.cpp index 87a2a842a..475bcf07b 100644 --- a/src/app/qbs-setup-toolchains/main.cpp +++ b/src/app/qbs-setup-toolchains/main.cpp @@ -49,7 +49,6 @@ #include <cstdlib> #include <iostream> -using qbs::Internal::Tr; using qbs::Settings; static void printUsage(const QString &usageString) diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp index c8108bfd2..bb54add9f 100644 --- a/src/app/qbs-setup-toolchains/msvcprobe.cpp +++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp @@ -50,15 +50,10 @@ #include <tools/qttools.h> #include <tools/settings.h> #include <tools/version.h> -#include <tools/visualstudioversioninfo.h> #include <tools/vsenvironmentdetector.h> #include <QtCore/qdir.h> #include <QtCore/qfileinfo.h> -#include <QtCore/qjsonarray.h> -#include <QtCore/qjsondocument.h> -#include <QtCore/qjsonobject.h> -#include <QtCore/qprocess.h> #include <QtCore/qsettings.h> #include <QtCore/qstringlist.h> @@ -87,70 +82,18 @@ static void setQtHelperProperties(Profile &p, const MSVC *msvc) p.setValue(QStringLiteral("cpp.compilerVersion"), msvc->compilerVersion.toString()); } -static void addMSVCPlatform(Settings *settings, QList<Profile> &profiles, QString name, MSVC *msvc) +static void addMSVCPlatform(Settings *settings, std::vector<Profile> &profiles, QString name, MSVC *msvc) { qbsInfo() << Tr::tr("Setting up profile '%1'.").arg(name); - Profile p(name, settings); + Profile p(std::move(name), settings); p.removeProfile(); p.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("windows")); - p.setValue(QStringLiteral("qbs.toolchain"), QStringList(QStringLiteral("msvc"))); + p.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("msvc")); p.setValue(QStringLiteral("cpp.toolchainInstallPath"), msvc->binPath); setQtHelperProperties(p, msvc); profiles.push_back(p); } -struct MSVCArchInfo -{ - QString arch; - QString binPath; -}; - -static std::vector<MSVCArchInfo> findSupportedArchitectures(const MSVC &msvc) -{ - std::vector<MSVCArchInfo> result; - auto addResult = [&result](const MSVCArchInfo &ai) { - if (QFile::exists(ai.binPath + QLatin1String("/cl.exe"))) - result.push_back(ai); - }; - if (msvc.internalVsVersion.majorVersion() < 15) { - static const QStringList knownArchitectures = QStringList() - << QStringLiteral("x86") - << QStringLiteral("amd64_x86") - << QStringLiteral("amd64") - << QStringLiteral("x86_amd64") - << QStringLiteral("ia64") - << QStringLiteral("x86_ia64") - << QStringLiteral("x86_arm") - << QStringLiteral("amd64_arm"); - for (const QString &knownArchitecture : knownArchitectures) { - MSVCArchInfo ai; - ai.arch = knownArchitecture; - ai.binPath = msvc.binPathForArchitecture(knownArchitecture); - addResult(ai); - } - } else { - QDir vcInstallDir(msvc.vcInstallPath); - const auto hostArchs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &hostArch : hostArchs) { - QDir subdir = vcInstallDir; - if (!subdir.cd(hostArch)) - continue; - const QString shortHostArch = hostArch.mid(4).toLower(); - const auto archs = subdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &arch : archs) { - MSVCArchInfo ai; - ai.binPath = subdir.absoluteFilePath(arch); - if (shortHostArch == arch) - ai.arch = arch; - else - ai.arch = shortHostArch + QLatin1Char('_') + arch; - addResult(ai); - } - } - } - return result; -} - static QString wow6432Key() { #ifdef Q_OS_WIN64 @@ -160,203 +103,7 @@ static QString wow6432Key() #endif } -static QString vswhereFilePath() -{ - static const std::vector<const char *> envVarCandidates{"ProgramFiles", "ProgramFiles(x86)"}; - for (const char * const envVar : envVarCandidates) { - const QString value = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar))); - const QString cmd = value - + QStringLiteral("/Microsoft Visual Studio/Installer/vswhere.exe"); - if (QFileInfo(cmd).exists()) - return cmd; - } - return {}; -} - -enum class ProductType { VisualStudio, BuildTools }; -static std::vector<MSVCInstallInfo> retrieveInstancesFromVSWhere(ProductType productType) -{ - std::vector<MSVCInstallInfo> result; - const QString cmd = vswhereFilePath(); - if (cmd.isEmpty()) - return result; - QProcess vsWhere; - QStringList args = productType == ProductType::VisualStudio - ? QStringList({QStringLiteral("-all"), QStringLiteral("-legacy"), - QStringLiteral("-prerelease")}) - : QStringList({QStringLiteral("-products"), - QStringLiteral("Microsoft.VisualStudio.Product.BuildTools")}); - args << QStringLiteral("-format") << QStringLiteral("json") << QStringLiteral("-utf8"); - vsWhere.start(cmd, args); - if (!vsWhere.waitForStarted(-1)) - return result; - if (!vsWhere.waitForFinished(-1)) { - qbsWarning() << Tr::tr("The vswhere tool failed to run: %1").arg(vsWhere.errorString()); - return result; - } - if (vsWhere.exitCode() != 0) { - qbsWarning() << Tr::tr("The vswhere tool failed to run: %1") - .arg(QString::fromLocal8Bit(vsWhere.readAllStandardError())); - return result; - } - QJsonParseError parseError; - QJsonDocument jsonOutput = QJsonDocument::fromJson(vsWhere.readAllStandardOutput(), - &parseError); - if (parseError.error != QJsonParseError::NoError) { - qbsWarning() << Tr::tr("The vswhere tool produced invalid JSON output: %1") - .arg(parseError.errorString()); - return result; - } - const auto jsonArray = jsonOutput.array(); - for (const QJsonValue &v : jsonArray) { - const QJsonObject o = v.toObject(); - MSVCInstallInfo info; - info.version = o.value(QStringLiteral("installationVersion")).toString(); - if (productType == ProductType::BuildTools) { - // For build tools, the version is e.g. "15.8.28010.2036", rather than "15.0". - const int dotIndex = info.version.indexOf(QLatin1Char('.')); - if (dotIndex != -1) - info.version = info.version.left(dotIndex); - } - info.installDir = o.value(QStringLiteral("installationPath")).toString(); - if (!info.version.isEmpty() && !info.installDir.isEmpty()) - result.push_back(info); - } - return result; -} - -static std::vector<MSVCInstallInfo> installedMSVCsFromVsWhere() -{ - const std::vector<MSVCInstallInfo> vsInstallations - = retrieveInstancesFromVSWhere(ProductType::VisualStudio); - const std::vector<MSVCInstallInfo> buildToolInstallations - = retrieveInstancesFromVSWhere(ProductType::BuildTools); - std::vector<MSVCInstallInfo> all; - std::copy(vsInstallations.begin(), vsInstallations.end(), std::back_inserter(all)); - std::copy(buildToolInstallations.begin(), buildToolInstallations.end(), - std::back_inserter(all)); - return all; -} - -static std::vector<MSVCInstallInfo> installedMSVCsFromRegistry() -{ - std::vector<MSVCInstallInfo> result; - - // Detect Visual Studio - const QSettings vsRegistry( - QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() - + QStringLiteral("\\Microsoft\\VisualStudio\\SxS\\VS7"), - QSettings::NativeFormat); - const auto vsNames = vsRegistry.childKeys(); - for (const QString &vsName : vsNames) { - MSVCInstallInfo entry; - entry.version = vsName; - entry.installDir = vsRegistry.value(vsName).toString(); - result.push_back(entry); - } - - // Detect Visual C++ Build Tools - QSettings vcbtRegistry( - QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() - + QStringLiteral("\\Microsoft\\VisualCppBuildTools"), - QSettings::NativeFormat); - const QStringList &vcbtRegistryChildGroups = vcbtRegistry.childGroups(); - for (const QString &childGroup : vcbtRegistryChildGroups) { - vcbtRegistry.beginGroup(childGroup); - bool ok; - int installed = vcbtRegistry.value(QStringLiteral("Installed")).toInt(&ok); - if (ok && installed) { - MSVCInstallInfo entry; - entry.version = childGroup; - const QSettings vsRegistry( - QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() - + QStringLiteral("\\Microsoft\\VisualStudio\\") + childGroup - + QStringLiteral("\\Setup\\VC"), - QSettings::NativeFormat); - entry.installDir = vsRegistry.value(QStringLiteral("ProductDir")).toString(); - result.push_back(entry); - } - vcbtRegistry.endGroup(); - } - - return result; -} - -QString MSVCInstallInfo::findVcvarsallBat() const -{ - static const auto vcvarsall2017 = QStringLiteral("VC/Auxiliary/Build/vcvarsall.bat"); - // 2015, 2013 and 2012 - static const auto vcvarsallOld = QStringLiteral("VC/vcvarsall.bat"); - QDir dir(installDir); - if (dir.exists(vcvarsall2017)) - return dir.absoluteFilePath(vcvarsall2017); - if (dir.exists(vcvarsallOld)) - return dir.absoluteFilePath(vcvarsallOld); - return {}; -} - -std::vector<MSVCInstallInfo> installedMSVCs() -{ - const auto installInfos = installedMSVCsFromVsWhere(); - if (installInfos.empty()) - return installedMSVCsFromRegistry(); - return installInfos; -} - -static std::vector<MSVC> installedCompilers() -{ - std::vector<MSVC> msvcs; - std::vector<MSVCInstallInfo> installInfos = installedMSVCsFromVsWhere(); - if (installInfos.empty()) - installInfos = installedMSVCsFromRegistry(); - for (const MSVCInstallInfo &installInfo : installInfos) { - MSVC msvc; - msvc.internalVsVersion = Version::fromString(installInfo.version, true); - if (!msvc.internalVsVersion.isValid()) - continue; - - QDir vsInstallDir(installInfo.installDir); - msvc.vsInstallPath = vsInstallDir.absolutePath(); - if (vsInstallDir.dirName() != QStringLiteral("VC") - && !vsInstallDir.cd(QStringLiteral("VC"))) { - continue; - } - - msvc.version = QString::number(Internal::VisualStudioVersionInfo( - msvc.internalVsVersion).marketingVersion()); - if (msvc.version.isEmpty()) { - qbsWarning() << Tr::tr("Unknown MSVC version %1 found.").arg(installInfo.version); - continue; - } - - if (msvc.internalVsVersion.majorVersion() < 15) { - QDir vcInstallDir = vsInstallDir; - if (!vcInstallDir.cd(QStringLiteral("bin"))) - continue; - msvc.vcInstallPath = vcInstallDir.absolutePath(); - msvcs.push_back(msvc); - } else { - QDir vcInstallDir = vsInstallDir; - vcInstallDir.cd(QStringLiteral("Tools/MSVC")); - const auto vcVersionStrs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &vcVersionStr : vcVersionStrs) { - const Version vcVersion = Version::fromString(vcVersionStr); - if (!vcVersion.isValid()) - continue; - QDir specificVcInstallDir = vcInstallDir; - if (!specificVcInstallDir.cd(vcVersionStr) - || !specificVcInstallDir.cd(QStringLiteral("bin"))) { - continue; - } - msvc.vcInstallPath = specificVcInstallDir.absolutePath(); - msvcs.push_back(msvc); - } - } - } - return msvcs; -} - -void msvcProbe(Settings *settings, QList<Profile> &profiles) +void msvcProbe(Settings *settings, std::vector<Profile> &profiles) { qbsInfo() << Tr::tr("Detecting MSVC toolchains..."); @@ -381,7 +128,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles) sdk.vcInstallPath.chop(1); if (sdk.isDefault) defaultWinSDK = sdk; - const auto ais = findSupportedArchitectures(sdk); + const auto ais = MSVC::findSupportedArchitectures(sdk); for (const MSVCArchInfo &ai : ais) { WinSDK specificSDK = sdk; specificSDK.architecture = ai.arch; @@ -399,24 +146,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles) } // 2) Installed MSVCs - std::vector<MSVC> msvcs; - const auto instMsvcs = installedCompilers(); - for (const MSVC &msvc : instMsvcs) { - if (msvc.internalVsVersion.majorVersion() < 15) { - // Check existence of various install scripts - const QString vcvars32bat = msvc.vcInstallPath + QLatin1String("/vcvars32.bat"); - if (!QFileInfo(vcvars32bat).isFile()) - continue; - } - - const auto ais = findSupportedArchitectures(msvc); - for (const MSVCArchInfo &ai : ais) { - MSVC specificMSVC = msvc; - specificMSVC.architecture = ai.arch; - specificMSVC.binPath = ai.binPath; - msvcs.push_back(specificMSVC); - } - } + std::vector<MSVC> msvcs = MSVC::installedCompilers(ConsoleLogger::instance()); for (const MSVC &msvc : qAsConst(msvcs)) { qbsInfo() << Tr::tr(" MSVC %1 (%2) detected in\n" @@ -470,7 +200,7 @@ void createMsvcProfile(const QFileInfo &compiler, Settings *settings, const auto compilerFilePath = compiler.absoluteFilePath(); MSVC msvc(compilerFilePath, MSVC::architectureFromClPath(compilerFilePath)); msvc.init(); - QList<Profile> dummy; + std::vector<Profile> dummy; addMSVCPlatform(settings, dummy, profileName, &msvc); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profileName, QDir::toNativeSeparators(compilerFilePath)); diff --git a/src/app/qbs-setup-toolchains/msvcprobe.h b/src/app/qbs-setup-toolchains/msvcprobe.h index f63dd5dc8..981bbc561 100644 --- a/src/app/qbs-setup-toolchains/msvcprobe.h +++ b/src/app/qbs-setup-toolchains/msvcprobe.h @@ -53,19 +53,9 @@ class Profile; class Settings; } -struct MSVCInstallInfo -{ - QString version; - QString installDir; - - QString findVcvarsallBat() const; -}; - -std::vector<MSVCInstallInfo> installedMSVCs(); - void createMsvcProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName); -void msvcProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles); +void msvcProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles); #endif // Header guard diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp index 205306acd..add7ba05c 100644 --- a/src/app/qbs-setup-toolchains/probe.cpp +++ b/src/app/qbs-setup-toolchains/probe.cpp @@ -50,6 +50,7 @@ #include <tools/error.h> #include <tools/hostosinfo.h> #include <tools/profile.h> +#include <tools/qttools.h> #include <tools/settings.h> #include <tools/toolchains.h> @@ -96,32 +97,32 @@ QString findExecutable(const QString &fileName) return {}; } -QStringList toolchainTypeFromCompilerName(const QString &compilerName) +QString toolchainTypeFromCompilerName(const QString &compilerName) { if (compilerName == QLatin1String("cl.exe")) - return canonicalToolchain(QStringLiteral("msvc")); + return QStringLiteral("msvc"); if (compilerName == QLatin1String("clang-cl.exe")) - return canonicalToolchain(QLatin1String("clang-cl")); + return QStringLiteral("clang-cl"); const auto types = { QStringLiteral("clang"), QStringLiteral("llvm"), QStringLiteral("mingw"), QStringLiteral("gcc") }; for (const auto &type : types) { if (compilerName.contains(type)) - return canonicalToolchain(type); + return type; } if (compilerName == QLatin1String("g++")) - return canonicalToolchain(QStringLiteral("gcc")); + return QStringLiteral("gcc"); if (isIarCompiler(compilerName)) - return canonicalToolchain(QStringLiteral("iar")); + return QStringLiteral("iar"); if (isKeilCompiler(compilerName)) - return canonicalToolchain(QStringLiteral("keil")); + return QStringLiteral("keil"); if (isSdccCompiler(compilerName)) - return canonicalToolchain(QStringLiteral("sdcc")); + return QStringLiteral("sdcc"); return {}; } void probe(Settings *settings) { - QList<Profile> profiles; + std::vector<Profile> profiles; if (HostOsInfo::isWindowsHost()) { msvcProbe(settings, profiles); clangClProbe(settings, profiles); @@ -137,10 +138,10 @@ void probe(Settings *settings) sdccProbe(settings, profiles); if (profiles.empty()) { - qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl; + qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << Qt::endl; } else if (profiles.size() == 1 && settings->defaultProfile().isEmpty()) { const QString profileName = profiles.front().name(); - qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << endl; + qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << Qt::endl; settings->setValue(QStringLiteral("defaultProfile"), profileName); } } @@ -157,23 +158,22 @@ void createProfile(const QString &profileName, const QString &toolchainType, .arg(compilerFilePath)); } - QStringList toolchainTypes; - if (toolchainType.isEmpty()) - toolchainTypes = toolchainTypeFromCompilerName(compiler.fileName()); - else - toolchainTypes = canonicalToolchain(toolchainType); + const QString realToolchainType = !toolchainType.isEmpty() + ? toolchainType + : toolchainTypeFromCompilerName(compiler.fileName()); + const QStringList toolchain = canonicalToolchain(realToolchainType); - if (toolchainTypes.contains(QLatin1String("msvc"))) + if (toolchain.contains(QLatin1String("msvc"))) createMsvcProfile(compiler, settings, profileName); - else if (toolchainTypes.contains(QLatin1String("clang-cl"))) + else if (toolchain.contains(QLatin1String("clang-cl"))) createClangClProfile(compiler, settings, profileName); - else if (toolchainTypes.contains(QLatin1String("gcc"))) - createGccProfile(compiler, settings, toolchainTypes, profileName); - else if (toolchainTypes.contains(QLatin1String("iar"))) + else if (toolchain.contains(QLatin1String("gcc"))) + createGccProfile(compiler, settings, realToolchainType, profileName); + else if (toolchain.contains(QLatin1String("iar"))) createIarProfile(compiler, settings, profileName); - else if (toolchainTypes.contains(QLatin1String("keil"))) + else if (toolchain.contains(QLatin1String("keil"))) createKeilProfile(compiler, settings, profileName); - else if (toolchainTypes.contains(QLatin1String("sdcc"))) + else if (toolchain.contains(QLatin1String("sdcc"))) createSdccProfile(compiler, settings, profileName); else throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type.")); diff --git a/src/app/qbs-setup-toolchains/probe.h b/src/app/qbs-setup-toolchains/probe.h index 235d7a899..bce150bd7 100644 --- a/src/app/qbs-setup-toolchains/probe.h +++ b/src/app/qbs-setup-toolchains/probe.h @@ -57,7 +57,7 @@ QStringList systemSearchPaths(); QString findExecutable(const QString &fileName); -QStringList toolchainTypeFromCompilerName(const QString &compilerName); +QString toolchainTypeFromCompilerName(const QString &compilerName); void createProfile(const QString &profileName, const QString &toolchainType, const QString &compilerFilePath, qbs::Settings *settings); diff --git a/src/app/qbs-setup-toolchains/sdccprobe.cpp b/src/app/qbs-setup-toolchains/sdccprobe.cpp index eccd3ccae..977d834c4 100644 --- a/src/app/qbs-setup-toolchains/sdccprobe.cpp +++ b/src/app/qbs-setup-toolchains/sdccprobe.cpp @@ -116,8 +116,8 @@ static std::vector<Profile> createSdccProfileHelper( if (actualArch != QString::fromLatin1(knownArch)) continue; - QString fullProfileName = profileName; - if (fullProfileName.isEmpty()) { + QString fullProfileName; + if (profileName.isEmpty()) { // Create a full profile name in case we is // in auto-detecting mode. if (!info.compilerVersion.isValid()) { @@ -133,7 +133,7 @@ static std::vector<Profile> createSdccProfileHelper( // Append the detected actual architecture name // to the proposed profile name. fullProfileName = QStringLiteral("%1-%2").arg( - fullProfileName, actualArch); + profileName, actualArch); } Profile profile(fullProfileName, settings); @@ -151,6 +151,21 @@ static std::vector<Profile> createSdccProfileHelper( return profiles; } +static Version dumpOldSddcCompilerVersion(const QByteArray ¯oDump) +{ + const auto keyToken = QByteArrayLiteral("__SDCC "); + const int startIndex = macroDump.indexOf(keyToken); + if (startIndex == -1) + return Version{}; + const int endIndex = macroDump.indexOf('\n', startIndex); + if (endIndex == -1) + return Version{}; + const auto keyLength = keyToken.length(); + return Version::fromString(QString::fromLatin1( + macroDump.mid(startIndex + keyLength, + endIndex - startIndex - keyLength).replace('_', '.'))); +} + static Version dumpSdccCompilerVersion(const QFileInfo &compiler) { const QByteArray dump = dumpSdccMacros(compiler); @@ -161,10 +176,14 @@ static Version dumpSdccCompilerVersion(const QFileInfo &compiler) const int minor = extractVersion(dump, "__SDCC_VERSION_MINOR "); const int patch = extractVersion(dump, "__SDCC_VERSION_PATCH "); if (major < 0 || minor < 0 || patch < 0) { - qbsWarning() << Tr::tr("No '__SDCC_VERSION_xxx' token was found " - "in the compiler dump:\n%1") - .arg(QString::fromUtf8(dump)); - return Version{}; + const auto version = dumpOldSddcCompilerVersion(dump); + if (!version.isValid()) { + qbsWarning() << Tr::tr("No '__SDCC_VERSION_xxx' or '__SDCC' token was found " + "in the compiler dump:\n%1") + .arg(QString::fromUtf8(dump)); + return Version{}; + } + return version; } return Version{major, minor, patch}; @@ -252,13 +271,13 @@ bool isSdccCompiler(const QString &compilerName) } void createSdccProfile(const QFileInfo &compiler, Settings *settings, - QString profileName) + const QString &profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createSdccProfileHelper(info, settings, profileName); } -void sdccProbe(Settings *settings, QList<Profile> &profiles) +void sdccProbe(Settings *settings, std::vector<Profile> &profiles) { qbsInfo() << Tr::tr("Trying to detect SDCC toolchains..."); diff --git a/src/app/qbs-setup-toolchains/sdccprobe.h b/src/app/qbs-setup-toolchains/sdccprobe.h index aa2c613f3..4c913ddeb 100644 --- a/src/app/qbs-setup-toolchains/sdccprobe.h +++ b/src/app/qbs-setup-toolchains/sdccprobe.h @@ -68,8 +68,8 @@ inline bool operator==(const SdccInstallInfo &lhs, const SdccInstallInfo &rhs) bool isSdccCompiler(const QString &compilerName); void createSdccProfile(const QFileInfo &compiler, qbs::Settings *settings, - QString profileName); + const QString &profileName); -void sdccProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles); +void sdccProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles); #endif // Header guard diff --git a/src/app/qbs-setup-toolchains/xcodeprobe.cpp b/src/app/qbs-setup-toolchains/xcodeprobe.cpp index a0f6f80d1..97b043f92 100644 --- a/src/app/qbs-setup-toolchains/xcodeprobe.cpp +++ b/src/app/qbs-setup-toolchains/xcodeprobe.cpp @@ -110,7 +110,7 @@ namespace { class XcodeProbe { public: - XcodeProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles) + XcodeProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles) : settings(settings), profiles(profiles) { } @@ -120,7 +120,7 @@ public: void detectAll(); private: qbs::Settings *settings; - QList<qbs::Profile> &profiles; + std::vector<qbs::Profile> &profiles; QStringList developerPaths; }; @@ -172,11 +172,7 @@ void XcodeProbe::setupDefaultToolchains(const QString &devPath, const QString &x Profile installationProfile(xcodeName, settings); installationProfile.removeProfile(); - installationProfile.setValue(QStringLiteral("qbs.toolchain"), QStringList() - << QStringLiteral("xcode") - << QStringLiteral("clang") - << QStringLiteral("llvm") - << QStringLiteral("gcc")); + installationProfile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("xcode")); if (devPath != defaultDeveloperPath) installationProfile.setValue(QStringLiteral("xcode.developerPath"), devPath); profiles.push_back(installationProfile); @@ -229,7 +225,7 @@ void XcodeProbe::detectAll() } } // end anonymous namespace -void xcodeProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles) +void xcodeProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles) { XcodeProbe probe(settings, profiles); probe.detectAll(); diff --git a/src/app/qbs-setup-toolchains/xcodeprobe.h b/src/app/qbs-setup-toolchains/xcodeprobe.h index ab501036b..fc15d177e 100644 --- a/src/app/qbs-setup-toolchains/xcodeprobe.h +++ b/src/app/qbs-setup-toolchains/xcodeprobe.h @@ -47,6 +47,6 @@ class Profile; class Settings; } -void xcodeProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles); +void xcodeProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles); #endif // Header guard |