aboutsummaryrefslogtreecommitdiffstats
path: root/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/app')
-rw-r--r--src/app/config-ui/main.cpp2
-rw-r--r--src/app/config-ui/mainwindow.cpp4
-rw-r--r--src/app/config/configcommandexecutor.cpp5
-rw-r--r--src/app/config/configcommandlineparser.h2
-rw-r--r--src/app/qbs-setup-android/android-setup.cpp37
-rw-r--r--src/app/qbs-setup-android/commandlineparser.cpp5
-rw-r--r--src/app/qbs-setup-qt/setupqt.cpp12
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.cpp108
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.h6
-rw-r--r--src/app/qbs-setup-toolchains/gccprobe.cpp32
-rw-r--r--src/app/qbs-setup-toolchains/gccprobe.h4
-rw-r--r--src/app/qbs-setup-toolchains/iarewprobe.cpp29
-rw-r--r--src/app/qbs-setup-toolchains/iarewprobe.h2
-rw-r--r--src/app/qbs-setup-toolchains/keilprobe.cpp337
-rw-r--r--src/app/qbs-setup-toolchains/keilprobe.h2
-rw-r--r--src/app/qbs-setup-toolchains/main.cpp1
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp284
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.h12
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp46
-rw-r--r--src/app/qbs-setup-toolchains/probe.h2
-rw-r--r--src/app/qbs-setup-toolchains/sdccprobe.cpp37
-rw-r--r--src/app/qbs-setup-toolchains/sdccprobe.h4
-rw-r--r--src/app/qbs-setup-toolchains/xcodeprobe.cpp12
-rw-r--r--src/app/qbs-setup-toolchains/xcodeprobe.h2
-rw-r--r--src/app/qbs/commandlinefrontend.cpp3
-rw-r--r--src/app/qbs/parser/commandlineoption.cpp12
-rw-r--r--src/app/qbs/parser/parsercommand.cpp4
-rw-r--r--src/app/qbs/session.cpp11
-rw-r--r--src/app/qbs/sessionpacket.cpp4
-rw-r--r--src/app/qbs/sessionpacketreader.cpp10
-rw-r--r--src/app/qbs/sessionpacketreader.h6
-rw-r--r--src/app/qbs/stdinreader.cpp32
32 files changed, 468 insertions, 601 deletions
diff --git a/src/app/config-ui/main.cpp b/src/app/config-ui/main.cpp
index a7c2662e6..dcf538989 100644
--- a/src/app/config-ui/main.cpp
+++ b/src/app/config-ui/main.cpp
@@ -47,8 +47,6 @@
#include <cstdlib>
#include <iostream>
-using qbs::Internal::Tr;
-
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
diff --git a/src/app/config-ui/mainwindow.cpp b/src/app/config-ui/mainwindow.cpp
index 2bf7fad5e..febf170a2 100644
--- a/src/app/config-ui/mainwindow.cpp
+++ b/src/app/config-ui/mainwindow.cpp
@@ -119,10 +119,10 @@ MainWindow::MainWindow(const QString &settingsDir, qbs::Settings::Scope scope, Q
saveAction->setShortcut(QKeySequence::Save);
connect(saveAction, &QAction::triggered, this, &MainWindow::saveSettings);
const auto expandAllAction = new QAction(tr("&Expand All"), this);
- expandAllAction->setShortcut(Qt::CTRL | Qt::Key_E);
+ expandAllAction->setShortcut(int(Qt::CTRL) | int(Qt::Key_E));
connect(expandAllAction, &QAction::triggered, this, &MainWindow::expandAll);
const auto collapseAllAction = new QAction(tr("C&ollapse All"), this);
- collapseAllAction->setShortcut(Qt::CTRL | Qt::Key_O);
+ collapseAllAction->setShortcut(int(Qt::CTRL) | int(Qt::Key_O));
connect(collapseAllAction, &QAction::triggered, this, &MainWindow::collapseAll);
const auto exitAction = new QAction(tr("E&xit"), this);
exitAction->setShortcut(QKeySequence::Quit);
diff --git a/src/app/config/configcommandexecutor.cpp b/src/app/config/configcommandexecutor.cpp
index 1290ba2f0..f2d9fc59e 100644
--- a/src/app/config/configcommandexecutor.cpp
+++ b/src/app/config/configcommandexecutor.cpp
@@ -41,8 +41,9 @@
#include "configcommand.h"
#include "../shared/logging/consolelogger.h"
-#include <tools/settingsrepresentation.h>
#include <tools/error.h>
+#include <tools/qttools.h>
+#include <tools/settingsrepresentation.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
@@ -131,7 +132,7 @@ void ConfigCommandExecutor::exportSettings(const QString &filename)
const auto keys = m_settings->allKeys(m_scope);
for (const QString &key : keys)
stream << key << ": " << qbs::settingsValueToRepresentation(m_settings->value(key, m_scope))
- << endl;
+ << Qt::endl;
}
void ConfigCommandExecutor::importSettings(const QString &filename)
diff --git a/src/app/config/configcommandlineparser.h b/src/app/config/configcommandlineparser.h
index b567134fd..f1f026678 100644
--- a/src/app/config/configcommandlineparser.h
+++ b/src/app/config/configcommandlineparser.h
@@ -60,7 +60,7 @@ public:
class Error
{
public:
- Error(const QString &message) : m_message(message) { }
+ Error(QString message) : m_message(std::move(message)) { }
QString message() const { return m_message; }
private:
QString m_message;
diff --git a/src/app/qbs-setup-android/android-setup.cpp b/src/app/qbs-setup-android/android-setup.cpp
index 029628419..a0a9d2948 100644
--- a/src/app/qbs-setup-android/android-setup.cpp
+++ b/src/app/qbs-setup-android/android-setup.cpp
@@ -45,6 +45,7 @@
#include <tools/profile.h>
#include <tools/settings.h>
#include <tools/version.h>
+#include <tools/qttools.h>
#include <QtCore/qbytearraylist.h>
#include <QtCore/qcoreapplication.h>
@@ -94,10 +95,10 @@ static QString mapArch(const QString &androidName)
}
struct QtAndroidInfo {
- bool isValid() const { return !arch.isEmpty(); }
+ bool isValid() const { return !archs.isEmpty(); }
QString qmakePath;
- QString arch;
+ QStringList archs;
QString platform;
};
@@ -111,19 +112,30 @@ static QtAndroidInfo getInfoForQtDir(const QString &qtDir)
if (!qdevicepri.open(QIODevice::ReadOnly))
return info;
while (!qdevicepri.atEnd()) {
+ // For Qt < 5.14 use DEFAULT_ANDROID_TARGET_ARCH (which is the abi) to compute
+ // the architecture
+ // DEFAULT_ANDROID_ABIS doesn't exit
+ // For Qt >= 5.14:
+ // DEFAULT_ANDROID_TARGET_ARCH doesn't exist, use DEFAULT_ANDROID_ABIS to compute
+ // the architectures
const QByteArray line = qdevicepri.readLine().simplified();
const bool isArchLine = line.startsWith("DEFAULT_ANDROID_TARGET_ARCH");
+ const bool isAbisLine = line.startsWith("DEFAULT_ANDROID_ABIS");
const bool isPlatformLine = line.startsWith("DEFAULT_ANDROID_PLATFORM");
- if (!isArchLine && !isPlatformLine)
+ if (!isArchLine && !isPlatformLine && !isAbisLine)
continue;
const QList<QByteArray> elems = line.split('=');
if (elems.size() != 2)
continue;
const QString rhs = QString::fromLatin1(elems.at(1).trimmed());
- if (isArchLine)
- info.arch = mapArch(rhs);
- else
+ if (isArchLine) {
+ info.archs << mapArch(rhs);
+ } else if (isAbisLine) {
+ for (const QString &abi: rhs.split(QLatin1Char(' ')))
+ info.archs << mapArch(abi);
+ } else {
info.platform = rhs;
+ }
}
return info;
}
@@ -136,13 +148,16 @@ static QtInfoPerArch getQtAndroidInfo(const QString &qtSdkDir)
return archs;
QStringList qtDirs(qtSdkDir);
- QDirIterator dit(qtSdkDir, QStringList() << QStringLiteral("android_*"), QDir::Dirs);
+ const QStringList nameFilters{QStringLiteral("android_*"), QStringLiteral("android")};
+ QDirIterator dit(qtSdkDir, nameFilters, QDir::Dirs);
while (dit.hasNext())
qtDirs << dit.next();
for (const auto &qtDir : qtDirs) {
const QtAndroidInfo info = getInfoForQtDir(qtDir);
- if (info.isValid())
- archs.insert(info.arch, info);
+ if (info.isValid()) {
+ for (const QString &arch: info.archs)
+ archs.insert(arch, info);
+ }
}
return archs;
}
@@ -224,8 +239,10 @@ static void setupNdk(qbs::Settings *settings, const QString &profileName, const
qmakeFilePaths << qtAndroidInfo.qmakePath;
platform = maximumPlatform(platform, qtAndroidInfo.platform);
}
- if (!qmakeFilePaths.empty())
+ if (!qmakeFilePaths.empty()) {
+ qmakeFilePaths.removeDuplicates();
mainProfile.setValue(qls("moduleProviders.Qt.qmakeFilePaths"), qmakeFilePaths);
+ }
if (!platform.isEmpty())
mainProfile.setValue(qls("Android.ndk.platform"), platform);
}
diff --git a/src/app/qbs-setup-android/commandlineparser.cpp b/src/app/qbs-setup-android/commandlineparser.cpp
index 0aecc8773..8beeeb601 100644
--- a/src/app/qbs-setup-android/commandlineparser.cpp
+++ b/src/app/qbs-setup-android/commandlineparser.cpp
@@ -43,10 +43,7 @@
#include <QtCore/qfileinfo.h>
-CommandLineParser::CommandLineParser()
-{
-
-}
+CommandLineParser::CommandLineParser() = default;
using qbs::Internal::Tr;
diff --git a/src/app/qbs-setup-qt/setupqt.cpp b/src/app/qbs-setup-qt/setupqt.cpp
index 947cbc5fc..07e1a81b5 100644
--- a/src/app/qbs-setup-qt/setupqt.cpp
+++ b/src/app/qbs-setup-qt/setupqt.cpp
@@ -47,6 +47,7 @@
#include <tools/set.h>
#include <tools/settings.h>
#include <tools/stlutils.h>
+#include <tools/toolchains.h>
#include <tools/version.h>
#include <QtCore/qbytearraymatcher.h>
@@ -196,7 +197,7 @@ static bool isToolchainProfile(const Profile &profile)
{
const auto actual = Internal::Set<QString>::fromList(
profile.allKeys(Profile::KeySelectionRecursive));
- Internal::Set<QString> expected = Internal::Set<QString> { QStringLiteral("qbs.toolchain") };
+ Internal::Set<QString> expected{ QStringLiteral("qbs.toolchainType") };
if (HostOsInfo::isMacosHost())
expected.insert(QStringLiteral("qbs.targetPlatform")); // match only Xcode profiles
return Internal::Set<QString>(actual).unite(expected) == actual;
@@ -230,8 +231,13 @@ static Match compatibility(const QtEnvironment &env, const Profile &toolchainPro
{
Match match = MatchFull;
- const auto toolchainNames = Internal::Set<QString>::fromList(
- toolchainProfile.value(QStringLiteral("qbs.toolchain")).toStringList());
+ const auto toolchainType =
+ toolchainProfile.value(QStringLiteral("qbs.toolchainType")).toString();
+ const auto toolchain = !toolchainType.isEmpty()
+ ? canonicalToolchain(toolchainType)
+ : toolchainProfile.value(QStringLiteral("qbs.toolchain")).toStringList();
+
+ const auto toolchainNames = Internal::Set<QString>::fromList(toolchain);
const auto qtToolchainNames = Internal::Set<QString>::fromList(env.qbsToolchain);
if (areProfilePropertiesIncompatible(toolchainNames, qtToolchainNames)) {
auto intersection = toolchainNames;
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 &section)
+{
+ 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 &macroDump)
+{
+ 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
diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp
index 8be06f3af..d8b4d9ca8 100644
--- a/src/app/qbs/commandlinefrontend.cpp
+++ b/src/app/qbs/commandlinefrontend.cpp
@@ -78,6 +78,7 @@ CommandLineFrontend::CommandLineFrontend(const CommandLineParser &parser, Settin
CommandLineFrontend::~CommandLineFrontend()
{
m_cancelTimer->stop();
+ delete m_observer;
}
// Called from interrupt handler. Don't do anything non-trivial here.
@@ -653,7 +654,7 @@ ProductData CommandLineFrontend::getTheOneRunnableProduct()
}
QBS_CHECK(false);
}
- QBS_CHECK(m_parser.products().size() == 0);
+ QBS_CHECK(m_parser.products().isEmpty());
QList<ProductData> runnableProducts;
const auto products = m_projects.front().projectData().allProducts();
diff --git a/src/app/qbs/parser/commandlineoption.cpp b/src/app/qbs/parser/commandlineoption.cpp
index 0c13662f0..a09f36c2c 100644
--- a/src/app/qbs/parser/commandlineoption.cpp
+++ b/src/app/qbs/parser/commandlineoption.cpp
@@ -47,9 +47,7 @@
namespace qbs {
using namespace Internal;
-CommandLineOption::~CommandLineOption()
-{
-}
+CommandLineOption::~CommandLineOption() = default;
void CommandLineOption::parse(CommandType command, const QString &representation, QStringList &input)
{
@@ -546,9 +544,7 @@ QString LogTimeOption::longRepresentation() const
}
-SettingsDirOption::SettingsDirOption()
-{
-}
+SettingsDirOption::SettingsDirOption() = default;
QString SettingsDirOption::description(CommandType command) const
{
@@ -627,9 +623,7 @@ QString RespectProjectJobLimitsOption::longRepresentation() const
return QStringLiteral("--enforce-project-job-limits");
}
-CommandEchoModeOption::CommandEchoModeOption()
-{
-}
+CommandEchoModeOption::CommandEchoModeOption() = default;
QString CommandEchoModeOption::description(CommandType command) const
{
diff --git a/src/app/qbs/parser/parsercommand.cpp b/src/app/qbs/parser/parsercommand.cpp
index c7185a725..799bf5dcf 100644
--- a/src/app/qbs/parser/parsercommand.cpp
+++ b/src/app/qbs/parser/parsercommand.cpp
@@ -53,9 +53,7 @@
namespace qbs {
using namespace Internal;
-Command::~Command()
-{
-}
+Command::~Command() = default;
void Command::parse(QStringList &input)
{
diff --git a/src/app/qbs/session.cpp b/src/app/qbs/session.cpp
index 30e71dfd5..75f0e3bc9 100644
--- a/src/app/qbs/session.cpp
+++ b/src/app/qbs/session.cpp
@@ -148,7 +148,7 @@ private:
struct ProductSelection {
ProductSelection(Project::ProductSelection s) : selection(s) {}
- ProductSelection(const QList<ProductData> &p) : products(p) {}
+ ProductSelection(QList<ProductData> p) : products(std::move(p)) {}
Project::ProductSelection selection = Project::ProductSelectionDefaultOnly;
QList<ProductData> products;
@@ -186,7 +186,10 @@ Session::Session()
#ifdef Q_OS_WIN32
// Make sure the line feed character appears as itself.
if (_setmode(_fileno(stdout), _O_BINARY) == -1) {
- std::cerr << "Failed to set stdout to binary mode: " << std::strerror(errno) << std::endl;
+ constexpr size_t errmsglen = FILENAME_MAX;
+ char errmsg[errmsglen];
+ strerror_s(errmsg, errmsglen, errno);
+ std::cerr << "Failed to set stdout to binary mode: " << errmsg << std::endl;
qApp->exit(EXIT_FAILURE);
}
#endif
@@ -248,7 +251,7 @@ void Session::setupProject(const QJsonObject &request)
if (m_currentJob) {
if (qobject_cast<SetupProjectJob *>(m_currentJob)
&& m_currentJob->state() == AbstractJob::StateCanceling) {
- m_resolveRequest = std::move(request);
+ m_resolveRequest = request;
return;
}
sendErrorReply("project-resolved",
@@ -258,7 +261,7 @@ void Session::setupProject(const QJsonObject &request)
m_moduleProperties = modulePropertiesFromRequest(request);
auto params = SetupProjectParameters::fromJson(request);
const ProjectDataMode dataMode = dataModeFromRequest(request);
- m_settings.reset(new Settings(params.settingsDirectory()));
+ m_settings = std::make_unique<Settings>(params.settingsDirectory());
const Preferences prefs(m_settings.get());
const QString appDir = QDir::cleanPath(QCoreApplication::applicationDirPath());
params.setSearchPaths(prefs.searchPaths(appDir + QLatin1String(
diff --git a/src/app/qbs/sessionpacket.cpp b/src/app/qbs/sessionpacket.cpp
index ce9fdaf76..dd6d1726e 100644
--- a/src/app/qbs/sessionpacket.cpp
+++ b/src/app/qbs/sessionpacket.cpp
@@ -99,8 +99,8 @@ QJsonObject SessionPacket::helloMessage()
{
return QJsonObject{
{StringConstants::type(), QLatin1String("hello")},
- {QLatin1String("api-level"), 1},
- {QLatin1String("api-compat-level"), 1}
+ {QLatin1String("api-level"), 2},
+ {QLatin1String("api-compat-level"), 2}
};
}
diff --git a/src/app/qbs/sessionpacketreader.cpp b/src/app/qbs/sessionpacketreader.cpp
index fe4b73f69..e99ea01ed 100644
--- a/src/app/qbs/sessionpacketreader.cpp
+++ b/src/app/qbs/sessionpacketreader.cpp
@@ -52,12 +52,12 @@ public:
SessionPacket currentPacket;
};
-SessionPacketReader::SessionPacketReader(QObject *parent) : QObject(parent), d(new Private) { }
+SessionPacketReader::SessionPacketReader(QObject *parent)
+ : QObject(parent)
+ , d(std::make_unique<Private>())
+{ }
-SessionPacketReader::~SessionPacketReader()
-{
- delete d;
-}
+SessionPacketReader::~SessionPacketReader() = default;
void SessionPacketReader::start()
{
diff --git a/src/app/qbs/sessionpacketreader.h b/src/app/qbs/sessionpacketreader.h
index 87d70cf39..f186fbc8c 100644
--- a/src/app/qbs/sessionpacketreader.h
+++ b/src/app/qbs/sessionpacketreader.h
@@ -43,6 +43,8 @@
#include <QtCore/qjsonobject.h>
#include <QtCore/qobject.h>
+#include <memory>
+
namespace qbs {
namespace Internal {
@@ -51,7 +53,7 @@ class SessionPacketReader : public QObject
Q_OBJECT
public:
explicit SessionPacketReader(QObject *parent = nullptr);
- ~SessionPacketReader();
+ ~SessionPacketReader() override;
void start();
@@ -61,7 +63,7 @@ signals:
private:
class Private;
- Private * const d;
+ const std::unique_ptr<Private> d;
};
} // namespace Internal
diff --git a/src/app/qbs/stdinreader.cpp b/src/app/qbs/stdinreader.cpp
index 4f784505d..5f00d7de4 100644
--- a/src/app/qbs/stdinreader.cpp
+++ b/src/app/qbs/stdinreader.cpp
@@ -43,13 +43,13 @@
#include <QtCore/qfile.h>
#include <QtCore/qsocketnotifier.h>
+#include <QtCore/qtimer.h>
#include <cerrno>
#include <cstring>
#ifdef Q_OS_WIN32
#include <qt_windows.h>
-#include <QtCore/qtimer.h>
#else
#include <fcntl.h>
#endif
@@ -69,11 +69,11 @@ private:
emit errorOccurred(tr("Cannot read from standard input."));
return;
}
+#ifdef Q_OS_UNIX
const auto emitError = [this] {
emit errorOccurred(tr("Failed to make standard input non-blocking: %1")
.arg(QLatin1String(std::strerror(errno))));
};
-#ifdef Q_OS_UNIX
const int flags = fcntl(0, F_GETFL, 0);
if (flags == -1) {
emitError();
@@ -87,6 +87,18 @@ private:
connect(&m_notifier, &QSocketNotifier::activated, this, [this] {
emit dataAvailable(m_stdIn.readAll());
});
+
+ // Neither the aboutToClose() nor the readChannelFinished() signals
+ // are triggering, so we need a timer to check whether the controlling
+ // process disappeared.
+ const auto stdinClosedChecker = new QTimer(this);
+ connect(stdinClosedChecker, &QTimer::timeout, this, [this, stdinClosedChecker] {
+ if (m_stdIn.atEnd()) {
+ stdinClosedChecker->stop();
+ emit errorOccurred(tr("Input channel closed unexpectedly."));
+ }
+ });
+ stdinClosedChecker->start(1000);
}
QFile m_stdIn;
@@ -112,14 +124,22 @@ private:
// (how would we abort that one?), but ideally we'd like
// to have a signal-based approach like in the Unix variant.
const auto timer = new QTimer(this);
- connect(timer, &QTimer::timeout, this, [this] {
+ connect(timer, &QTimer::timeout, this, [this, timer] {
char buf[1024];
DWORD bytesAvail;
- PeekNamedPipe(m_stdinHandle, nullptr, 0, nullptr, &bytesAvail, nullptr);
+ if (!PeekNamedPipe(m_stdinHandle, nullptr, 0, nullptr, &bytesAvail, nullptr)) {
+ timer->stop();
+ emit errorOccurred(tr("Failed to read from input channel."));
+ return;
+ }
while (bytesAvail > 0) {
DWORD bytesRead;
- ReadFile(m_stdinHandle, buf, std::min<DWORD>(bytesAvail, sizeof buf), &bytesRead,
- nullptr);
+ if (!ReadFile(m_stdinHandle, buf, std::min<DWORD>(bytesAvail, sizeof buf),
+ &bytesRead, nullptr)) {
+ timer->stop();
+ emit errorOccurred(tr("Failed to read from input channel."));
+ return;
+ }
emit dataAvailable(QByteArray(buf, bytesRead));
bytesAvail -= bytesRead;
}