diff options
Diffstat (limited to 'src')
247 files changed, 2336 insertions, 2228 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 §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 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; } diff --git a/src/lib/corelib/api/changeset.cpp b/src/lib/corelib/api/changeset.cpp index 5d375fd65..773af328d 100644 --- a/src/lib/corelib/api/changeset.cpp +++ b/src/lib/corelib/api/changeset.cpp @@ -48,8 +48,8 @@ ChangeSet::ChangeSet() { } -ChangeSet::ChangeSet(const QList<EditOp> &operations) - : m_string(nullptr), m_cursor(nullptr), m_operationList(operations), m_error(false) +ChangeSet::ChangeSet(QList<EditOp> operations) + : m_string(nullptr), m_cursor(nullptr), m_operationList(std::move(operations)), m_error(false) { } @@ -393,5 +393,5 @@ void ChangeSet::apply_helper() m_cursor->endEditBlock(); } -} // namespace Internal { +} // namespace QbsQmlJS diff --git a/src/lib/corelib/api/changeset.h b/src/lib/corelib/api/changeset.h index 13d3908d4..23248c48e 100644 --- a/src/lib/corelib/api/changeset.h +++ b/src/lib/corelib/api/changeset.h @@ -86,7 +86,7 @@ public: public: ChangeSet(); - ChangeSet(const QList<EditOp> &operations); + ChangeSet(QList<EditOp> operations); bool empty() const; diff --git a/src/lib/corelib/api/internaljobs.cpp b/src/lib/corelib/api/internaljobs.cpp index c74c3d8a4..c53cf3e33 100644 --- a/src/lib/corelib/api/internaljobs.cpp +++ b/src/lib/corelib/api/internaljobs.cpp @@ -225,9 +225,7 @@ InternalSetupProjectJob::InternalSetupProjectJob(const Logger &logger) { } -InternalSetupProjectJob::~InternalSetupProjectJob() -{ -} +InternalSetupProjectJob::~InternalSetupProjectJob() = default; void InternalSetupProjectJob::init(const TopLevelProjectPtr &existingProject, const SetupProjectParameters ¶meters) @@ -350,12 +348,10 @@ BuildGraphTouchingJob::BuildGraphTouchingJob(const Logger &logger, QObject *pare { } -BuildGraphTouchingJob::~BuildGraphTouchingJob() -{ -} +BuildGraphTouchingJob::~BuildGraphTouchingJob() = default; void BuildGraphTouchingJob::setup(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, bool dryRun) + const QVector<ResolvedProductPtr> &products, bool dryRun) { m_project = project; m_products = products; @@ -374,14 +370,14 @@ InternalBuildJob::InternalBuildJob(const Logger &logger, QObject *parent) } void InternalBuildJob::build(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const BuildOptions &buildOptions) + const QVector<ResolvedProductPtr> &products, const BuildOptions &buildOptions) { setup(project, products, buildOptions.dryRun()); setTimed(buildOptions.logElapsedTime()); m_executor = new Executor(logger()); m_executor->setProject(project); - m_executor->setProducts(std::vector<ResolvedProductPtr>(products.cbegin(), products.cend())); + m_executor->setProducts(products); m_executor->setBuildOptions(buildOptions); m_executor->setProgressObserver(observer()); @@ -418,7 +414,8 @@ InternalCleanJob::InternalCleanJob(const Logger &logger, QObject *parent) } void InternalCleanJob::init(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const CleanOptions &options) + const QVector<ResolvedProductPtr> &products, + const CleanOptions &options) { setup(project, products, options.dryRun()); setTimed(options.logElapsedTime()); @@ -443,12 +440,10 @@ InternalInstallJob::InternalInstallJob(const Logger &logger) { } -InternalInstallJob::~InternalInstallJob() -{ -} +InternalInstallJob::~InternalInstallJob() = default; void InternalInstallJob::init(const TopLevelProjectPtr &project, - const std::vector<ResolvedProductPtr> &products, const InstallOptions &options) + const QVector<ResolvedProductPtr> &products, const InstallOptions &options) { m_project = project; m_products = products; diff --git a/src/lib/corelib/api/internaljobs.h b/src/lib/corelib/api/internaljobs.h index 58127eb05..d66835941 100644 --- a/src/lib/corelib/api/internaljobs.h +++ b/src/lib/corelib/api/internaljobs.h @@ -151,7 +151,7 @@ class BuildGraphTouchingJob : public InternalJob { Q_OBJECT public: - const QList<ResolvedProductPtr> &products() const { return m_products; } + const QVector<ResolvedProductPtr> &products() const { return m_products; } const TopLevelProjectPtr &project() const { return m_project; } signals: @@ -162,13 +162,13 @@ protected: BuildGraphTouchingJob(const Logger &logger, QObject *parent = nullptr); ~BuildGraphTouchingJob() override; - void setup(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, + void setup(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, bool dryRun); void storeBuildGraph(); private: TopLevelProjectPtr m_project; - QList<ResolvedProductPtr> m_products; + QVector<ResolvedProductPtr> m_products; bool m_dryRun; }; @@ -179,7 +179,7 @@ class InternalBuildJob : public BuildGraphTouchingJob public: InternalBuildJob(const Logger &logger, QObject *parent = nullptr); - void build(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, + void build(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const BuildOptions &buildOptions); private: @@ -196,8 +196,8 @@ class InternalCleanJob : public BuildGraphTouchingJob public: InternalCleanJob(const Logger &logger, QObject *parent = nullptr); - void init(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, - const CleanOptions &options); + void init(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, + const CleanOptions &options); private: void start() override; @@ -213,14 +213,14 @@ public: InternalInstallJob(const Logger &logger); ~InternalInstallJob() override; - void init(const TopLevelProjectPtr &project, const std::vector<ResolvedProductPtr> &products, + void init(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const InstallOptions &options); private: void start() override; TopLevelProjectPtr m_project; - std::vector<ResolvedProductPtr> m_products; + QVector<ResolvedProductPtr> m_products; InstallOptions m_options; }; diff --git a/src/lib/corelib/api/jobs.cpp b/src/lib/corelib/api/jobs.cpp index 32b7accc7..7a845b0ac 100644 --- a/src/lib/corelib/api/jobs.cpp +++ b/src/lib/corelib/api/jobs.cpp @@ -309,7 +309,7 @@ BuildJob::BuildJob(const Logger &logger, QObject *parent) this, &BuildJob::reportProcessResult); } -void BuildJob::build(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, +void BuildJob::build(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const BuildOptions &options) { if (!lockProject(project)) @@ -340,7 +340,7 @@ CleanJob::CleanJob(const Logger &logger, QObject *parent) { } -void CleanJob::clean(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, +void CleanJob::clean(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const qbs::CleanOptions &options) { if (!lockProject(project)) @@ -361,15 +361,14 @@ InstallJob::InstallJob(const Logger &logger, QObject *parent) } void InstallJob::install(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const InstallOptions &options) + const QVector<ResolvedProductPtr> &products, + const InstallOptions &options) { if (!lockProject(project)) return; auto wrapper = qobject_cast<InternalJobThreadWrapper *>(internalJob()); auto installJob = qobject_cast<InternalInstallJob *>(wrapper->synchronousJob()); - installJob->init(project, - std::vector<ResolvedProductPtr>(products.cbegin(), products.cend()), - options); + installJob->init(project, products, options); wrapper->start(); } diff --git a/src/lib/corelib/api/jobs.h b/src/lib/corelib/api/jobs.h index 36c6b7a80..64929489e 100644 --- a/src/lib/corelib/api/jobs.h +++ b/src/lib/corelib/api/jobs.h @@ -136,7 +136,7 @@ private: BuildJob(const Internal::Logger &logger, QObject *parent); void build(const Internal::TopLevelProjectPtr &project, - const QList<qbs::Internal::ResolvedProductPtr> &products, + const QVector<Internal::ResolvedProductPtr> &products, const BuildOptions &options); void handleLauncherError(const ErrorInfo &error); @@ -153,7 +153,7 @@ private: CleanJob(const Internal::Logger &logger, QObject *parent); void clean(const Internal::TopLevelProjectPtr &project, - const QList<Internal::ResolvedProductPtr> &products, const CleanOptions &options); + const QVector<Internal::ResolvedProductPtr> &products, const CleanOptions &options); }; class QBS_EXPORT InstallJob : public AbstractJob @@ -164,7 +164,8 @@ private: InstallJob(const Internal::Logger &logger, QObject *parent); void install(const Internal::TopLevelProjectPtr &project, - const QList<Internal::ResolvedProductPtr> &products, const InstallOptions &options); + const QVector<Internal::ResolvedProductPtr> &products, + const InstallOptions &options); }; } // namespace qbs diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp index d0fe7296e..2b07f1a8d 100644 --- a/src/lib/corelib/api/project.cpp +++ b/src/lib/corelib/api/project.cpp @@ -131,7 +131,7 @@ ProjectData ProjectPrivate::projectData() return m_projectData; } -static void addDependencies(QList<ResolvedProductPtr> &products) +static void addDependencies(QVector<ResolvedProductPtr> &products) { for (int i = 0; i < products.size(); ++i) { const ResolvedProductPtr &product = products.at(i); @@ -142,11 +142,11 @@ static void addDependencies(QList<ResolvedProductPtr> &products) } } -BuildJob *ProjectPrivate::buildProducts(const QList<ResolvedProductPtr> &products, +BuildJob *ProjectPrivate::buildProducts(const QVector<ResolvedProductPtr> &products, const BuildOptions &options, bool needsDepencencyResolving, QObject *jobOwner) { - QList<ResolvedProductPtr> productsToBuild = products; + QVector<ResolvedProductPtr> productsToBuild = products; if (needsDepencencyResolving) addDependencies(productsToBuild); @@ -156,7 +156,7 @@ BuildJob *ProjectPrivate::buildProducts(const QList<ResolvedProductPtr> &product return job; } -CleanJob *ProjectPrivate::cleanProducts(const QList<ResolvedProductPtr> &products, +CleanJob *ProjectPrivate::cleanProducts(const QVector<ResolvedProductPtr> &products, const CleanOptions &options, QObject *jobOwner) { const auto job = new CleanJob(logger, jobOwner); @@ -165,10 +165,10 @@ CleanJob *ProjectPrivate::cleanProducts(const QList<ResolvedProductPtr> &product return job; } -InstallJob *ProjectPrivate::installProducts(const QList<ResolvedProductPtr> &products, +InstallJob *ProjectPrivate::installProducts(const QVector<ResolvedProductPtr> &products, const InstallOptions &options, bool needsDepencencyResolving, QObject *jobOwner) { - QList<ResolvedProductPtr> productsToInstall = products; + QVector<ResolvedProductPtr> productsToInstall = products; if (needsDepencencyResolving) addDependencies(productsToInstall); const auto job = new InstallJob(logger, jobOwner); @@ -177,9 +177,9 @@ InstallJob *ProjectPrivate::installProducts(const QList<ResolvedProductPtr> &pro return job; } -QList<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductData> &products) const +QVector<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductData> &products) const { - QList<ResolvedProductPtr> internalProducts; + QVector<ResolvedProductPtr> internalProducts; for (const ProductData &product : products) { if (product.isEnabled()) internalProducts.push_back(internalProduct(product)); @@ -187,20 +187,21 @@ QList<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductDa return internalProducts; } -static QList<ResolvedProductPtr> enabledInternalProducts(const ResolvedProjectConstPtr &project, +static QVector<ResolvedProductPtr> enabledInternalProducts(const ResolvedProjectConstPtr &project, bool includingNonDefault) { - QList<ResolvedProductPtr> products; + QVector<ResolvedProductPtr> products; for (const ResolvedProductPtr &p : project->products) { if (p->enabled && (includingNonDefault || p->builtByDefault())) products.push_back(p); } - for (const ResolvedProjectConstPtr &subProject : qAsConst(project->subProjects)) + for (const auto &subProject : qAsConst(project->subProjects)) products << enabledInternalProducts(subProject, includingNonDefault); return products; } -QList<ResolvedProductPtr> ProjectPrivate::allEnabledInternalProducts(bool includingNonDefault) const +QVector<ResolvedProductPtr> ProjectPrivate::allEnabledInternalProducts( + bool includingNonDefault) const { return enabledInternalProducts(internalProject, includingNonDefault); } @@ -218,7 +219,7 @@ static ResolvedProductPtr internalProductForProject(const ResolvedProjectConstPt if (matches(product, resolvedProduct)) return resolvedProduct; } - for (const ResolvedProjectConstPtr &subProject : qAsConst(project->subProjects)) { + for (const auto &subProject : qAsConst(project->subProjects)) { const ResolvedProductPtr &p = internalProductForProject(subProject, product); if (p) return p; @@ -272,13 +273,13 @@ GroupData ProjectPrivate::createGroupDataFromGroup(const GroupPtr &resolvedGroup group.d->name = resolvedGroup->name; group.d->prefix = resolvedGroup->prefix; group.d->location = resolvedGroup->location; - for (const SourceArtifactConstPtr &sa : resolvedGroup->files) { + for (const auto &sa : resolvedGroup->files) { ArtifactData artifact = createApiSourceArtifact(sa); setupInstallData(artifact, product); group.d->sourceArtifacts.push_back(artifact); } if (resolvedGroup->wildcards) { - for (const SourceArtifactConstPtr &sa : resolvedGroup->wildcards->files) { + for (const auto &sa : resolvedGroup->wildcards->files) { ArtifactData artifact = createApiSourceArtifact(sa); setupInstallData(artifact, product); group.d->sourceArtifactsFromWildcards.push_back(artifact); @@ -355,7 +356,7 @@ void ProjectPrivate::addGroup(const ProductData &product, const QString &groupNa QList<ProductData> products = findProductsByName(product.name()); if (products.empty()) throw ErrorInfo(Tr::tr("Product '%1' does not exist.").arg(product.name())); - const QList<ResolvedProductPtr> resolvedProducts = internalProducts(products); + const auto resolvedProducts = internalProducts(products); QBS_CHECK(products.size() == resolvedProducts.size()); for (const GroupPtr &resolvedGroup : resolvedProducts.front()->groups) { @@ -367,28 +368,6 @@ void ProjectPrivate::addGroup(const ProductData &product, const QString &groupNa ProjectFileGroupInserter groupInserter(products.front(), groupName); groupInserter.apply(); - - m_projectData.d.detach(); // The data we already gave out must stay as it is. - - updateInternalCodeLocations(internalProject, groupInserter.itemPosition(), - groupInserter.lineOffset()); - updateExternalCodeLocations(m_projectData, groupInserter.itemPosition(), - groupInserter.lineOffset()); - - products = findProductsByName(products.front().name()); // These are new objects. - QBS_CHECK(products.size() == resolvedProducts.size()); - for (int i = 0; i < products.size(); ++i) { - const GroupPtr resolvedGroup = ResolvedGroup::create(); - resolvedGroup->location = groupInserter.itemPosition(); - resolvedGroup->enabled = true; - resolvedGroup->name = groupName; - resolvedGroup->properties = resolvedProducts[i]->moduleProperties; - resolvedGroup->overrideTags = false; - resolvedProducts.at(i)->groups << resolvedGroup; - QList<GroupData> &groupData = products.at(i).d->groups; - groupData << createGroupDataFromGroup(resolvedGroup, resolvedProducts.at(i)); - std::sort(groupData.begin(), groupData.end()); - } } ProjectPrivate::GroupUpdateContext ProjectPrivate::getGroupContext(const ProductData &product, @@ -484,15 +463,6 @@ ProjectPrivate::FileListUpdateContext ProjectPrivate::getFileListContext(const P return filesContext; } -static SourceArtifactPtr createSourceArtifact(const QString &filePath, - const ResolvedProductPtr &product, const GroupPtr &group, bool wildcard) -{ - const SourceArtifactPtr artifact - = ProjectResolver::createSourceArtifact(product, filePath, group, wildcard); - ProjectResolver::applyFileTaggers(artifact, product); - return artifact; -} - void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths) { @@ -503,7 +473,7 @@ void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group // due to conditions. for (const GroupPtr &group : qAsConst(groupContext.resolvedGroups)) { for (const QString &filePath : qAsConst(filesContext.absoluteFilePaths)) { - for (const SourceArtifactConstPtr &sa : group->files) { + for (const auto &sa : group->files) { if (sa->absoluteFilePath == filePath) { throw ErrorInfo(Tr::tr("File '%1' already exists in group '%2'.") .arg(filePath, group->name)); @@ -516,57 +486,6 @@ void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group group.isValid() ? groupContext.groups.front() : GroupData(), filesContext.relativeFilePaths); adder.apply(); - - m_projectData.d.detach(); - updateInternalCodeLocations(internalProject, adder.itemPosition(), adder.lineOffset()); - updateExternalCodeLocations(m_projectData, adder.itemPosition(), adder.lineOffset()); - - QHash<QString, std::pair<SourceArtifactPtr, ResolvedProductPtr>> addedSourceArtifacts; - for (int i = 0; i < groupContext.resolvedGroups.size(); ++i) { - const ResolvedProductPtr &resolvedProduct = groupContext.resolvedProducts.at(i); - const GroupPtr &resolvedGroup = groupContext.resolvedGroups.at(i); - for (const QString &file : qAsConst(filesContext.absoluteFilePaths)) { - const SourceArtifactPtr sa = createSourceArtifact(file, resolvedProduct, resolvedGroup, - false); - addedSourceArtifacts.insert(file, std::make_pair(sa, resolvedProduct)); - } - for (const QString &file : qAsConst(filesContext.absoluteFilePathsFromWildcards)) { - QBS_CHECK(resolvedGroup->wildcards); - const SourceArtifactPtr sa = createSourceArtifact(file, resolvedProduct, resolvedGroup, - true); - addedSourceArtifacts.insert(file, std::make_pair(sa, resolvedProduct)); - } - if (resolvedProduct->enabled) { - for (const auto &pair : qAsConst(addedSourceArtifacts)) - createArtifact(resolvedProduct, pair.first); - } - } - doSanityChecks(internalProject, logger); - QList<ArtifactData> sourceArtifacts; - QList<ArtifactData> sourceArtifactsFromWildcards; - for (const QString &fp : qAsConst(filesContext.absoluteFilePaths)) { - const auto pair = addedSourceArtifacts.value(fp); - const SourceArtifactConstPtr sa = pair.first; - QBS_CHECK(sa); - ArtifactData artifactData = createApiSourceArtifact(sa); - setupInstallData(artifactData, pair.second); - sourceArtifacts << artifactData; - } - for (const QString &fp : qAsConst(filesContext.absoluteFilePathsFromWildcards)) { - const auto pair = addedSourceArtifacts.value(fp); - const SourceArtifactConstPtr sa = pair.first; - QBS_CHECK(sa); - ArtifactData artifactData = createApiSourceArtifact(sa); - setupInstallData(artifactData, pair.second); - sourceArtifactsFromWildcards << artifactData; - } - for (const GroupData &g : qAsConst(groupContext.groups)) { - g.d->sourceArtifacts << sourceArtifacts; - std::sort(g.d->sourceArtifacts.begin(), g.d->sourceArtifacts.end()); - g.d->sourceArtifactsFromWildcards << sourceArtifactsFromWildcards; - std::sort(g.d->sourceArtifactsFromWildcards.begin(), - g.d->sourceArtifactsFromWildcards.end()); - } } void ProjectPrivate::removeFiles(const ProductData &product, const GroupData &group, @@ -595,134 +514,17 @@ void ProjectPrivate::removeFiles(const ProductData &product, const GroupData &gr group.isValid() ? groupContext.groups.front() : GroupData(), filesContext.relativeFilePaths); remover.apply(); - - for (int i = 0; i < groupContext.resolvedProducts.size(); ++i) { - removeFilesFromBuildGraph(groupContext.resolvedProducts.at(i), sourceArtifacts); - for (const SourceArtifactPtr &sa : sourceArtifacts) - removeOne(groupContext.resolvedGroups.at(i)->files, sa); - } - doSanityChecks(internalProject, logger); - - m_projectData.d.detach(); - updateInternalCodeLocations(internalProject, remover.itemPosition(), remover.lineOffset()); - updateExternalCodeLocations(m_projectData, remover.itemPosition(), remover.lineOffset()); - for (const GroupData &g : qAsConst(groupContext.groups)) { - for (int i = g.d->sourceArtifacts.size() - 1; i >= 0; --i) { - if (filesContext.absoluteFilePaths.contains(g.d->sourceArtifacts.at(i).filePath())) - g.d->sourceArtifacts.removeAt(i); - } - } } void ProjectPrivate::removeGroup(const ProductData &product, const GroupData &group) { GroupUpdateContext context = getGroupContext(product, group); - ProjectFileGroupRemover remover(context.products.front(), context.groups.front()); remover.apply(); - for (int i = 0; i < context.resolvedProducts.size(); ++i) { - const ResolvedProductPtr &product = context.resolvedProducts.at(i); - const GroupPtr &group = context.resolvedGroups.at(i); - removeFilesFromBuildGraph(product, group->allFiles()); - const bool removed = removeOne(product->groups, group); - QBS_CHECK(removed); - } - doSanityChecks(internalProject, logger); - - m_projectData.d.detach(); - updateInternalCodeLocations(internalProject, remover.itemPosition(), remover.lineOffset()); - updateExternalCodeLocations(m_projectData, remover.itemPosition(), remover.lineOffset()); - for (int i = 0; i < context.products.size(); ++i) { - const bool removed = context.products.at(i).d->groups.removeOne(context.groups.at(i)); - QBS_CHECK(removed); - } } #endif // QBS_ENABLE_PROJECT_FILE_UPDATES -void ProjectPrivate::removeFilesFromBuildGraph(const ResolvedProductConstPtr &product, - const std::vector<SourceArtifactPtr> &files) -{ - if (!product->enabled) - return; - QBS_CHECK(internalProject->buildData); - ArtifactSet allRemovedArtifacts; - for (const SourceArtifactPtr &sa : files) { - ArtifactSet removedArtifacts; - Artifact * const artifact = lookupArtifact(product, sa->absoluteFilePath); - if (artifact) { // Can be null if the executor has not yet applied the respective rule. - internalProject->buildData->removeArtifactAndExclusiveDependents(artifact, logger, - true, &removedArtifacts); - } - allRemovedArtifacts.unite(removedArtifacts); - } - EmptyDirectoriesRemover(product->topLevelProject(), logger) - .removeEmptyParentDirectories(allRemovedArtifacts); - qDeleteAll(allRemovedArtifacts); -} - -static void updateLocationIfNecessary(CodeLocation &location, const CodeLocation &changeLocation, - int lineOffset) -{ - if (location.filePath() == changeLocation.filePath() - && location.line() >= changeLocation.line()) { - location = CodeLocation(location.filePath(), location.line() + lineOffset, - location.column()); - } -} - -void ProjectPrivate::updateInternalCodeLocations(const ResolvedProjectPtr &project, - const CodeLocation &changeLocation, int lineOffset) -{ - if (lineOffset == 0) - return; - updateLocationIfNecessary(project->location, changeLocation, lineOffset); - for (const ResolvedProjectPtr &subProject : qAsConst(project->subProjects)) - updateInternalCodeLocations(subProject, changeLocation, lineOffset); - for (const ResolvedProductPtr &product : project->products) { - updateLocationIfNecessary(product->location, changeLocation, lineOffset); - for (const GroupPtr &group : product->groups) - updateLocationIfNecessary(group->location, changeLocation, lineOffset); - for (const RulePtr &rule : qAsConst(product->rules)) { - updateLocationIfNecessary(rule->prepareScript.location(), changeLocation, lineOffset); - for (const RuleArtifactPtr &artifact : rule->artifacts) { - for (auto &binding : artifact->bindings) { - updateLocationIfNecessary(binding.location, changeLocation, lineOffset); - } - } - } - for (const ResolvedScannerConstPtr &scanner : product->scanners) { - updateLocationIfNecessary(scanner->searchPathsScript.location(), changeLocation, - lineOffset); - updateLocationIfNecessary(scanner->scanScript.location(), changeLocation, lineOffset); - } - for (const ResolvedModuleConstPtr &module : product->modules) { - updateLocationIfNecessary(module->setupBuildEnvironmentScript.location(), - changeLocation, lineOffset); - updateLocationIfNecessary(module->setupRunEnvironmentScript.location(), - changeLocation, lineOffset); - } - } -} - -void ProjectPrivate::updateExternalCodeLocations(const ProjectData &project, - const CodeLocation &changeLocation, int lineOffset) -{ - if (lineOffset == 0) - return; - updateLocationIfNecessary(project.d->location, changeLocation, lineOffset); - const auto subProjects = project.subProjects(); - for (const ProjectData &subProject : subProjects) - updateExternalCodeLocations(subProject, changeLocation, lineOffset); - const auto products = project.products(); - for (const ProductData &product : products) { - updateLocationIfNecessary(product.d->location, changeLocation, lineOffset); - const auto groups = product.groups(); - for (const GroupData &group : groups) - updateLocationIfNecessary(group.d->location, changeLocation, lineOffset); - } -} - void ProjectPrivate::prepareChangeToProject() { if (internalProject->locked) @@ -851,7 +653,7 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData, projectData.d->name = internalProject->name; projectData.d->location = internalProject->location; projectData.d->enabled = internalProject->enabled; - for (const ResolvedProductConstPtr &resolvedProduct : internalProject->products) { + for (const auto &resolvedProduct : internalProject->products) { ProductData product; product.d->type = resolvedProduct->fileTags.toStringList(); product.d->name = resolvedProduct->name; @@ -904,8 +706,7 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData, product.d->isValid = true; projectData.d->products << product; } - for (const ResolvedProjectConstPtr &internalSubProject - : qAsConst(internalProject->subProjects)) { + for (const auto &internalSubProject : qAsConst(internalProject->subProjects)) { if (!internalSubProject->enabled) continue; ProjectData subProject; @@ -931,13 +732,9 @@ Project::Project(const TopLevelProjectPtr &internalProject, const Logger &logger { } -Project::Project(const Project &other) : d(other.d) -{ -} +Project::Project(const Project &other) = default; -Project::~Project() -{ -} +Project::~Project() = default; /*! * \brief Returns true if and only if this object was retrieved from a successful \c SetupProjectJob. @@ -957,11 +754,7 @@ QString Project::profile() const return d->internalProject->profile(); } -Project &Project::operator=(const Project &other) -{ - d = other.d; - return *this; -} +Project &Project::operator=(const Project &other) = default; /*! * \brief Sets up a \c Project from a source file, possibly re-using previously stored information. @@ -996,10 +789,7 @@ SetupProjectJob *Project::setupProject(const SetupProjectParameters ¶meters, return job; } -Project::Project() -{ -} - +Project::Project() = default; /*! * \brief Retrieves information for this project. @@ -1227,9 +1017,9 @@ Project::BuildGraphInfo Project::getBuildGraphInfo(const QString &bgFilePath, for (const QString &prop : requestedProperties) { QStringList components = prop.split(QLatin1Char('.')); const QString propName = components.takeLast(); - props.push_back(std::make_pair(components.join(QLatin1Char('.')), propName)); + props.emplace_back(components.join(QLatin1Char('.')), propName); } - for (const ResolvedProductConstPtr &product : project->allProducts()) { + for (const auto &product : project->allProducts()) { if (props.empty()) break; if (product->profile() != project->profile()) @@ -1283,10 +1073,10 @@ ErrorInfo Project::addGroup(const ProductData &product, const QString &groupName QBS_CHECK(isValid()); d->prepareChangeToProject(); d->addGroup(product, groupName); - d->internalProject->lastStartResolveTime = FileTime::currentTime(); d->internalProject->store(d->logger); return {}; - } catch (ErrorInfo errorInfo) { + } catch (const ErrorInfo &exception) { + auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure adding group '%1' to product '%2'.") .arg(groupName, product.name())); return errorInfo; @@ -1310,10 +1100,10 @@ ErrorInfo Project::addFiles(const ProductData &product, const GroupData &group, QBS_CHECK(isValid()); d->prepareChangeToProject(); d->addFiles(product, group, filePaths); - d->internalProject->lastStartResolveTime = FileTime::currentTime(); d->internalProject->store(d->logger); return {}; - } catch (ErrorInfo errorInfo) { + } catch (const ErrorInfo &exception) { + auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure adding files to product.")); return errorInfo; } @@ -1336,10 +1126,10 @@ ErrorInfo Project::removeFiles(const ProductData &product, const GroupData &grou QBS_CHECK(isValid()); d->prepareChangeToProject(); d->removeFiles(product, group, filePaths); - d->internalProject->lastStartResolveTime = FileTime::currentTime(); d->internalProject->store(d->logger); return {}; - } catch (ErrorInfo errorInfo) { + } catch (const ErrorInfo &exception) { + auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure removing files from product '%1'.").arg(product.name())); return errorInfo; } @@ -1357,10 +1147,10 @@ ErrorInfo Project::removeGroup(const ProductData &product, const GroupData &grou QBS_CHECK(isValid()); d->prepareChangeToProject(); d->removeGroup(product, group); - d->internalProject->lastStartResolveTime = FileTime::currentTime(); d->internalProject->store(d->logger); return {}; - } catch (ErrorInfo errorInfo) { + } catch (const ErrorInfo &exception) { + auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure removing group '%1' from product '%2'.") .arg(group.name(), product.name())); return errorInfo; diff --git a/src/lib/corelib/api/project_p.h b/src/lib/corelib/api/project_p.h index 58f61a5bc..60c8311f3 100644 --- a/src/lib/corelib/api/project_p.h +++ b/src/lib/corelib/api/project_p.h @@ -62,22 +62,22 @@ namespace Internal { class ProjectPrivate : public QSharedData { public: - ProjectPrivate(const TopLevelProjectPtr &internalProject, const Logger &logger) - : internalProject(internalProject), logger(logger) + ProjectPrivate(TopLevelProjectPtr internalProject, Logger logger) + : internalProject(std::move(internalProject)), logger(std::move(logger)) { } ProjectData projectData(); - BuildJob *buildProducts(const QList<ResolvedProductPtr> &products, const BuildOptions &options, + BuildJob *buildProducts(const QVector<ResolvedProductPtr> &products, const BuildOptions &options, bool needsDepencencyResolving, QObject *jobOwner); - CleanJob *cleanProducts(const QList<ResolvedProductPtr> &products, const CleanOptions &options, + CleanJob *cleanProducts(const QVector<ResolvedProductPtr> &products, const CleanOptions &options, QObject *jobOwner); - InstallJob *installProducts(const QList<ResolvedProductPtr> &products, + InstallJob *installProducts(const QVector<ResolvedProductPtr> &products, const InstallOptions &options, bool needsDepencencyResolving, QObject *jobOwner); - QList<ResolvedProductPtr> internalProducts(const QList<ProductData> &products) const; - QList<ResolvedProductPtr> allEnabledInternalProducts(bool includingNonDefault) const; + QVector<ResolvedProductPtr> internalProducts(const QList<ProductData> &products) const; + QVector<ResolvedProductPtr> allEnabledInternalProducts(bool includingNonDefault) const; ResolvedProductPtr internalProduct(const ProductData &product) const; ProductData findProductData(const ProductData &product) const; QList<ProductData> findProductsByName(const QString &name) const; @@ -92,7 +92,7 @@ public: void setupInstallData(ArtifactData &artifact, const ResolvedProductConstPtr &product); struct GroupUpdateContext { - QList<ResolvedProductPtr> resolvedProducts; + QVector<ResolvedProductPtr> resolvedProducts; QList<GroupPtr> resolvedGroups; QList<ProductData> products; QList<GroupData> groups; @@ -114,12 +114,7 @@ public: void removeFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths); void removeGroup(const ProductData &product, const GroupData &group); - void removeFilesFromBuildGraph(const ResolvedProductConstPtr &product, - const std::vector<SourceArtifactPtr> &files); - void updateInternalCodeLocations(const ResolvedProjectPtr &project, - const CodeLocation &changeLocation, int lineOffset); - void updateExternalCodeLocations(const ProjectData &project, - const CodeLocation &changeLocation, int lineOffset); + void prepareChangeToProject(); RuleCommandList ruleCommandListForTransformer(const Transformer *transformer); diff --git a/src/lib/corelib/api/projectfileupdater.cpp b/src/lib/corelib/api/projectfileupdater.cpp index 04f8e630f..0bc5bc7c4 100644 --- a/src/lib/corelib/api/projectfileupdater.cpp +++ b/src/lib/corelib/api/projectfileupdater.cpp @@ -115,7 +115,7 @@ private: }; -ProjectFileUpdater::ProjectFileUpdater(const QString &projectFile) : m_projectFile(projectFile) +ProjectFileUpdater::ProjectFileUpdater(QString projectFile) : m_projectFile(std::move(projectFile)) { } @@ -201,11 +201,10 @@ void ProjectFileUpdater::apply() } -ProjectFileGroupInserter::ProjectFileGroupInserter(const ProductData &product, - const QString &groupName) +ProjectFileGroupInserter::ProjectFileGroupInserter(ProductData product, QString groupName) : ProjectFileUpdater(product.location().filePath()) - , m_product(product) - , m_groupName(groupName) + , m_product(std::move(product)) + , m_groupName(std::move(groupName)) { } @@ -222,7 +221,7 @@ void ProjectFileGroupInserter::doApply(QString &fileContent, UiProgram *ast) Rewriter rewriter(fileContent, &changeSet, QStringList()); QString groupItemString; const int productItemIndentation - = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1; + = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int groupItemIndentation = productItemIndentation + 4; const QString groupItemIndentationString = QString(groupItemIndentation, QLatin1Char(' ')); groupItemString += groupItemIndentationString + QLatin1String("Group {\n"); @@ -252,7 +251,7 @@ static QString getNodeRepresentation(const QString &fileContent, const QbsQmlJS: { const quint32 start = node->firstSourceLocation().offset; const quint32 end = node->lastSourceLocation().end(); - return fileContent.mid(start, end - start); + return fileContent.mid(start, int(end - start)); } static const ChangeSet::EditOp &getEditOp(const ChangeSet &changeSet) @@ -273,12 +272,12 @@ static int getBindingLine(const ChangeSet &changeSet, const QString &fileContent } -ProjectFileFilesAdder::ProjectFileFilesAdder(const ProductData &product, const GroupData &group, - const QStringList &files) +ProjectFileFilesAdder::ProjectFileFilesAdder(ProductData product, GroupData group, + QStringList files) : ProjectFileUpdater(product.location().filePath()) - , m_product(product) - , m_group(group) - , m_files(files) + , m_product(std::move(product)) + , m_group(std::move(group)) + , m_files(std::move(files)) { } @@ -319,7 +318,7 @@ void ProjectFileFilesAdder::doApply(QString &fileContent, UiProgram *ast) } const int itemIndentation - = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1; + = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int bindingIndentation = itemIndentation + 4; const int arrayElemIndentation = bindingIndentation + 4; @@ -405,12 +404,12 @@ void ProjectFileFilesAdder::doApply(QString &fileContent, UiProgram *ast) changeSet.apply(&fileContent); } -ProjectFileFilesRemover::ProjectFileFilesRemover(const ProductData &product, const GroupData &group, - const QStringList &files) +ProjectFileFilesRemover::ProjectFileFilesRemover(ProductData product, GroupData group, + QStringList files) : ProjectFileUpdater(product.location().filePath()) - , m_product(product) - , m_group(group) - , m_files(files) + , m_product(std::move(product)) + , m_group(std::move(group)) + , m_files(std::move(files)) { } @@ -444,7 +443,7 @@ void ProjectFileFilesRemover::doApply(QString &fileContent, UiProgram *ast) Rewriter rewriter(fileContent, &changeSet, QStringList()); const int itemIndentation - = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1; + = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int bindingIndentation = itemIndentation + 4; const int arrayElemIndentation = bindingIndentation + 4; @@ -512,10 +511,10 @@ void ProjectFileFilesRemover::doApply(QString &fileContent, UiProgram *ast) } -ProjectFileGroupRemover::ProjectFileGroupRemover(const ProductData &product, const GroupData &group) +ProjectFileGroupRemover::ProjectFileGroupRemover(ProductData product, GroupData group) : ProjectFileUpdater(product.location().filePath()) - , m_product(product) - , m_group(group) + , m_product(std::move(product)) + , m_group(std::move(group)) { } diff --git a/src/lib/corelib/api/projectfileupdater.h b/src/lib/corelib/api/projectfileupdater.h index c0d46c747..3459d788e 100644 --- a/src/lib/corelib/api/projectfileupdater.h +++ b/src/lib/corelib/api/projectfileupdater.h @@ -61,7 +61,7 @@ public: int lineOffset() const { return m_lineOffset; } protected: - ProjectFileUpdater(const QString &projectFile); + ProjectFileUpdater(QString projectFile); QString projectFile() const { return m_projectFile; } @@ -92,7 +92,7 @@ private: class ProjectFileGroupInserter : public ProjectFileUpdater { public: - ProjectFileGroupInserter(const ProductData &product, const QString &groupName); + ProjectFileGroupInserter(ProductData product, QString groupName); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; @@ -105,8 +105,7 @@ private: class ProjectFileFilesAdder : public ProjectFileUpdater { public: - ProjectFileFilesAdder(const ProductData &product, const GroupData &group, - const QStringList &files); + ProjectFileFilesAdder(ProductData product, GroupData group, QStringList files); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; @@ -119,8 +118,8 @@ private: class ProjectFileFilesRemover : public ProjectFileUpdater { public: - ProjectFileFilesRemover(const ProductData &product, const GroupData &group, - const QStringList &files); + ProjectFileFilesRemover(ProductData product, GroupData group, + QStringList files); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; @@ -133,7 +132,7 @@ private: class ProjectFileGroupRemover : public ProjectFileUpdater { public: - ProjectFileGroupRemover(const ProductData &product, const GroupData &group); + ProjectFileGroupRemover(ProductData product, GroupData group); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; diff --git a/src/lib/corelib/api/qmljsrewriter.cpp b/src/lib/corelib/api/qmljsrewriter.cpp index 16817d682..5551e5650 100644 --- a/src/lib/corelib/api/qmljsrewriter.cpp +++ b/src/lib/corelib/api/qmljsrewriter.cpp @@ -63,12 +63,12 @@ static QString toString(UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Cha } -Rewriter::Rewriter(const QString &originalText, +Rewriter::Rewriter(QString originalText, ChangeSet *changeSet, - const QStringList &propertyOrder) - : m_originalText(originalText) + QStringList propertyOrder) + : m_originalText(std::move(originalText)) , m_changeSet(changeSet) - , m_propertyOrder(propertyOrder) + , m_propertyOrder(std::move(propertyOrder)) { Q_ASSERT(changeSet); } @@ -260,7 +260,7 @@ UiObjectMemberList *Rewriter::searchMemberToInsertAfter(UiObjectMemberList *memb idx = propertyOrder.size() - 1; for (; idx > 0; --idx) { - const QString prop = propertyOrder.at(idx - 1); + const QString &prop = propertyOrder.at(idx - 1); UiObjectMemberList *candidate = orderedMembers.value(prop, 0); if (candidate != nullptr) return candidate; @@ -649,7 +649,7 @@ Rewriter::Range Rewriter::addObject(UiObjectInitializer *ast, const QString &con textToInsert += content; m_changeSet->insert(insertionPoint, QLatin1String("\n") + textToInsert); - return Range(insertionPoint, insertionPoint); + return {insertionPoint, insertionPoint}; } Rewriter::Range Rewriter::addObject(UiArrayBinding *ast, const QString &content) @@ -672,7 +672,7 @@ Rewriter::Range Rewriter::addObject(UiArrayBinding *ast, const QString &content, m_changeSet->insert(insertionPoint, textToInsert); - return Range(insertionPoint, insertionPoint); + return {insertionPoint, insertionPoint}; } void Rewriter::removeObjectMember(UiObjectMember *member, UiObjectMember *parent) diff --git a/src/lib/corelib/api/qmljsrewriter.h b/src/lib/corelib/api/qmljsrewriter.h index 797b05459..3788035f2 100644 --- a/src/lib/corelib/api/qmljsrewriter.h +++ b/src/lib/corelib/api/qmljsrewriter.h @@ -60,9 +60,9 @@ public: using Range = ChangeSet::Range; public: - Rewriter(const QString &originalText, + Rewriter(QString originalText, ChangeSet *changeSet, - const QStringList &propertyOrder); + QStringList propertyOrder); Range addBinding(AST::UiObjectInitializer *ast, const QString &propertyName, diff --git a/src/lib/corelib/api/rulecommand.cpp b/src/lib/corelib/api/rulecommand.cpp index bc12140f3..e01cde7cc 100644 --- a/src/lib/corelib/api/rulecommand.cpp +++ b/src/lib/corelib/api/rulecommand.cpp @@ -65,17 +65,11 @@ RuleCommand::RuleCommand() : d(new Internal::RuleCommandPrivate) { } -RuleCommand::RuleCommand(const RuleCommand &other) : d(other.d) {} +RuleCommand::RuleCommand(const RuleCommand &other) = default; -RuleCommand::~RuleCommand() -{ -} +RuleCommand::~RuleCommand() = default; -RuleCommand& RuleCommand::operator=(const RuleCommand &other) -{ - d = other.d; - return *this; -} +RuleCommand& RuleCommand::operator=(const RuleCommand &other) = default; /*! * Returns the type of this object. If the value is \c InvalidType, the object is invalid. diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp index df5b4337d..94a74dac2 100644 --- a/src/lib/corelib/api/runenvironment.cpp +++ b/src/lib/corelib/api/runenvironment.cpp @@ -62,8 +62,8 @@ #include <QtCore/qtemporaryfile.h> #include <QtCore/qvariant.h> +#include <cstdlib> #include <regex> -#include <stdlib.h> namespace qbs { using namespace Internal; diff --git a/src/lib/corelib/api/runenvironment.h b/src/lib/corelib/api/runenvironment.h index 69603bf76..c5123ca9c 100644 --- a/src/lib/corelib/api/runenvironment.h +++ b/src/lib/corelib/api/runenvironment.h @@ -52,6 +52,8 @@ class QString; class QStringList; QT_END_NAMESPACE +class TestApi; + namespace qbs { class ErrorInfo; class InstallOptions; @@ -66,7 +68,7 @@ class QBS_EXPORT RunEnvironment { friend class CommandLineFrontend; friend class Project; - friend class TestApi; + friend class ::TestApi; public: ~RunEnvironment(); diff --git a/src/lib/corelib/api/transformerdata.cpp b/src/lib/corelib/api/transformerdata.cpp index b4ee61d0c..9724e641b 100644 --- a/src/lib/corelib/api/transformerdata.cpp +++ b/src/lib/corelib/api/transformerdata.cpp @@ -44,14 +44,10 @@ namespace qbs { TransformerData::TransformerData() : d(new Internal::TransformerDataPrivate) { } -TransformerData::TransformerData(const TransformerData &other) : d(other.d) {} -TransformerData::~TransformerData() { } +TransformerData::TransformerData(const TransformerData &other) = default; +TransformerData::~TransformerData() = default; -TransformerData& TransformerData::operator=(const TransformerData &other) -{ - d = other.d; - return *this; -} +TransformerData& TransformerData::operator=(const TransformerData &other) = default; QList<ArtifactData> TransformerData::inputs() const { return d->inputs; } QList<ArtifactData> TransformerData::outputs() const { return d->outputs; } diff --git a/src/lib/corelib/buildgraph/artifactcleaner.cpp b/src/lib/corelib/buildgraph/artifactcleaner.cpp index 000dfda02..03b327232 100644 --- a/src/lib/corelib/buildgraph/artifactcleaner.cpp +++ b/src/lib/corelib/buildgraph/artifactcleaner.cpp @@ -162,7 +162,7 @@ ArtifactCleaner::ArtifactCleaner(Logger logger, ProgressObserver *observer) } void ArtifactCleaner::cleanup(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const CleanOptions &options) + const QVector<ResolvedProductPtr> &products, const CleanOptions &options) { m_hasError = false; diff --git a/src/lib/corelib/buildgraph/artifactcleaner.h b/src/lib/corelib/buildgraph/artifactcleaner.h index 5112a75d6..8d0bef275 100644 --- a/src/lib/corelib/buildgraph/artifactcleaner.h +++ b/src/lib/corelib/buildgraph/artifactcleaner.h @@ -54,7 +54,7 @@ class ArtifactCleaner { public: ArtifactCleaner(Logger logger, ProgressObserver *observer); - void cleanup(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, + void cleanup(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const CleanOptions &options); private: diff --git a/src/lib/corelib/buildgraph/artifactvisitor.cpp b/src/lib/corelib/buildgraph/artifactvisitor.cpp index c28f07424..22c987572 100644 --- a/src/lib/corelib/buildgraph/artifactvisitor.cpp +++ b/src/lib/corelib/buildgraph/artifactvisitor.cpp @@ -61,7 +61,7 @@ void ArtifactVisitor::visitProduct(const ResolvedProductConstPtr &product) void ArtifactVisitor::visitProject(const ResolvedProjectConstPtr &project) { - for (const ResolvedProductConstPtr &product : project->allProducts()) + for (const auto &product : project->allProducts()) visitProduct(product); } diff --git a/src/lib/corelib/buildgraph/buildgraph.cpp b/src/lib/corelib/buildgraph/buildgraph.cpp index 3726c654d..0d5e8a1f0 100644 --- a/src/lib/corelib/buildgraph/buildgraph.cpp +++ b/src/lib/corelib/buildgraph/buildgraph.cpp @@ -278,7 +278,7 @@ private: } return result; } - for (const ResolvedModuleConstPtr &dependency : product->modules) { + for (const auto &dependency : product->modules) { if (dependency->isProduct) continue; QScriptValue obj = engine->newObject(engine->modulePropertyScriptClass()); @@ -661,7 +661,7 @@ void provideFullFileTagsAndProperties(Artifact *artifact) artifact->properties = artifact->product->moduleProperties; FileTags allTags = artifact->pureFileTags.empty() ? artifact->product->fileTagsForFileName(artifact->fileName()) : artifact->pureFileTags; - for (const ArtifactPropertiesConstPtr &props : artifact->product->artifactProperties) { + for (const auto &props : artifact->product->artifactProperties) { if (allTags.intersects(props->fileTagsFilter())) { artifact->properties = props->propertyMap(); allTags += props->extraFileTags(); @@ -733,7 +733,7 @@ static void doSanityChecksForProduct(const ResolvedProductConstPtr &product, CycleDetector cycleDetector(logger); cycleDetector.visitProduct(product); const ProductBuildData * const buildData = product->buildData.get(); - for (const ResolvedModuleConstPtr &m : product->modules) + for (const auto &m : product->modules) QBS_CHECK(m->product == product.get()); qCDebug(lcBuildGraph) << "enabled:" << product->enabled << "build data:" << buildData; if (product->enabled) @@ -836,7 +836,7 @@ static void doSanityChecks(const ResolvedProjectPtr &project, for (const ResolvedProjectPtr &subProject : qAsConst(project->subProjects)) doSanityChecks(subProject, allProducts, productNames, logger); - for (const ResolvedProductConstPtr &product : project->products) { + for (const auto &product : project->products) { QBS_CHECK(product->project == project); QBS_CHECK(product->topLevelProject() == project->topLevelProject()); doSanityChecksForProduct(product, allProducts, logger); diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp index bf6c30dcd..58a34b616 100644 --- a/src/lib/corelib/buildgraph/buildgraphloader.cpp +++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp @@ -71,6 +71,7 @@ #include <algorithm> #include <functional> +#include <memory> #include <unordered_map> namespace qbs { @@ -273,7 +274,7 @@ static void updateProductAndRulePointers(const ResolvedProductPtr &newProduct) const auto it = ruleMap.find(oldRule); if (it != ruleMap.cend()) return it->second; - for (const RuleConstPtr &r : qAsConst(newProduct->rules)) { + for (const auto &r : qAsConst(newProduct->rules)) { if (*r == *oldRule) { ruleMap.insert(std::make_pair(oldRule, r)); return r; @@ -362,7 +363,7 @@ void BuildGraphLoader::trackProjectChanges() ChildListHash childLists; if (!changedProducts.empty()) { oldBuildData = std::make_shared<ProjectBuildData>(restoredProject->buildData.get()); - for (const ResolvedProductConstPtr &product : qAsConst(allRestoredProducts)) { + for (const auto &product : qAsConst(allRestoredProducts)) { if (!product->buildData) continue; @@ -451,7 +452,7 @@ void BuildGraphLoader::trackProjectChanges() updateGeneratedArtifacts(product.get()); } - for (const ResolvedProductConstPtr &changedProduct : qAsConst(changedProducts)) { + for (const auto &changedProduct : qAsConst(changedProducts)) { rescueOldBuildData(changedProduct, m_freshProductsByName.value(changedProduct->uniqueName()), childLists, rescuableArtifactData.value(changedProduct->uniqueName())); @@ -614,7 +615,7 @@ bool BuildGraphLoader::hasProductFileChanged(const std::vector<ResolvedProductPt FileInfo::path(group->location.filePath()), product->topLevelProject()->buildDirectory); Set<QString> wcFiles; - for (const SourceArtifactConstPtr &sourceArtifact : group->wildcards->files) + for (const auto &sourceArtifact : group->wildcards->files) wcFiles += sourceArtifact->absoluteFilePath; if (files == wcFiles) continue; @@ -741,9 +742,9 @@ static bool dependenciesAreEqual(const ResolvedProductConstPtr &p1, return false; Set<QString> names1; Set<QString> names2; - for (const ResolvedProductConstPtr &dep : qAsConst(p1->dependencies)) + for (const auto &dep : qAsConst(p1->dependencies)) names1 << dep->uniqueName(); - for (const ResolvedProductConstPtr &dep : qAsConst(p2->dependencies)) + for (const auto &dep : qAsConst(p2->dependencies)) names2 << dep->uniqueName(); return names1 == names2; } @@ -909,7 +910,7 @@ void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restore if (!restoredProduct->buildData) return; if (!newlyResolvedProduct->buildData) - newlyResolvedProduct->buildData.reset(new ProductBuildData); + newlyResolvedProduct->buildData = std::make_unique<ProductBuildData>(); qCDebug(lcBuildGraph) << "rescue data of product" << restoredProduct->uniqueName(); QBS_CHECK(newlyResolvedProduct->buildData); diff --git a/src/lib/corelib/buildgraph/buildgraphloader.h b/src/lib/corelib/buildgraph/buildgraphloader.h index 9363b8358..c62ba7fa7 100644 --- a/src/lib/corelib/buildgraph/buildgraphloader.h +++ b/src/lib/corelib/buildgraph/buildgraphloader.h @@ -121,9 +121,9 @@ private: bool checkConfigCompatibility(); struct ChildrenInfo { - ChildrenInfo() {} - ChildrenInfo(const ArtifactSet &c1, const ArtifactSet &c2) - : children(c1), childrenAddedByScanner(c2) {} + ChildrenInfo() = default; + ChildrenInfo(ArtifactSet c1, ArtifactSet c2) + : children(std::move(c1)), childrenAddedByScanner(std::move(c2)) {} ArtifactSet children; ArtifactSet childrenAddedByScanner; }; diff --git a/src/lib/corelib/buildgraph/depscanner.h b/src/lib/corelib/buildgraph/depscanner.h index ffc0b83de..6b18004f9 100644 --- a/src/lib/corelib/buildgraph/depscanner.h +++ b/src/lib/corelib/buildgraph/depscanner.h @@ -61,7 +61,7 @@ class ScriptEngine; class DependencyScanner { public: - virtual ~DependencyScanner() {} + virtual ~DependencyScanner() = default; QString id() const; diff --git a/src/lib/corelib/buildgraph/environmentscriptrunner.cpp b/src/lib/corelib/buildgraph/environmentscriptrunner.cpp index 7d82efb41..9dafbf296 100644 --- a/src/lib/corelib/buildgraph/environmentscriptrunner.cpp +++ b/src/lib/corelib/buildgraph/environmentscriptrunner.cpp @@ -129,12 +129,12 @@ void EnvironmentScriptRunner::setupEnvironment() return; QMap<QString, const ResolvedModule *> moduleMap; - for (const ResolvedModuleConstPtr &module : m_product->modules) + for (const auto &module : m_product->modules) moduleMap.insert(module->name, module.get()); QHash<const ResolvedModule*, QList<const ResolvedModule*> > moduleParents; QHash<const ResolvedModule*, QList<const ResolvedModule*> > moduleChildren; - for (const ResolvedModuleConstPtr &module : m_product->modules) { + for (const auto &module : m_product->modules) { for (const QString &moduleName : qAsConst(module->moduleDependencies)) { const ResolvedModule * const depmod = moduleMap.value(moduleName); QBS_ASSERT(depmod, return); @@ -144,7 +144,7 @@ void EnvironmentScriptRunner::setupEnvironment() } QList<const ResolvedModule *> rootModules; - for (const ResolvedModuleConstPtr &module : m_product->modules) { + for (const auto &module : m_product->modules) { if (moduleParents.value(module.get()).isEmpty()) { QBS_ASSERT(module, return); rootModules.push_back(module.get()); diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp index de81ada20..377222d21 100644 --- a/src/lib/corelib/buildgraph/executor.cpp +++ b/src/lib/corelib/buildgraph/executor.cpp @@ -102,12 +102,8 @@ Executor::Executor(Logger logger, QObject *parent) Executor::~Executor() { - // jobs must be destroyed before deleting the shared scan result cache - for (ExecutorJob *job : qAsConst(m_availableJobs)) - delete job; - const auto processingJobs = m_processingJobs.keys(); - for (ExecutorJob *job : processingJobs) - delete job; + // jobs must be destroyed before deleting the m_inputArtifactScanContext + m_allJobs.clear(); delete m_inputArtifactScanContext; delete m_productInstaller; } @@ -153,7 +149,7 @@ void Executor::retrieveSourceFileTimestamp(Artifact *artifact) const void Executor::build() { try { - m_partialBuild = m_productsToBuild.size() != m_allProducts.size(); + m_partialBuild = size_t(m_productsToBuild.size()) != m_allProducts.size(); doBuild(); } catch (const ErrorInfo &e) { handleError(e); @@ -170,7 +166,7 @@ void Executor::setProject(const TopLevelProjectPtr &project) m_projectsByName.insert(std::make_pair(p->name, p.get())); } -void Executor::setProducts(const std::vector<ResolvedProductPtr> &productsToBuild) +void Executor::setProducts(const QVector<ResolvedProductPtr> &productsToBuild) { m_productsToBuild = productsToBuild; m_productsByName.clear(); @@ -266,8 +262,7 @@ void Executor::doBuild() doSanityChecks(); QBS_CHECK(!m_project->buildData->evaluationContext); - m_project->buildData->evaluationContext - = RulesEvaluationContextPtr(new RulesEvaluationContext(m_logger)); + m_project->buildData->evaluationContext = std::make_shared<RulesEvaluationContext>(m_logger); m_evalContext = m_project->buildData->evaluationContext; m_elapsedTimeRules = m_elapsedTimeScanners = m_elapsedTimeInstalling = 0; @@ -700,7 +695,7 @@ bool Executor::transformerHasMatchingInputFiles(const TransformerConstPtr &trans void Executor::setupJobLimits() { Settings settings(m_buildOptions.settingsDirectory()); - for (const ResolvedProductConstPtr &p : m_productsToBuild) { + for (const auto &p : qAsConst(m_productsToBuild)) { const Preferences prefs(&settings, p->profile()); const JobLimits &jobLimitsFromSettings = prefs.jobLimits(); JobLimits effectiveJobLimits; @@ -737,7 +732,7 @@ void Executor::setupProgressObserver() if (!m_progressObserver) return; int totalEffort = 1; // For the effort after the last rule application; - for (const ResolvedProductConstPtr &product : qAsConst(m_productsToBuild)) { + for (const auto &product : qAsConst(m_productsToBuild)) { QBS_CHECK(product->buildData); const auto filtered = filterByType<RuleNode>(product->buildData->allNodes()); totalEffort += std::distance(filtered.begin(), filtered.end()); @@ -749,7 +744,7 @@ void Executor::doSanityChecks() { QBS_CHECK(m_project); QBS_CHECK(!m_productsToBuild.empty()); - for (const ResolvedProductConstPtr &product : qAsConst(m_productsToBuild)) { + for (const auto &product : qAsConst(m_productsToBuild)) { QBS_CHECK(product->buildData); QBS_CHECK(product->topLevelProject() == m_project.get()); } @@ -768,10 +763,13 @@ void Executor::handleError(const ErrorInfo &error) void Executor::addExecutorJobs() { - qCDebug(lcExec) << "preparing executor for" << m_buildOptions.maxJobCount() - << "jobs in parallel"; - for (int i = 1; i <= m_buildOptions.maxJobCount(); i++) { - const auto job = new ExecutorJob(m_logger, this); + const int count = m_buildOptions.maxJobCount(); + qCDebug(lcExec) << "preparing executor for" << count << "jobs in parallel"; + m_allJobs.reserve(count); + m_availableJobs.reserve(count); + for (int i = 1; i <= count; i++) { + m_allJobs.push_back(std::make_unique<ExecutorJob>(m_logger)); + const auto job = m_allJobs.back().get(); job->setMainThreadScriptEngine(m_evalContext->engine()); job->setObjectName(QStringLiteral("J%1").arg(i)); job->setDryRun(m_buildOptions.dryRun()); @@ -1084,7 +1082,7 @@ void Executor::checkForUnbuiltProducts() if (m_buildOptions.executeRulesOnly()) return; std::vector<ResolvedProductPtr> unbuiltProducts; - for (const ResolvedProductPtr &product : m_productsToBuild) { + for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) { bool productBuilt = true; for (BuildGraphNode *rootNode : qAsConst(product->buildData->rootNodes())) { if (rootNode->buildState != BuildGraphNode::Built) { @@ -1206,7 +1204,7 @@ void Executor::prepareAllNodes() node->buildState = BuildGraphNode::Untouched; } } - for (const ResolvedProductPtr &product : m_productsToBuild) { + for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) { QBS_CHECK(product->buildData); for (Artifact * const artifact : filterByType<Artifact>(product->buildData->allNodes())) prepareArtifact(artifact); @@ -1228,7 +1226,7 @@ void Executor::syncFileDependencies() "removing from lookup table"; m_project->buildData->removeFromLookupTable(dep); bool isReferencedByArtifact = false; - for (const ResolvedProductConstPtr &product : m_allProducts) { + for (const auto &product : m_allProducts) { if (!product->buildData) continue; const auto artifactList = filterByType<Artifact>(product->buildData->allNodes()); @@ -1310,7 +1308,7 @@ void Executor::prepareProducts() { ProductPrioritySetter prioritySetter(m_allProducts); prioritySetter.apply(); - for (const ResolvedProductPtr &product : m_productsToBuild) { + for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) { EnvironmentScriptRunner(product.get(), m_evalContext.get(), m_project->environment) .setupForBuild(); } @@ -1319,7 +1317,7 @@ void Executor::prepareProducts() void Executor::setupRootNodes() { m_roots.clear(); - for (const ResolvedProductPtr &product : m_productsToBuild) + for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) m_roots += product->buildData->rootNodes(); } diff --git a/src/lib/corelib/buildgraph/executor.h b/src/lib/corelib/buildgraph/executor.h index 1fd591176..cc879e125 100644 --- a/src/lib/corelib/buildgraph/executor.h +++ b/src/lib/corelib/buildgraph/executor.h @@ -81,7 +81,7 @@ public: ~Executor() override; void setProject(const TopLevelProjectPtr &project); - void setProducts(const std::vector<ResolvedProductPtr> &productsToBuild); + void setProducts(const QVector<ResolvedProductPtr> &productsToBuild); void setBuildOptions(const BuildOptions &buildOptions); void setProgressObserver(ProgressObserver *observer) { m_progressObserver = observer; } @@ -166,10 +166,11 @@ private: BuildOptions m_buildOptions; Logger m_logger; ProgressObserver *m_progressObserver; + std::vector<std::unique_ptr<ExecutorJob>> m_allJobs; QList<ExecutorJob*> m_availableJobs; ExecutorState m_state; TopLevelProjectPtr m_project; - std::vector<ResolvedProductPtr> m_productsToBuild; + QVector<ResolvedProductPtr> m_productsToBuild; std::vector<ResolvedProductPtr> m_allProducts; std::unordered_map<QString, const ResolvedProduct *> m_productsByName; std::unordered_map<QString, const ResolvedProject *> m_projectsByName; diff --git a/src/lib/corelib/buildgraph/executorjob.cpp b/src/lib/corelib/buildgraph/executorjob.cpp index 79f17377d..bc96cbb6e 100644 --- a/src/lib/corelib/buildgraph/executorjob.cpp +++ b/src/lib/corelib/buildgraph/executorjob.cpp @@ -71,9 +71,7 @@ ExecutorJob::ExecutorJob(const Logger &logger, QObject *parent) reset(); } -ExecutorJob::~ExecutorJob() -{ -} +ExecutorJob::~ExecutorJob() = default; void ExecutorJob::setMainThreadScriptEngine(ScriptEngine *engine) { diff --git a/src/lib/corelib/buildgraph/executorjob.h b/src/lib/corelib/buildgraph/executorjob.h index bc8954072..1f8f0cd73 100644 --- a/src/lib/corelib/buildgraph/executorjob.h +++ b/src/lib/corelib/buildgraph/executorjob.h @@ -65,7 +65,7 @@ class ExecutorJob : public QObject { Q_OBJECT public: - ExecutorJob(const Logger &logger, QObject *parent); + explicit ExecutorJob(const Logger &logger, QObject *parent = nullptr); ~ExecutorJob() override; void setMainThreadScriptEngine(ScriptEngine *engine); diff --git a/src/lib/corelib/buildgraph/filedependency.cpp b/src/lib/corelib/buildgraph/filedependency.cpp index 9420fa96b..cbee758c7 100644 --- a/src/lib/corelib/buildgraph/filedependency.cpp +++ b/src/lib/corelib/buildgraph/filedependency.cpp @@ -44,13 +44,9 @@ namespace qbs { namespace Internal { -FileResourceBase::FileResourceBase() -{ -} +FileResourceBase::FileResourceBase() = default; -FileResourceBase::~FileResourceBase() -{ -} +FileResourceBase::~FileResourceBase() = default; void FileResourceBase::setTimestamp(const FileTime &t) @@ -86,13 +82,9 @@ void FileResourceBase::store(PersistentPool &pool) } -FileDependency::FileDependency() -{ -} +FileDependency::FileDependency() = default; -FileDependency::~FileDependency() -{ -} +FileDependency::~FileDependency() = default; } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/buildgraph/inputartifactscanner.cpp b/src/lib/corelib/buildgraph/inputartifactscanner.cpp index 81cbe2178..1d00e29e1 100644 --- a/src/lib/corelib/buildgraph/inputartifactscanner.cpp +++ b/src/lib/corelib/buildgraph/inputartifactscanner.cpp @@ -77,6 +77,7 @@ static void resolveDepencency(const RawScannedDependency &dependency, FileDependency *fileDependencyArtifact = nullptr; Artifact *dependencyInProduct = nullptr; Artifact *dependencyInOtherProduct = nullptr; + bool productOfDependencyIsDependency = false; const auto files = project->topLevelProject() ->buildData->lookupFiles(absDirPath, dependency.fileName()); for (FileResourceBase *lookupResult : files) { @@ -86,10 +87,13 @@ static void resolveDepencency(const RawScannedDependency &dependency, break; case FileResourceBase::FileTypeArtifact: { auto const foundArtifact = static_cast<Artifact *>(lookupResult); - if (foundArtifact->product == product) + if (foundArtifact->product == product) { dependencyInProduct = foundArtifact; - else + } else if (!productOfDependencyIsDependency) { dependencyInOtherProduct = foundArtifact; + productOfDependencyIsDependency + = contains(product->dependencies, dependencyInOtherProduct->product.lock()); + } break; } } @@ -102,6 +106,14 @@ static void resolveDepencency(const RawScannedDependency &dependency, || (result->file = dependencyInOtherProduct) || (result->file = fileDependencyArtifact)) { result->filePath = result->file->filePath(); + + if (result->file == dependencyInOtherProduct && !productOfDependencyIsDependency) { + qCDebug(lcDepScan) << "product" << dependencyInOtherProduct->product->fullDisplayName() + << "of scanned dependency" << result->filePath + << "is not a dependency of product" << product->fullDisplayName() + << ". The file dependency might get lost during change tracking."; + } + return; } @@ -349,6 +361,8 @@ void InputArtifactScanner::handleDependency(ResolvedDependency &dependency) if (m_artifact == dependency.file) return; + if (artifactDependency && artifactDependency->transformer == m_artifact->transformer) + return; if (fileDependency) { m_artifact->fileDependencies << fileDependency; @@ -372,16 +386,14 @@ void InputArtifactScanner::scanWithScannerPlugin(DependencyScanner *scanner, const QStringList &dependencies = scanner->collectDependencies( inputArtifact, fileToBeScanned, m_fileTagsForScanner.constData()); for (const QString &s : dependencies) - scanResult->deps.push_back(RawScannedDependency(s)); + scanResult->deps.emplace_back(s); } InputArtifactScannerContext::DependencyScannerCacheItem::DependencyScannerCacheItem() : valid(false) { } -InputArtifactScannerContext::DependencyScannerCacheItem::~DependencyScannerCacheItem() -{ -} +InputArtifactScannerContext::DependencyScannerCacheItem::~DependencyScannerCacheItem() = default; } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/buildgraph/nodetreedumper.cpp b/src/lib/corelib/buildgraph/nodetreedumper.cpp index 89975baf2..8475a46cf 100644 --- a/src/lib/corelib/buildgraph/nodetreedumper.cpp +++ b/src/lib/corelib/buildgraph/nodetreedumper.cpp @@ -51,13 +51,13 @@ namespace qbs { namespace Internal { -static unsigned int indentWidth() { return 4; } +static int indentWidth() { return 4; } NodeTreeDumper::NodeTreeDumper(QIODevice &outDevice) : m_outDevice(outDevice) { } -void NodeTreeDumper::start(const QList<ResolvedProductPtr> &products) +void NodeTreeDumper::start(const QVector<ResolvedProductPtr> &products) { m_indentation = 0; for (const ResolvedProductPtr &p : products) { diff --git a/src/lib/corelib/buildgraph/nodetreedumper.h b/src/lib/corelib/buildgraph/nodetreedumper.h index 4175ce727..38ccd6dae 100644 --- a/src/lib/corelib/buildgraph/nodetreedumper.h +++ b/src/lib/corelib/buildgraph/nodetreedumper.h @@ -57,7 +57,7 @@ class NodeTreeDumper : public BuildGraphVisitor public: NodeTreeDumper(QIODevice &outDevice); - void start(const QList<ResolvedProductPtr> &products); + void start(const QVector<ResolvedProductPtr> &products); private: bool visit(Artifact *artifact) override; @@ -74,7 +74,7 @@ private: QIODevice &m_outDevice; ResolvedProductPtr m_currentProduct; NodeSet m_visited; - unsigned int m_indentation = 0; + int m_indentation = 0; }; } // namespace Internal diff --git a/src/lib/corelib/buildgraph/processcommandexecutor.cpp b/src/lib/corelib/buildgraph/processcommandexecutor.cpp index 79edda320..7cde8553c 100644 --- a/src/lib/corelib/buildgraph/processcommandexecutor.cpp +++ b/src/lib/corelib/buildgraph/processcommandexecutor.cpp @@ -166,6 +166,7 @@ bool ProcessCommandExecutor::doStart() .arg(responseFile.fileName()))); return false; } + const auto separator = cmd->responseFileSeparator().toUtf8(); for (int i = cmd->responseFileArgumentIndex(); i < cmd->arguments().size(); ++i) { const QString arg = cmd->arguments().at(i); if (arg.startsWith(cmd->responseFileUsagePrefix())) { @@ -179,7 +180,7 @@ bool ProcessCommandExecutor::doStart() } else { responseFile.write(qbs::Internal::shellQuote(arg).toLocal8Bit()); } - responseFile.write("\n"); + responseFile.write(separator); } responseFile.close(); m_responseFileName = responseFile.fileName(); diff --git a/src/lib/corelib/buildgraph/productinstaller.cpp b/src/lib/corelib/buildgraph/productinstaller.cpp index d4acc9ace..80a76d7f5 100644 --- a/src/lib/corelib/buildgraph/productinstaller.cpp +++ b/src/lib/corelib/buildgraph/productinstaller.cpp @@ -60,7 +60,7 @@ namespace qbs { namespace Internal { ProductInstaller::ProductInstaller(TopLevelProjectPtr project, - std::vector<ResolvedProductPtr> products, InstallOptions options, + QVector<ResolvedProductPtr> products, InstallOptions options, ProgressObserver *observer, Logger logger) : m_project(std::move(project)), m_products(std::move(products)), @@ -96,7 +96,7 @@ void ProductInstaller::install() removeInstallRoot(); QList<const Artifact *> artifactsToInstall; - for (const ResolvedProductConstPtr &product : qAsConst(m_products)) { + for (const auto &product : qAsConst(m_products)) { QBS_CHECK(product->buildData); for (const Artifact *artifact : filterByType<Artifact>(product->buildData->allNodes())) { if (artifact->properties->qbsPropertyValue(StringConstants::installProperty()).toBool()) @@ -250,5 +250,5 @@ void ProductInstaller::handleError(const QString &message) m_logger.qbsWarning() << message; } -} // namespace Intern +} // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/buildgraph/productinstaller.h b/src/lib/corelib/buildgraph/productinstaller.h index 09828cfe9..c07e0b7cf 100644 --- a/src/lib/corelib/buildgraph/productinstaller.h +++ b/src/lib/corelib/buildgraph/productinstaller.h @@ -56,7 +56,7 @@ class ProductInstaller { public: ProductInstaller(TopLevelProjectPtr project, - std::vector<ResolvedProductPtr> products, + QVector<ResolvedProductPtr> products, InstallOptions options, ProgressObserver *observer, Logger logger); void install(); @@ -72,7 +72,7 @@ private: void handleError(const QString &message); const TopLevelProjectConstPtr m_project; - const std::vector<ResolvedProductPtr> m_products; + const QVector<ResolvedProductPtr> m_products; InstallOptions m_options; ProgressObserver * const m_observer; Logger m_logger; diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp index 31012e23e..0ac6b1537 100644 --- a/src/lib/corelib/buildgraph/projectbuilddata.cpp +++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp @@ -60,6 +60,8 @@ #include <tools/qttools.h> #include <tools/stlutils.h> +#include <memory> + namespace qbs { namespace Internal { @@ -276,7 +278,7 @@ void BuildDataResolver::resolveBuildData(const TopLevelProjectPtr &resolvedProje { QBS_CHECK(!resolvedProject->buildData); m_project = resolvedProject; - resolvedProject->buildData.reset(new ProjectBuildData); + resolvedProject->buildData = std::make_unique<ProjectBuildData>(); resolvedProject->buildData->evaluationContext = evalContext; const std::vector<ResolvedProductPtr> &allProducts = resolvedProject->allProducts(); evalContext->initializeObserver(Tr::tr("Setting up build graph for configuration %1") @@ -390,7 +392,7 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc evalContext()->checkForCancelation(); - product->buildData.reset(new ProductBuildData); + product->buildData = std::make_unique<ProductBuildData>(); ArtifactSetByFileTag artifactsPerFileTag; for (const auto &dependency : qAsConst(product->dependencies)) { @@ -411,7 +413,7 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc artifactsPerFileTag["qbs"].insert(qbsFileArtifact); // read sources - for (const SourceArtifactConstPtr &sourceArtifact : product->allEnabledFiles()) { + for (const auto &sourceArtifact : product->allEnabledFiles()) { QString filePath = sourceArtifact->absoluteFilePath; if (lookupArtifact(product, filePath)) continue; // ignore duplicate artifacts @@ -443,7 +445,7 @@ void BuildDataResolver::connectRulesToDependencies(const ResolvedProductPtr &pro std::vector<RuleNode *> ruleNodes; for (RuleNode *ruleNode : filterByType<RuleNode>(product->buildData->allNodes())) ruleNodes.push_back(ruleNode); - for (const ResolvedProductConstPtr &dep : dependencies) { + for (const auto &dep : dependencies) { if (!dep->buildData) continue; for (RuleNode *depRuleNode : filterByType<RuleNode>(dep->buildData->allNodes())) { diff --git a/src/lib/corelib/buildgraph/qtmocscanner.cpp b/src/lib/corelib/buildgraph/qtmocscanner.cpp index c834c60e6..4e054a636 100644 --- a/src/lib/corelib/buildgraph/qtmocscanner.cpp +++ b/src/lib/corelib/buildgraph/qtmocscanner.cpp @@ -167,7 +167,7 @@ static RawScanResult runScanner(ScannerPlugin *scanner, const Artifact *artifact if (FileInfo::exists(localFilePath)) includedFilePath = localFilePath; } - scanData.rawScanResult.deps.push_back(RawScannedDependency(includedFilePath)); + scanData.rawScanResult.deps.emplace_back(includedFilePath); } scanner->close(opaq); diff --git a/src/lib/corelib/buildgraph/requesteddependencies.cpp b/src/lib/corelib/buildgraph/requesteddependencies.cpp index f993b2518..b95c8db94 100644 --- a/src/lib/corelib/buildgraph/requesteddependencies.cpp +++ b/src/lib/corelib/buildgraph/requesteddependencies.cpp @@ -48,9 +48,9 @@ namespace Internal { static Set<QString> depNamesForProduct(const ResolvedProduct *p) { Set<QString> names; - for (const ResolvedProductConstPtr &dep : p->dependencies) + for (const auto &dep : p->dependencies) names.insert(dep->uniqueName()); - for (const ResolvedModuleConstPtr &m : p->modules) { + for (const auto &m : p->modules) { if (!m->isProduct) names.insert(m->name); } @@ -73,7 +73,7 @@ bool RequestedDependencies::isUpToDate(const TopLevelProject *project) const { if (m_depsPerProduct.empty()) return true; - for (const ResolvedProductConstPtr &product : project->allProducts()) { + for (const auto &product : project->allProducts()) { const auto it = m_depsPerProduct.find(product->uniqueName()); if (it == m_depsPerProduct.cend()) continue; diff --git a/src/lib/corelib/buildgraph/rescuableartifactdata.h b/src/lib/corelib/buildgraph/rescuableartifactdata.h index 3e4d6e25f..6dd10f76c 100644 --- a/src/lib/corelib/buildgraph/rescuableartifactdata.h +++ b/src/lib/corelib/buildgraph/rescuableartifactdata.h @@ -84,9 +84,12 @@ public: struct ChildData { - ChildData(const QString &n = QString(), const QString &m = QString(), - const QString &c = QString(), bool byScanner = false) - : productName(n), productMultiplexId(m), childFilePath(c), addedByScanner(byScanner) + ChildData(QString n = QString(), QString m = QString(), + QString c = QString(), bool byScanner = false) + : productName(std::move(n)) + , productMultiplexId(std::move(m)) + , childFilePath(std::move(c)) + , addedByScanner(byScanner) {} template<PersistentPool::OpType opType> void completeSerializationOp(PersistentPool &pool) diff --git a/src/lib/corelib/buildgraph/rulecommands.cpp b/src/lib/corelib/buildgraph/rulecommands.cpp index 31ff6be4b..8fa3255f1 100644 --- a/src/lib/corelib/buildgraph/rulecommands.cpp +++ b/src/lib/corelib/buildgraph/rulecommands.cpp @@ -70,6 +70,7 @@ static QString responseFileUsagePrefixProperty() { return QStringLiteral("responseFileUsagePrefix"); } +static QString responseFileSeparatorProperty() { return QStringLiteral("responseFileSeparator"); } static QString silentProperty() { return QStringLiteral("silent"); } static QString stderrFilePathProperty() { return QStringLiteral("stderrFilePath"); } static QString stderrFilterFunctionProperty() { return QStringLiteral("stderrFilterFunction"); } @@ -78,7 +79,7 @@ static QString stdoutFilterFunctionProperty() { return QStringLiteral("stdoutFil static QString timeoutProperty() { return QStringLiteral("timeout"); } static QString workingDirProperty() { return QStringLiteral("workingDirectory"); } -static QString invokedSourceCode(const QScriptValue codeOrFunction) +static QString invokedSourceCode(const QScriptValue &codeOrFunction) { const QString &code = codeOrFunction.toString(); return codeOrFunction.isFunction() ? QStringLiteral("(") + code + QStringLiteral(")()") : code; @@ -94,9 +95,7 @@ AbstractCommand::AbstractCommand() { } -AbstractCommand::~AbstractCommand() -{ -} +AbstractCommand::~AbstractCommand() = default; bool AbstractCommand::equals(const AbstractCommand *other) const { @@ -218,6 +217,8 @@ static QScriptValue js_Command(QScriptContext *context, QScriptEngine *engine) engine->toScriptValue(commandPrototype->responseFileArgumentIndex())); cmd.setProperty(responseFileUsagePrefixProperty(), engine->toScriptValue(commandPrototype->responseFileUsagePrefix())); + cmd.setProperty(responseFileSeparatorProperty(), + engine->toScriptValue(commandPrototype->responseFileSeparator())); cmd.setProperty(stdoutFilePathProperty(), engine->toScriptValue(commandPrototype->stdoutFilePath())); cmd.setProperty(stderrFilePathProperty(), @@ -241,6 +242,7 @@ ProcessCommand::ProcessCommand() : m_maxExitCode(0) , m_responseFileThreshold(defaultResponseFileThreshold()) , m_responseFileArgumentIndex(0) + , m_responseFileSeparator(QStringLiteral("\n")) { } @@ -279,6 +281,7 @@ bool ProcessCommand::equals(const AbstractCommand *otherAbstractCommand) const && m_responseFileThreshold == other->m_responseFileThreshold && m_responseFileArgumentIndex == other->m_responseFileArgumentIndex && m_responseFileUsagePrefix == other->m_responseFileUsagePrefix + && m_responseFileSeparator == other->m_responseFileSeparator && m_stdoutFilePath == other->m_stdoutFilePath && m_stderrFilePath == other->m_stderrFilePath && m_relevantEnvVars == other->m_relevantEnvVars @@ -313,6 +316,8 @@ void ProcessCommand::fillFromScriptValue(const QScriptValue *scriptValue, const .toInt32(); m_responseFileUsagePrefix = scriptValue->property(responseFileUsagePrefixProperty()) .toString(); + m_responseFileSeparator = scriptValue->property(responseFileSeparatorProperty()) + .toString(); QStringList envList = scriptValue->property(environmentProperty()).toVariant() .toStringList(); getEnvironmentFromList(envList); @@ -399,9 +404,7 @@ void JavaScriptCommand::setupForJavaScript(QScriptValue targetObject) targetObject.setProperty(StringConstants::javaScriptCommandType(), ctor); } -JavaScriptCommand::JavaScriptCommand() -{ -} +JavaScriptCommand::JavaScriptCommand() = default; bool JavaScriptCommand::equals(const AbstractCommand *otherAbstractCommand) const { diff --git a/src/lib/corelib/buildgraph/rulecommands.h b/src/lib/corelib/buildgraph/rulecommands.h index d4d70d591..725cd6d89 100644 --- a/src/lib/corelib/buildgraph/rulecommands.h +++ b/src/lib/corelib/buildgraph/rulecommands.h @@ -136,6 +136,7 @@ public: int responseFileThreshold() const { return m_responseFileThreshold; } int responseFileArgumentIndex() const { return m_responseFileArgumentIndex; } QString responseFileUsagePrefix() const { return m_responseFileUsagePrefix; } + QString responseFileSeparator() const { return m_responseFileSeparator; } QProcessEnvironment environment() const { return m_environment; } QStringList relevantEnvVars() const; void clearRelevantEnvValues() { m_relevantEnvValues.clear(); } @@ -158,10 +159,10 @@ private: { pool.serializationOp<opType>(m_program, m_arguments, m_environment, m_workingDir, m_stdoutFilterFunction, m_stderrFilterFunction, - m_responseFileUsagePrefix, m_maxExitCode, - m_responseFileThreshold, m_responseFileArgumentIndex, - m_relevantEnvVars, m_relevantEnvValues, m_stdoutFilePath, - m_stderrFilePath); + m_responseFileUsagePrefix, m_responseFileSeparator, + m_maxExitCode, m_responseFileThreshold, + m_responseFileArgumentIndex, m_relevantEnvVars, + m_relevantEnvValues, m_stdoutFilePath, m_stderrFilePath); } QString m_program; @@ -173,6 +174,7 @@ private: int m_responseFileThreshold; // When to use response files? In bytes of (program name + arguments). int m_responseFileArgumentIndex; QString m_responseFileUsagePrefix; + QString m_responseFileSeparator; QProcessEnvironment m_environment; QStringList m_relevantEnvVars; QProcessEnvironment m_relevantEnvValues; diff --git a/src/lib/corelib/buildgraph/rulegraph.cpp b/src/lib/corelib/buildgraph/rulegraph.cpp index 23227ca09..23f22b7f2 100644 --- a/src/lib/corelib/buildgraph/rulegraph.cpp +++ b/src/lib/corelib/buildgraph/rulegraph.cpp @@ -46,9 +46,7 @@ namespace qbs { namespace Internal { -RuleGraph::RuleGraph() -{ -} +RuleGraph::RuleGraph() = default; void RuleGraph::build(const std::vector<RulePtr> &rules, const FileTags &productFileTags) { @@ -63,7 +61,7 @@ void RuleGraph::build(const std::vector<RulePtr> &rules, const FileTags &product m_parents.resize(rules.size()); m_children.resize(rules.size()); - for (const RuleConstPtr &rule : qAsConst(m_rules)) { + for (const auto &rule : qAsConst(m_rules)) { FileTags inFileTags = rule->inputs; inFileTags += rule->auxiliaryInputs; inFileTags += rule->explicitlyDependsOn; @@ -100,7 +98,7 @@ void RuleGraph::dump() const QByteArray indent; printf("---rule graph dump:\n"); Set<int> rootRules; - for (const RuleConstPtr &rule : qAsConst(m_rules)) + for (const auto &rule : qAsConst(m_rules)) if (m_parents[rule->ruleGraphId].empty()) rootRules += rule->ruleGraphId; for (int idx : qAsConst(rootRules)) diff --git a/src/lib/corelib/buildgraph/rulenode.cpp b/src/lib/corelib/buildgraph/rulenode.cpp index bf25b1da8..0558ba144 100644 --- a/src/lib/corelib/buildgraph/rulenode.cpp +++ b/src/lib/corelib/buildgraph/rulenode.cpp @@ -56,13 +56,9 @@ namespace qbs { namespace Internal { -RuleNode::RuleNode() -{ -} +RuleNode::RuleNode() = default; -RuleNode::~RuleNode() -{ -} +RuleNode::~RuleNode() = default; void RuleNode::accept(BuildGraphVisitor *visitor) { @@ -182,7 +178,7 @@ void RuleNode::apply(const Logger &logger, if (removedInputForcesOutputRemoval) outputArtifactsToRemove += parent; else - connectionsToBreak.push_back(std::make_pair(parent, artifact)); + connectionsToBreak.emplace_back(parent, artifact); } disconnect(this, artifact); } @@ -262,7 +258,7 @@ ArtifactSet RuleNode::currentInputArtifacts() const } } - for (const ResolvedProductConstPtr &dep : qAsConst(product->dependencies)) { + for (const auto &dep : qAsConst(product->dependencies)) { if (!dep->buildData) continue; for (Artifact * const a : filterByType<Artifact>(dep->buildData->allNodes())) { diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp index 16aa0c001..0d36e1e21 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.cpp +++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp @@ -79,12 +79,13 @@ namespace Internal { RulesApplicator::RulesApplicator( ResolvedProductPtr product, - std::unordered_map<QString, const ResolvedProduct *> productsByName, - std::unordered_map<QString, const ResolvedProject *> projectsByName, + const std::unordered_map<QString, const ResolvedProduct *> &productsByName, + const std::unordered_map<QString, const ResolvedProject *> &projectsByName, Logger logger) : m_product(std::move(product)) - , m_productsByName(std::move(productsByName)) - , m_projectsByName(std::move(projectsByName)) + // m_productsByName and m_projectsByName are references, cannot move-construct + , m_productsByName(productsByName) + , m_projectsByName(projectsByName) , m_mocScanner(nullptr) , m_logger(std::move(logger)) { @@ -213,13 +214,13 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p ScriptEngine::argumentList(Rule::argumentNamesForOutputArtifacts(), scope())); } else { Set<QString> outputFilePaths; - for (const RuleArtifactConstPtr &ruleArtifact : m_rule->artifacts) { + for (const auto &ruleArtifact : m_rule->artifacts) { const OutputArtifactInfo outputInfo = createOutputArtifactFromRuleArtifact( ruleArtifact, inputArtifacts, &outputFilePaths); if (!outputInfo.artifact) continue; outputArtifacts.push_back(outputInfo.artifact); - ruleArtifactArtifactMap.push_back({ ruleArtifact.get(), outputInfo }); + ruleArtifactArtifactMap.emplace_back(ruleArtifact.get(), outputInfo); } if (m_rule->artifacts.empty()) { outputArtifacts.push_back(createOutputArtifactFromRuleArtifact( @@ -287,7 +288,7 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p } const QVariant value = scriptValue.toVariant(); setConfigProperty(artifactModulesCfg, binding.name, value); - outputArtifact->pureProperties.push_back(std::make_pair(binding.name, value)); + outputArtifact->pureProperties.emplace_back(binding.name, value); } outputArtifact->properties->setValue(artifactModulesCfg); if (!outputInfo.newlyCreated && (outputArtifact->fileTags() != outputInfo.oldFileTags @@ -354,7 +355,7 @@ ArtifactSet RulesApplicator::collectAdditionalInputs(const FileTags &tags, const } if (inputsSources.testFlag(Dependencies)) { - for (const ResolvedProductConstPtr &depProduct : product->dependencies) { + for (const auto &depProduct : product->dependencies) { for (Artifact * const ta : depProduct->targetArtifacts()) { if (ta->fileTags().contains(fileTag) && !ta->fileTags().intersects(rule->excludedInputs)) { @@ -607,7 +608,7 @@ public: for (const auto &e : m_propertyValues) { const QStringList key{e.module, e.name}; setConfigProperty(artifactCfg, key, e.value); - outputArtifact->pureProperties.push_back(std::make_pair(key, e.value)); + outputArtifact->pureProperties.emplace_back(key, e.value); } outputArtifact->properties->setValue(artifactCfg); } diff --git a/src/lib/corelib/buildgraph/rulesapplicator.h b/src/lib/corelib/buildgraph/rulesapplicator.h index 1160f3d09..da7815014 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.h +++ b/src/lib/corelib/buildgraph/rulesapplicator.h @@ -63,8 +63,8 @@ class RulesApplicator { public: RulesApplicator(ResolvedProductPtr product, - std::unordered_map<QString, const ResolvedProduct *> productsByName, - std::unordered_map<QString, const ResolvedProject *> projectsByName, + const std::unordered_map<QString, const ResolvedProduct *> &productsByName, + const std::unordered_map<QString, const ResolvedProject *> &projectsByName, Logger logger); ~RulesApplicator(); diff --git a/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h b/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h index f6154f993..b57072236 100644 --- a/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h +++ b/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h @@ -57,10 +57,10 @@ class ScriptClassPropertyIterator : public QScriptClassPropertyIterator { public: ScriptClassPropertyIterator(const QScriptValue &object, const QVariantMap &properties, - const std::vector<QString> &additionalProperties) + std::vector<QString> additionalProperties) : QScriptClassPropertyIterator(object), m_it(properties), - m_additionalProperties(additionalProperties) + m_additionalProperties(std::move(additionalProperties)) { } diff --git a/src/lib/corelib/buildgraph/timestampsupdater.cpp b/src/lib/corelib/buildgraph/timestampsupdater.cpp index d31f57445..3f5279dd2 100644 --- a/src/lib/corelib/buildgraph/timestampsupdater.cpp +++ b/src/lib/corelib/buildgraph/timestampsupdater.cpp @@ -83,7 +83,7 @@ private: }; void TimestampsUpdater::updateTimestamps(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const Logger &logger) + const QVector<ResolvedProductPtr> &products, const Logger &logger) { TimestampsUpdateVisitor v; for (const ResolvedProductPtr &product : products) diff --git a/src/lib/corelib/buildgraph/timestampsupdater.h b/src/lib/corelib/buildgraph/timestampsupdater.h index cfe20df12..8184ca708 100644 --- a/src/lib/corelib/buildgraph/timestampsupdater.h +++ b/src/lib/corelib/buildgraph/timestampsupdater.h @@ -51,7 +51,7 @@ class TimestampsUpdater { public: void updateTimestamps(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const Logger &logger); + const QVector<ResolvedProductPtr> &products, const Logger &logger); }; } // namespace Internal diff --git a/src/lib/corelib/buildgraph/transformer.cpp b/src/lib/corelib/buildgraph/transformer.cpp index cc0b4c923..29f2bcdf0 100644 --- a/src/lib/corelib/buildgraph/transformer.cpp +++ b/src/lib/corelib/buildgraph/transformer.cpp @@ -62,9 +62,7 @@ Transformer::Transformer() : alwaysRun(false) { } -Transformer::~Transformer() -{ -} +Transformer::~Transformer() = default; static QScriptValue js_baseName(QScriptContext *ctx, QScriptEngine *engine, const Artifact *artifact) @@ -196,7 +194,7 @@ void Transformer::setupInputs(QScriptValue targetScriptValue, const ArtifactSet targetScriptValue.setProperty(StringConstants::inputVar(), inputScriptValue); } -void Transformer::setupInputs(QScriptValue targetScriptValue) +void Transformer::setupInputs(const QScriptValue &targetScriptValue) { setupInputs(targetScriptValue, inputs, rule->module->name); } diff --git a/src/lib/corelib/buildgraph/transformer.h b/src/lib/corelib/buildgraph/transformer.h index 2f6a8e56d..8772ed868 100644 --- a/src/lib/corelib/buildgraph/transformer.h +++ b/src/lib/corelib/buildgraph/transformer.h @@ -95,7 +95,7 @@ public: const Artifact *artifact, const QString &defaultModuleName); ResolvedProductPtr product() const; - void setupInputs(QScriptValue targetScriptValue); + void setupInputs(const QScriptValue &targetScriptValue); void setupOutputs(QScriptValue targetScriptValue); void setupExplicitlyDependsOn(QScriptValue targetScriptValue); void createCommands(ScriptEngine *engine, const PrivateScriptFunction &script, diff --git a/src/lib/corelib/buildgraph/transformerchangetracking.cpp b/src/lib/corelib/buildgraph/transformerchangetracking.cpp index 505f0cbba..e44c31639 100644 --- a/src/lib/corelib/buildgraph/transformerchangetracking.cpp +++ b/src/lib/corelib/buildgraph/transformerchangetracking.cpp @@ -71,7 +71,7 @@ private: const char *context) const; bool isExportedModuleUpToDate(const QString &productName, const ExportedModule &module) const; bool areExportedModulesUpToDate( - const std::unordered_map<QString, ExportedModule> exportedModules) const; + const std::unordered_map<QString, ExportedModule> &exportedModules) const; const Artifact *getArtifact(const QString &filePath, const QString &productName) const; const ResolvedProduct *getProduct(const QString &name) const; @@ -207,7 +207,7 @@ bool TrafoChangeTracker::isExportedModuleUpToDate(const QString &productName, } bool TrafoChangeTracker::areExportedModulesUpToDate( - const std::unordered_map<QString, ExportedModule> exportedModules) const + const std::unordered_map<QString, ExportedModule> &exportedModules) const { for (const auto &kv : exportedModules) { if (!isExportedModuleUpToDate(kv.first, kv.second)) diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index bd44ac3ed..619c0f0e3 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -395,6 +395,8 @@ QbsLibrary { "buildgraphlocker.cpp", "buildgraphlocker.h", "buildoptions.cpp", + "clangclinfo.cpp", + "clangclinfo.h", "cleanoptions.cpp", "codelocation.cpp", "commandechomode.cpp", diff --git a/src/lib/corelib/generators/generatordata.h b/src/lib/corelib/generators/generatordata.h index da65815ad..fd9bdde31 100644 --- a/src/lib/corelib/generators/generatordata.h +++ b/src/lib/corelib/generators/generatordata.h @@ -99,7 +99,7 @@ template <typename U> struct IMultiplexableContainer { } protected: - IMultiplexableContainer() { } + IMultiplexableContainer() = default; }; struct QBS_EXPORT GeneratableProductData : public IMultiplexableContainer<ProductData> { @@ -114,7 +114,7 @@ struct QBS_EXPORT GeneratableProjectData : public IMultiplexableContainer<Projec struct Id { private: friend struct GeneratableProjectData; - Id() { } + Id() = default; QString value; public: diff --git a/src/lib/corelib/generators/generatorutils.h b/src/lib/corelib/generators/generatorutils.h index 9348ab18c..58e59cbf8 100644 --- a/src/lib/corelib/generators/generatorutils.h +++ b/src/lib/corelib/generators/generatorutils.h @@ -41,14 +41,17 @@ namespace gen { namespace utils { enum class Architecture { - Arm, - Avr, - Mcs51, - Stm8, - Msp430, - Unknown + Unknown = 0, + Arm = 1 << 1, + Avr = 1 << 2, + Mcs51 = 1 << 3, + Stm8 = 1 << 4, + Msp430 = 1 << 5 }; +Q_DECLARE_FLAGS(ArchitectureFlags, Architecture) +Q_DECLARE_OPERATORS_FOR_FLAGS(ArchitectureFlags) + QBS_EXPORT QString architectureName(Architecture arch); QBS_EXPORT Architecture architecture(const Project &qbsProject); QBS_EXPORT QString buildConfigurationName(const Project &qbsProject); diff --git a/src/lib/corelib/generators/generatorversioninfo.cpp b/src/lib/corelib/generators/generatorversioninfo.cpp index 3e2106b57..c5c8db03f 100644 --- a/src/lib/corelib/generators/generatorversioninfo.cpp +++ b/src/lib/corelib/generators/generatorversioninfo.cpp @@ -42,42 +42,10 @@ namespace qbs { namespace gen { -VersionInfo::VersionInfo(const Version &version, - const std::set<utils::Architecture> &archs) - : m_version(version), m_archs(archs) -{ -} - -bool VersionInfo::operator<(const VersionInfo &other) const -{ - return m_version < other.m_version; -} - -bool VersionInfo::operator==(const VersionInfo &other) const -{ - return m_version == other.m_version - && m_archs == other.m_archs; -} - -Version VersionInfo::version() const -{ - return m_version; -} - -bool VersionInfo::containsArchitecture(utils::Architecture arch) const -{ - return m_archs.find(arch) != m_archs.cend(); -} - int VersionInfo::marketingVersion() const { return m_version.majorVersion(); } -quint32 qHash(const VersionInfo &info) -{ - return qHash(info.version().toString()); -} - } // namespace gen } // namespace qbs diff --git a/src/lib/corelib/generators/generatorversioninfo.h b/src/lib/corelib/generators/generatorversioninfo.h index 65bfcf685..38616eb98 100644 --- a/src/lib/corelib/generators/generatorversioninfo.h +++ b/src/lib/corelib/generators/generatorversioninfo.h @@ -45,7 +45,7 @@ #include <tools/qbs_export.h> #include <tools/version.h> -#include <set> +#include <QFlags> namespace qbs { namespace gen { @@ -53,24 +53,31 @@ namespace gen { class QBS_EXPORT VersionInfo { public: - VersionInfo(const Version &version, - const std::set<utils::Architecture> &archs); - virtual ~VersionInfo() = default; + constexpr VersionInfo(const Version &version, utils::ArchitectureFlags archs) + : m_version(version), m_archs(archs) + { + } - bool operator<(const VersionInfo &other) const; - bool operator==(const VersionInfo &other) const; + constexpr bool operator<(const VersionInfo &other) const { return m_version < other.m_version; } + constexpr bool operator==(const VersionInfo &other) const + { + return m_version == other.m_version && m_archs == other.m_archs; + } - Version version() const; - bool containsArchitecture(utils::Architecture arch) const; + constexpr Version version() const { return m_version; } + constexpr bool containsArchitecture(utils::Architecture arch) const { return m_archs & arch; } - virtual int marketingVersion() const; + int marketingVersion() const; private: Version m_version; - std::set<utils::Architecture> m_archs; + utils::ArchitectureFlags m_archs; }; -quint32 qHash(const VersionInfo &info); +inline quint32 qHash(const VersionInfo &info) +{ + return qHash(info.version().toString()); +} } // namespace gen } // namespace qbs diff --git a/src/lib/corelib/generators/igeneratableprojectvisitor.h b/src/lib/corelib/generators/igeneratableprojectvisitor.h index c3bd28580..dbf73b4e0 100644 --- a/src/lib/corelib/generators/igeneratableprojectvisitor.h +++ b/src/lib/corelib/generators/igeneratableprojectvisitor.h @@ -46,7 +46,7 @@ namespace qbs { class IGeneratableProjectVisitor { public: - virtual ~IGeneratableProjectVisitor() { } + virtual ~IGeneratableProjectVisitor() = default; // Collapsed configurations virtual void visitProject(const GeneratableProject &project) { diff --git a/src/lib/corelib/generators/ixmlnodevisitor.h b/src/lib/corelib/generators/ixmlnodevisitor.h index d3d118975..278f4cf2e 100644 --- a/src/lib/corelib/generators/ixmlnodevisitor.h +++ b/src/lib/corelib/generators/ixmlnodevisitor.h @@ -47,7 +47,7 @@ class Workspace; class QBS_EXPORT INodeVisitor { public: - virtual ~INodeVisitor() {} + virtual ~INodeVisitor() = default; virtual void visitWorkspaceStart(const Workspace *workspace) { Q_UNUSED(workspace) } virtual void visitWorkspaceEnd(const Workspace *workspace) { Q_UNUSED(workspace) } diff --git a/src/lib/corelib/generators/xmlprojectwriter.cpp b/src/lib/corelib/generators/xmlprojectwriter.cpp index 5554e5935..190e1304f 100644 --- a/src/lib/corelib/generators/xmlprojectwriter.cpp +++ b/src/lib/corelib/generators/xmlprojectwriter.cpp @@ -33,6 +33,7 @@ #include "xmlproperty.h" #include "xmlpropertygroup.h" +#include <memory> #include <ostream> namespace qbs { @@ -42,7 +43,7 @@ namespace xml { ProjectWriter::ProjectWriter(std::ostream *device) : m_device(device) { - m_writer.reset(new QXmlStreamWriter(&m_buffer)); + m_writer = std::make_unique<QXmlStreamWriter>(&m_buffer); m_writer->setAutoFormatting(true); } diff --git a/src/lib/corelib/generators/xmlpropertygroup.cpp b/src/lib/corelib/generators/xmlpropertygroup.cpp index 398d68e77..c9e6a97c1 100644 --- a/src/lib/corelib/generators/xmlpropertygroup.cpp +++ b/src/lib/corelib/generators/xmlpropertygroup.cpp @@ -45,10 +45,9 @@ void PropertyGroup::appendProperty(QByteArray name, QVariant value) appendChild<Property>(std::move(name), std::move(value)); } -void PropertyGroup::appendMultiLineProperty( - QByteArray key, QStringList values, QChar sep) +void PropertyGroup::appendMultiLineProperty(QByteArray key, const QStringList &values, QChar sep) { - const auto line = values.join(std::move(sep)); + const auto line = values.join(sep); appendProperty(std::move(key), QVariant::fromValue(line)); } diff --git a/src/lib/corelib/generators/xmlpropertygroup.h b/src/lib/corelib/generators/xmlpropertygroup.h index e63b515fc..e7e051a87 100644 --- a/src/lib/corelib/generators/xmlpropertygroup.h +++ b/src/lib/corelib/generators/xmlpropertygroup.h @@ -52,7 +52,7 @@ public: explicit PropertyGroup(QByteArray name); void appendProperty(QByteArray name, QVariant value); - void appendMultiLineProperty(QByteArray key, QStringList values, + void appendMultiLineProperty(QByteArray key, const QStringList &values, QChar sep = QLatin1Char(',')); void accept(INodeVisitor *visitor) const final; diff --git a/src/lib/corelib/generators/xmlworkspacewriter.cpp b/src/lib/corelib/generators/xmlworkspacewriter.cpp index c88cb06d0..d21b63c42 100644 --- a/src/lib/corelib/generators/xmlworkspacewriter.cpp +++ b/src/lib/corelib/generators/xmlworkspacewriter.cpp @@ -33,6 +33,7 @@ #include "xmlworkspace.h" #include "xmlworkspacewriter.h" +#include <memory> #include <ostream> namespace qbs { @@ -42,7 +43,7 @@ namespace xml { WorkspaceWriter::WorkspaceWriter(std::ostream *device) : m_device(device) { - m_writer.reset(new QXmlStreamWriter(&m_buffer)); + m_writer = std::make_unique<QXmlStreamWriter>(&m_buffer); m_writer->setAutoFormatting(true); } diff --git a/src/lib/corelib/jsextensions/binaryfile.cpp b/src/lib/corelib/jsextensions/binaryfile.cpp index 5f28f689b..f02f0bff6 100644 --- a/src/lib/corelib/jsextensions/binaryfile.cpp +++ b/src/lib/corelib/jsextensions/binaryfile.cpp @@ -235,7 +235,7 @@ void BinaryFile::write(const QVariantList &data) QByteArray bytes; std::for_each(data.constBegin(), data.constEnd(), [&bytes](const QVariant &v) { - bytes.append(v.toUInt() & 0xFF); }); + bytes.append(char(v.toUInt() & 0xFF)); }); const qint64 size = m_file->write(bytes); if (Q_UNLIKELY(size == -1)) { diff --git a/src/lib/corelib/jsextensions/domxml.cpp b/src/lib/corelib/jsextensions/domxml.cpp index 118e8d5e1..86e1574c6 100644 --- a/src/lib/corelib/jsextensions/domxml.cpp +++ b/src/lib/corelib/jsextensions/domxml.cpp @@ -85,7 +85,7 @@ public: Q_INVOKABLE QScriptValue previousSibling(const QString & tagName = QString()) const; Q_INVOKABLE QScriptValue nextSibling(const QString & tagName = QString()) const; - Q_INVOKABLE QScriptValue appendChild(QScriptValue newChild); + Q_INVOKABLE QScriptValue appendChild(const QScriptValue &newChild); Q_INVOKABLE QScriptValue insertBefore(const QScriptValue& newChild, const QScriptValue& refChild); Q_INVOKABLE QScriptValue insertAfter(const QScriptValue& newChild, const QScriptValue& refChild); Q_INVOKABLE QScriptValue replaceChild(const QScriptValue& newChild, const QScriptValue& oldChild); @@ -314,7 +314,6 @@ void XmlDomNode::setData(const QString &v) const if (m_domNode.isCharacterData()) return m_domNode.toCharacterData().setData(v); context()->throwError(QStringLiteral("Node '%1' is not a character data node").arg(m_domNode.nodeName())); - return; } void XmlDomNode::clear() @@ -365,7 +364,7 @@ QScriptValue XmlDomNode::nextSibling(const QString &tagName) const return engine()->newQObject(new XmlDomNode(m_domNode.nextSiblingElement(tagName)), QScriptEngine::ScriptOwnership); } -QScriptValue XmlDomNode::appendChild(QScriptValue newChild) +QScriptValue XmlDomNode::appendChild(const QScriptValue &newChild) { auto newNode = qobject_cast<XmlDomNode*>(newChild.toQObject()); if (!newNode) { diff --git a/src/lib/corelib/jsextensions/fileinfoextension.cpp b/src/lib/corelib/jsextensions/fileinfoextension.cpp index 0f2570ed0..038f3db41 100644 --- a/src/lib/corelib/jsextensions/fileinfoextension.cpp +++ b/src/lib/corelib/jsextensions/fileinfoextension.cpp @@ -53,6 +53,16 @@ namespace qbs { namespace Internal { +// removes duplicate separators from the path +static QString uniqueSeparators(QString path) +{ + const auto it = std::unique(path.begin(), path.end(), [](QChar c1, QChar c2) { + return c1 == c2 && c1 == QLatin1Char('/'); + }); + path.resize(int(it - path.begin())); + return path; +} + class FileInfoExtension : public QObject, QScriptable { Q_OBJECT @@ -268,9 +278,7 @@ QScriptValue FileInfoExtension::js_joinPaths(QScriptContext *context, QScriptEng paths.push_back(arg); } } - return engine->toScriptValue(QString::fromStdString( - std::regex_replace(paths.join(QLatin1Char('/')).toStdString(), - std::regex("/{2,}"), std::string("/")))); + return engine->toScriptValue(uniqueSeparators(paths.join(QLatin1Char('/')))); } } // namespace Internal diff --git a/src/lib/corelib/jsextensions/jsextensions.cpp b/src/lib/corelib/jsextensions/jsextensions.cpp index e5fbd3de8..052fb79e4 100644 --- a/src/lib/corelib/jsextensions/jsextensions.cpp +++ b/src/lib/corelib/jsextensions/jsextensions.cpp @@ -75,7 +75,7 @@ static InitializerMap &initializers() return theMap; } -void JsExtensions::setupExtensions(const QStringList &names, QScriptValue scope) +void JsExtensions::setupExtensions(const QStringList &names, const QScriptValue &scope) { for (const QString &name : names) initializers().value(name)(scope); diff --git a/src/lib/corelib/jsextensions/jsextensions.h b/src/lib/corelib/jsextensions/jsextensions.h index 8977dbe8a..f1ebfbdc3 100644 --- a/src/lib/corelib/jsextensions/jsextensions.h +++ b/src/lib/corelib/jsextensions/jsextensions.h @@ -54,7 +54,7 @@ namespace Internal { class JsExtensions { public: - static void setupExtensions(const QStringList &names, QScriptValue scope); + static void setupExtensions(const QStringList &names, const QScriptValue &scope); static QScriptValue loadExtension(QScriptEngine *engine, const QString &name); static bool hasExtension(const QString &name); static QStringList extensionNames(); diff --git a/src/lib/corelib/jsextensions/moduleproperties.cpp b/src/lib/corelib/jsextensions/moduleproperties.cpp index c0fd8ca84..f721e0016 100644 --- a/src/lib/corelib/jsextensions/moduleproperties.cpp +++ b/src/lib/corelib/jsextensions/moduleproperties.cpp @@ -195,7 +195,7 @@ static QScriptValue js_moduleDependencies(QScriptContext *, ScriptEngine *engine QScriptValue result = engine->newArray(); quint32 idx = 0; for (const QString &depName : qAsConst(module->moduleDependencies)) { - for (const ResolvedModuleConstPtr &dep : module->product->modules) { + for (const auto &dep : module->product->modules) { if (dep->name != depName) continue; QScriptValue obj = engine->newObject(engine->modulePropertyScriptClass()); diff --git a/src/lib/corelib/jsextensions/propertylist.mm b/src/lib/corelib/jsextensions/propertylist.mm index 6ac9d56c9..2ae422c41 100644 --- a/src/lib/corelib/jsextensions/propertylist.mm +++ b/src/lib/corelib/jsextensions/propertylist.mm @@ -95,7 +95,7 @@ public: QVariant propertyListObject; int propertyListFormat; - void readFromData(QScriptContext *context, QByteArray data); + void readFromData(QScriptContext *context, const QByteArray &data); QByteArray writeToData(QScriptContext *context, const QString &format); }; @@ -263,7 +263,7 @@ QString PropertyList::toJSON(const QString &style) const namespace qbs { namespace Internal { -void PropertyListPrivate::readFromData(QScriptContext *context, QByteArray data) +void PropertyListPrivate::readFromData(QScriptContext *context, const QByteArray &data) { @autoreleasepool { NSPropertyListFormat format; diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp index b425bb4a2..6c693cb61 100644 --- a/src/lib/corelib/jsextensions/utilitiesextension.cpp +++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp @@ -72,6 +72,7 @@ struct fat_arch_64 { #ifdef Q_OS_WIN +#include <tools/clangclinfo.h> #include <tools/msvcinfo.h> #include <tools/vsenvironmentdetector.h> #endif @@ -88,6 +89,10 @@ struct fat_arch_64 { namespace qbs { namespace Internal { +class DummyLogSink : public ILogSink { + void doPrintMessage(LoggerLevel, const QString &, const QString &) override { } +}; + class UtilitiesExtension : public QObject, QScriptable { Q_OBJECT @@ -110,6 +115,8 @@ public: static QScriptValue js_signingIdentities(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_clangClCompilerInfo(QScriptContext *context, QScriptEngine *engine); + static QScriptValue js_installedMSVCs(QScriptContext *context, QScriptEngine *engine); + static QScriptValue js_installedClangCls(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_versionCompare(QScriptContext *context, QScriptEngine *engine); @@ -132,7 +139,7 @@ QScriptValue UtilitiesExtension::js_canonicalPlatform(QScriptContext *context, { const QScriptValue value = context->argument(0); if (value.isUndefined() || value.isNull()) - return value; + return engine->toScriptValue(QStringList()); if (context->argumentCount() == 1 && value.isString()) { return engine->toScriptValue([&value] { @@ -529,7 +536,11 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context, QStringLiteral("clangClCompilerInfo expects 4 arguments")); const QString compilerFilePath = context->argument(0).toString(); - QString arch = context->argument(1).toString(); + // architecture cannot be empty as vcvarsall.bat requires at least 1 arg, so fallback + // to host architecture if none is present + QString arch = !context->argument(1).isNull() && !context->argument(1).isUndefined() + ? context->argument(1).toString() + : QString::fromStdString(HostOsInfo::hostOSArchitecture()); QString vcvarsallPath = context->argument(2).toString(); const QString compilerLanguage = context->argumentCount() > 3 ? context->argument(3).toString() @@ -551,6 +562,67 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context, #endif } +QScriptValue UtilitiesExtension::js_installedMSVCs(QScriptContext *context, QScriptEngine *engine) +{ +#ifndef Q_OS_WIN + Q_UNUSED(engine); + return context->throwError(QScriptContext::UnknownError, + QStringLiteral("installedMSVCs is not available on this platform")); +#else + if (Q_UNLIKELY(context->argumentCount() != 1)) { + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("installedMSVCs expects 1 arguments")); + } + + const auto value0 = context->argument(0); + const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture()); + const auto preferredArch = !value0.isNull() && !value0.isUndefined() + ? value0.toString() + : hostArch; + + DummyLogSink dummySink; + Logger dummyLogger(&dummySink); + auto msvcs = MSVC::installedCompilers(dummyLogger); + + const auto predicate = [&preferredArch, &hostArch](const MSVC &msvc) + { + auto archPair = MSVC::getHostTargetArchPair(msvc.architecture); + return archPair.first != hostArch || preferredArch != archPair.second; + }; + msvcs.erase(std::remove_if(msvcs.begin(), msvcs.end(), predicate), msvcs.end()); + QVariantList result; + for (const auto &msvc: msvcs) + result.append(msvc.toVariantMap()); + return engine->toScriptValue(result); +#endif +} + +QScriptValue UtilitiesExtension::js_installedClangCls( + QScriptContext *context, QScriptEngine *engine) +{ +#ifndef Q_OS_WIN + Q_UNUSED(engine); + return context->throwError(QScriptContext::UnknownError, + QStringLiteral("installedClangCls is not available on this platform")); +#else + if (Q_UNLIKELY(context->argumentCount() != 1)) { + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("installedClangCls expects 1 arguments")); + } + + const auto value0 = context->argument(0); + const auto path = !value0.isNull() && !value0.isUndefined() ? value0.toString() : QString(); + + DummyLogSink dummySink; + Logger dummyLogger(&dummySink); + auto compilers = ClangClInfo::installedCompilers({path}, dummyLogger); + QVariantList result; + for (const auto &compiler: compilers) + result.append(compiler.toVariantMap()); + return engine->toScriptValue(result); +#endif +} + QScriptValue UtilitiesExtension::js_versionCompare(QScriptContext *context, QScriptEngine *engine) { if (context->argumentCount() == 2) { @@ -851,6 +923,10 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject) engine->newFunction(UtilitiesExtension::js_msvcCompilerInfo, 1)); environmentObj.setProperty(QStringLiteral("clangClCompilerInfo"), engine->newFunction(UtilitiesExtension::js_clangClCompilerInfo, 1)); + environmentObj.setProperty(QStringLiteral("installedMSVCs"), + engine->newFunction(UtilitiesExtension::js_installedMSVCs, 1)); + environmentObj.setProperty(QStringLiteral("installedClangCls"), + engine->newFunction(UtilitiesExtension::js_installedClangCls, 1)); environmentObj.setProperty(QStringLiteral("versionCompare"), engine->newFunction(UtilitiesExtension::js_versionCompare, 2)); environmentObj.setProperty(QStringLiteral("qmlTypeInfo"), diff --git a/src/lib/corelib/language/artifactproperties.cpp b/src/lib/corelib/language/artifactproperties.cpp index dd61bf1a2..011e58d88 100644 --- a/src/lib/corelib/language/artifactproperties.cpp +++ b/src/lib/corelib/language/artifactproperties.cpp @@ -48,9 +48,7 @@ ArtifactPropertiesPtr ArtifactProperties::create() return ArtifactPropertiesPtr(new ArtifactProperties); } -ArtifactProperties::ArtifactProperties() -{ -} +ArtifactProperties::ArtifactProperties() = default; FileTags ArtifactProperties::extraFileTags() const { @@ -66,6 +64,7 @@ bool operator==(const ArtifactProperties &ap1, const ArtifactProperties &ap2) { return ap1.fileTagsFilter() == ap2.fileTagsFilter() && ap1.extraFileTags() == ap2.extraFileTags() + && !ap1.propertyMap() == !ap2.propertyMap() && *ap1.propertyMap() == *ap2.propertyMap(); } diff --git a/src/lib/corelib/language/asttools.cpp b/src/lib/corelib/language/asttools.cpp index 617c8b95b..1b6abac7f 100644 --- a/src/lib/corelib/language/asttools.cpp +++ b/src/lib/corelib/language/asttools.cpp @@ -61,13 +61,13 @@ QString textOf(const QString &source, QbsQmlJS::AST::Node *node) if (!node) return {}; return source.mid(node->firstSourceLocation().begin(), - node->lastSourceLocation().end() - node->firstSourceLocation().begin()); + int(node->lastSourceLocation().end() - node->firstSourceLocation().begin())); } QStringRef textRefOf(const QString &source, QbsQmlJS::AST::Node *node) { const quint32 firstBegin = node->firstSourceLocation().begin(); - return source.midRef(firstBegin, node->lastSourceLocation().end() - firstBegin); + return source.midRef(firstBegin, int(node->lastSourceLocation().end() - firstBegin)); } } // namespace Internal diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp index 68355df51..13783d3b9 100644 --- a/src/lib/corelib/language/builtindeclarations.cpp +++ b/src/lib/corelib/language/builtindeclarations.cpp @@ -125,7 +125,7 @@ ItemDeclaration BuiltinDeclarations::declarationsForType(ItemType type) const } ItemType BuiltinDeclarations::typeForName(const QString &typeName, - const CodeLocation location) const + const CodeLocation &location) const { const auto it = m_typeMap.constFind(typeName); if (it == m_typeMap.constEnd()) diff --git a/src/lib/corelib/language/builtindeclarations.h b/src/lib/corelib/language/builtindeclarations.h index 988f9ab81..9d7aee982 100644 --- a/src/lib/corelib/language/builtindeclarations.h +++ b/src/lib/corelib/language/builtindeclarations.h @@ -62,7 +62,7 @@ public: QStringList allTypeNames() const; ItemDeclaration declarationsForType(ItemType type) const; ItemType typeForName(const QString &typeName, - const CodeLocation location = CodeLocation()) const; + const CodeLocation &location = CodeLocation()) const; QString nameForType(ItemType itemType) const; QStringList argumentNamesForScriptFunction(ItemType itemType, const QString &scriptName) const; diff --git a/src/lib/corelib/language/deprecationinfo.h b/src/lib/corelib/language/deprecationinfo.h index 502715b84..89cd07f4a 100644 --- a/src/lib/corelib/language/deprecationinfo.h +++ b/src/lib/corelib/language/deprecationinfo.h @@ -50,11 +50,11 @@ class DeprecationInfo { public: explicit DeprecationInfo(const Version &removalVersion, - const QString &additionalUserInfo = QString()) + QString additionalUserInfo = QString()) : m_removalVersion(removalVersion) - , m_additionalUserInfo(additionalUserInfo) + , m_additionalUserInfo(std::move(additionalUserInfo)) {} - DeprecationInfo() {} + DeprecationInfo() = default; bool isValid() const { return m_removalVersion.isValid(); } Version removalVersion() const { return m_removalVersion; } diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h index d8931a37e..f8535d0d7 100644 --- a/src/lib/corelib/language/evaluator.h +++ b/src/lib/corelib/language/evaluator.h @@ -64,7 +64,7 @@ class QBS_AUTOTEST_EXPORT Evaluator : private ItemObserver public: Evaluator(ScriptEngine *scriptEngine); - virtual ~Evaluator(); + ~Evaluator() override; ScriptEngine *engine() const { return m_scriptEngine; } QScriptValue property(const Item *item, const QString &name); diff --git a/src/lib/corelib/language/identifiersearch.cpp b/src/lib/corelib/language/identifiersearch.cpp index 973aae6a8..49ceab36c 100644 --- a/src/lib/corelib/language/identifiersearch.cpp +++ b/src/lib/corelib/language/identifiersearch.cpp @@ -43,9 +43,7 @@ namespace qbs { namespace Internal { -IdentifierSearch::IdentifierSearch() -{ -} +IdentifierSearch::IdentifierSearch() = default; void IdentifierSearch::start(QbsQmlJS::AST::Node *node) { diff --git a/src/lib/corelib/language/item.cpp b/src/lib/corelib/language/item.cpp index 9f754bdd7..a86cfeac1 100644 --- a/src/lib/corelib/language/item.cpp +++ b/src/lib/corelib/language/item.cpp @@ -203,15 +203,15 @@ bool Item::isOfTypeOrhasParentOfType(ItemType type) const PropertyDeclaration Item::propertyDeclaration(const QString &name, bool allowExpired) const { - PropertyDeclaration decl = m_propertyDeclarations.value(name); - if (decl.isValid()) - return decl; + auto it = m_propertyDeclarations.find(name); + if (it != m_propertyDeclarations.end()) + return it.value(); if (allowExpired) { - decl = m_expiredPropertyDeclarations.value(name); - if (decl.isValid()) - return decl; + it = m_expiredPropertyDeclarations.find(name); + if (it != m_expiredPropertyDeclarations.end()) + return it.value(); } - return m_prototype ? m_prototype->propertyDeclaration(name) : decl; + return m_prototype ? m_prototype->propertyDeclaration(name) : PropertyDeclaration(); } void Item::addModule(const Item::Module &module) diff --git a/src/lib/corelib/language/itempool.cpp b/src/lib/corelib/language/itempool.cpp index 3da8b947b..ccd22fe2e 100644 --- a/src/lib/corelib/language/itempool.cpp +++ b/src/lib/corelib/language/itempool.cpp @@ -43,9 +43,7 @@ namespace qbs { namespace Internal { -ItemPool::ItemPool() -{ -} +ItemPool::ItemPool() = default; ItemPool::~ItemPool() { diff --git a/src/lib/corelib/language/itemreadervisitorstate.cpp b/src/lib/corelib/language/itemreadervisitorstate.cpp index ca6ba2e12..20ddb5cfb 100644 --- a/src/lib/corelib/language/itemreadervisitorstate.cpp +++ b/src/lib/corelib/language/itemreadervisitorstate.cpp @@ -81,10 +81,7 @@ public: { } - ASTCacheValue(const ASTCacheValue &other) - : d(other.d) - { - } + ASTCacheValue(const ASTCacheValue &other) = default; void setProcessingFlag(bool b) { d->processing = b; } bool isProcessing() const { return d->processing; } diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp index 40549b836..3b3e7401e 100644 --- a/src/lib/corelib/language/language.cpp +++ b/src/lib/corelib/language/language.cpp @@ -188,15 +188,9 @@ void ResolvedGroup::store(PersistentPool &pool) * \sa Rule */ -ScriptFunction::ScriptFunction() -{ - -} - -ScriptFunction::~ScriptFunction() -{ +ScriptFunction::ScriptFunction() = default; -} +ScriptFunction::~ScriptFunction() = default; /*! * \variable ScriptFunction::script @@ -282,7 +276,7 @@ QString Rule::toString() const FileTags Rule::staticOutputFileTags() const { FileTags result; - for (const RuleArtifactConstPtr &artifact : artifacts) + for (const auto &artifact : artifacts) result.unite(artifact->fileTags); return result; } @@ -312,9 +306,7 @@ ResolvedProduct::ResolvedProduct() { } -ResolvedProduct::~ResolvedProduct() -{ -} +ResolvedProduct::~ResolvedProduct() = default; void ResolvedProduct::accept(BuildGraphVisitor *visitor) const { @@ -331,7 +323,7 @@ void ResolvedProduct::accept(BuildGraphVisitor *visitor) const std::vector<SourceArtifactPtr> ResolvedProduct::allFiles() const { std::vector<SourceArtifactPtr> lst; - for (const GroupConstPtr &group : groups) + for (const auto &group : groups) lst << group->allFiles(); return lst; } @@ -343,7 +335,7 @@ std::vector<SourceArtifactPtr> ResolvedProduct::allFiles() const std::vector<SourceArtifactPtr> ResolvedProduct::allEnabledFiles() const { std::vector<SourceArtifactPtr> lst; - for (const GroupConstPtr &group : groups) { + for (const auto &group : groups) { if (group->enabled) lst << group->allFiles(); } @@ -364,7 +356,7 @@ FileTags ResolvedProduct::fileTagsForFileName(const QString &fileName) const return result; } } else { - priority.reset(new int(tagger->priority())); + priority = std::make_unique<int>(tagger->priority()); } result.unite(tagger->fileTags()); break; @@ -524,9 +516,7 @@ ResolvedProject::ResolvedProject() : enabled(true), m_topLevelProject(nullptr) { } -ResolvedProject::~ResolvedProject() -{ -} +ResolvedProject::~ResolvedProject() = default; void ResolvedProject::accept(BuildGraphVisitor *visitor) const { @@ -551,7 +541,7 @@ TopLevelProject *ResolvedProject::topLevelProject() std::vector<ResolvedProjectPtr> ResolvedProject::allSubProjects() const { std::vector<ResolvedProjectPtr> projectList = subProjects; - for (const ResolvedProjectConstPtr &subProject : subProjects) + for (const auto &subProject : subProjects) projectList << subProject->allSubProjects(); return projectList; } @@ -559,7 +549,7 @@ std::vector<ResolvedProjectPtr> ResolvedProject::allSubProjects() const std::vector<ResolvedProductPtr> ResolvedProject::allProducts() const { std::vector<ResolvedProductPtr> productList = products; - for (const ResolvedProjectConstPtr &subProject : qAsConst(subProjects)) + for (const auto &subProject : qAsConst(subProjects)) productList << subProject->allProducts(); return productList; } @@ -765,7 +755,7 @@ void SourceWildCards::expandPatterns(Set<QString> &result, const GroupConstPtr & if (baseDir.startsWith(buildDir)) return; - dirTimeStamps.push_back({ baseDir, FileInfo(baseDir).lastModified() }); + dirTimeStamps.emplace_back(baseDir, FileInfo(baseDir).lastModified()); QStringList changed_parts = parts; bool recursive = false; @@ -810,7 +800,7 @@ void SourceWildCards::expandPatterns(Set<QString> &result, const GroupConstPtr & expandPatterns(result, group, changed_parts, filePath, buildDir); } else { if (parentDir != baseDir) - dirTimeStamps.push_back({parentDir, FileInfo(baseDir).lastModified()}); + dirTimeStamps.emplace_back(parentDir, FileInfo(baseDir).lastModified()); result += QDir::cleanPath(filePath); } } @@ -867,6 +857,7 @@ bool operator==(const SourceArtifactInternal &sa1, const SourceArtifactInternal && sa1.fileTags == sa2.fileTags && sa1.overrideFileTags == sa2.overrideFileTags && sa1.targetOfModule == sa2.targetOfModule + && !sa1.properties == !sa2.properties && *sa1.properties == *sa2.properties; } diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h index 65879dd56..bbd851333 100644 --- a/src/lib/corelib/language/language.h +++ b/src/lib/corelib/language/language.h @@ -99,7 +99,7 @@ public: private: FileTagger(const QStringList &patterns, FileTags fileTags, int priority); - FileTagger() {} + FileTagger() = default; void setPatterns(const QStringList &patterns); @@ -139,20 +139,20 @@ public: } private: - Probe() {} - Probe(const QString &globalId, + Probe() = default; + Probe(QString globalId, const CodeLocation &location, bool condition, - const QString &configureScript, - const QVariantMap &properties, - const QVariantMap &initialProperties, - const std::vector<QString> &importedFilesUsed) - : m_globalId(globalId) + QString configureScript, + QVariantMap properties, + QVariantMap initialProperties, + std::vector<QString> importedFilesUsed) + : m_globalId(std::move(globalId)) , m_location(location) - , m_configureScript(configureScript) - , m_properties(properties) - , m_initialProperties(initialProperties) - , m_importedFilesUsed(importedFilesUsed) + , m_configureScript(std::move(configureScript)) + , m_properties(std::move(properties)) + , m_initialProperties(std::move(initialProperties)) + , m_importedFilesUsed(std::move(importedFilesUsed)) , m_condition(condition) {} @@ -378,7 +378,7 @@ public: } private: - ResolvedModule() {} + ResolvedModule() = default; }; bool operator==(const ResolvedModule &m1, const ResolvedModule &m2); inline bool operator!=(const ResolvedModule &m1, const ResolvedModule &m2) { return !(m1 == m2); } diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index 9c8f9da1d..56fbc198e 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -71,20 +71,24 @@ #include <QtCore/qdebug.h> #include <QtCore/qdir.h> +#include <QtCore/qglobalstatic.h> #include <QtCore/qdiriterator.h> #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> #include <QtCore/qtemporaryfile.h> #include <QtCore/qtextstream.h> +#include <QtCore/qthreadstorage.h> #include <QtScript/qscriptvalueiterator.h> #include <algorithm> +#include <memory> #include <utility> namespace qbs { namespace Internal { -static QString shadowProductPrefix() { return QStringLiteral("__shadow__"); } +using MultiplexConfigurationByIdTable = QThreadStorage<QHash<QString, QVariantMap> >; +Q_GLOBAL_STATIC(MultiplexConfigurationByIdTable, multiplexConfigurationsById); static void handlePropertyError(const ErrorInfo &error, const SetupProjectParameters ¶ms, Logger &logger) @@ -94,6 +98,20 @@ static void handlePropertyError(const ErrorInfo &error, const SetupProjectParame logger.printWarning(error); } +static bool multiplexConfigurationIntersects(const QVariantMap &lhs, const QVariantMap &rhs) +{ + QBS_CHECK(!lhs.isEmpty() && !rhs.isEmpty()); + + for (auto lhsProperty = lhs.constBegin(); lhsProperty != lhs.constEnd(); lhsProperty++) { + const auto rhsProperty = rhs.find(lhsProperty.key()); + const bool isCommonProperty = rhsProperty != rhs.constEnd(); + if (isCommonProperty && lhsProperty.value() != rhsProperty.value()) + return false; + } + + return true; +} + class ModuleLoader::ItemModuleList : public QList<Item::Module> {}; static QString probeGlobalId(Item *probe) @@ -292,7 +310,7 @@ ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters ¶meters) = m_elapsedTimePropertyChecking = 0; m_elapsedTimeProbes = 0; m_probesEncountered = m_probesRun = m_probesCachedCurrent = m_probesCachedOld = 0; - m_settings.reset(new Settings(parameters.settingsDirectory())); + m_settings = std::make_unique<Settings>(parameters.settingsDirectory()); const auto keys = m_parameters.overriddenValues().keys(); for (const QString &key : keys) { @@ -381,9 +399,9 @@ class PropertyDeclarationCheck : public ValueHandler Logger &m_logger; public: PropertyDeclarationCheck(const Set<Item *> &disabledItems, - const SetupProjectParameters ¶ms, Logger &logger) + SetupProjectParameters params, Logger &logger) : m_disabledItems(disabledItems) - , m_params(params) + , m_params(std::move(params)) , m_logger(logger) { } @@ -616,7 +634,7 @@ void ModuleLoader::handleTopLevelProject(ModuleLoaderResult *loadResult, Item *p for (ProductContext * const p : productSorter.sortedProducts()) { try { handleProduct(p); - if (p->name.startsWith(shadowProductPrefix())) + if (p->name.startsWith(StringConstants::shadowProductPrefix())) tlp.probes << p->info.probes; } catch (const ErrorInfo &err) { handleProductError(err, p); @@ -688,6 +706,9 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, m_qbsVersion.toString())); } + for (Item * const child : projectItem->children()) + child->setScope(projectContext.scope); + resolveProbes(&dummyProductContext, projectItem); projectContext.topLevelProject->probes << dummyProductContext.info.probes; @@ -695,7 +716,6 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, QList<Item *> multiplexedProducts; for (Item * const child : projectItem->children()) { - child->setScope(projectContext.scope); if (child->type() == ItemType::Product) multiplexedProducts << multiplexProductItem(&dummyProductContext, child); } @@ -762,9 +782,24 @@ QString ModuleLoader::MultiplexInfo::toIdString(size_t row) const const VariantValuePtr &mpvalue = mprow.at(column); multiplexConfiguration.insert(propertyName, mpvalue->value()); } - return QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration) - .toJson(QJsonDocument::Compact) - .toBase64()); + QString id = QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration) + .toJson(QJsonDocument::Compact) + .toBase64()); + // Cache for later use in:multiplexIdToVariantMap() + multiplexConfigurationsById->localData().insert(id, multiplexConfiguration); + return id; +} + +QVariantMap ModuleLoader::MultiplexInfo::multiplexIdToVariantMap(const QString &multiplexId) +{ + if (multiplexId.isEmpty()) + return QVariantMap(); + + QVariantMap result = multiplexConfigurationsById->localData().value(multiplexId); + // We assume that MultiplexInfo::toIdString() has been called for this + // particular multiplex configuration. + QBS_CHECK(!result.isEmpty()); + return result; } void qbs::Internal::ModuleLoader::ModuleLoader::dump(const ModuleLoader::MultiplexInfo &mpi) @@ -1085,66 +1120,111 @@ void ModuleLoader::adjustDependenciesForMultiplexing(const ProductContext &produ StringConstants::profilesProperty(), &profilesPropertyIsSet); const auto productRange = m_productsByName.equal_range(name); - std::vector<const ProductContext *> dependencies; + if (productRange.first == productRange.second) { + // Dependency is a module. Nothing to adjust. + return; + } + + std::vector<const ProductContext *> multiplexedDependencies; bool hasNonMultiplexedDependency = false; for (auto it = productRange.first; it != productRange.second; ++it) { - if (!it->second->multiplexConfigurationId.isEmpty()) { - dependencies.push_back(it->second); - if (productIsMultiplexed && !profilesPropertyIsSet) - break; - } else { + if (!it->second->multiplexConfigurationId.isEmpty()) + multiplexedDependencies.push_back(it->second); + else hasNonMultiplexedDependency = true; - break; - } } + bool hasMultiplexedDependencies = !multiplexedDependencies.empty(); // These are the allowed cases: // (1) Normal dependency with no multiplexing whatsoever. // (2) Both product and dependency are multiplexed. + // (2a) The profiles property is not set, we want to depend on the best + // matching variant. + // (2b) The profiles property is set, we want to depend on all variants + // with a matching profile. // (3) The product is not multiplexed, but the dependency is. - // (3a) The dependency has an aggregator. We want to depend on the aggregator. - // (3b) The dependency does not have an aggregator. We want to depend on all the - // multiplexed variants. - // (4) The product is multiplexed, but the dependency is not. This case is implicitly - // handled, because we don't have to adapt any Depends items. + // (3a) The profiles property is not set, the dependency has an aggregator. + // We want to depend on the aggregator. + // (3b) The profiles property is not set, the dependency does not have an + // aggregator. We want to depend on all the multiplexed variants. + // (3c) The profiles property is set, we want to depend on all variants + // with a matching profile regardless of whether an aggregator exists or not. + // (4) The product is multiplexed, but the dependency is not. We don't have to adapt + // any Depends items. // (5) The product is a "shadow product". In that case, we know which product // it should have a dependency on, and we make sure we depend on that. - // (1) and (3a) - if (!productIsMultiplexed && hasNonMultiplexedDependency) + // (1) and (4) + if (!hasMultiplexedDependencies) + return; + + // (3a) + if (!productIsMultiplexed && hasNonMultiplexedDependency && !profilesPropertyIsSet) return; QStringList multiplexIds; const ShadowProductInfo shadowProductInfo = getShadowProductInfo(product); const bool isShadowProduct = shadowProductInfo.first && shadowProductInfo.second == name; - for (const ProductContext *dependency : dependencies) { + const auto productMultiplexConfig = + MultiplexInfo::multiplexIdToVariantMap(product.multiplexConfigurationId); + + for (const ProductContext *dependency : multiplexedDependencies) { const bool depMatchesShadowProduct = isShadowProduct && dependency->item == product.item->parent(); const QString depMultiplexId = dependency->multiplexConfigurationId; if (depMatchesShadowProduct) { // (5) dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), VariantValue::create(depMultiplexId)); - multiplexIds.clear(); - break; - } - if (productIsMultiplexed && !profilesPropertyIsSet) { // (2) - const ValuePtr &multiplexId = product.item->property( - StringConstants::multiplexConfigurationIdProperty()); - dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), - multiplexId); - break; + return; } + if (productIsMultiplexed && !profilesPropertyIsSet) { // 2a + if (dependency->multiplexConfigurationId == product.multiplexConfigurationId) { + const ValuePtr &multiplexId = product.item->property( + StringConstants::multiplexConfigurationIdProperty()); + dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), + multiplexId); + return; - // (3b) (or (2) if Depends.profiles is set). - const bool profileMatch = !profilesPropertyIsSet || profiles.empty() - || profiles.contains(dependency->profileName); - if (profileMatch) - multiplexIds << depMultiplexId; - } - if (!multiplexIds.empty()) { - dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), - VariantValue::create(multiplexIds)); + } else { + // Otherwise collect partial matches and decide later + const auto dependencyMultiplexConfig = + MultiplexInfo::multiplexIdToVariantMap(dependency->multiplexConfigurationId); + + if (multiplexConfigurationIntersects(dependencyMultiplexConfig, productMultiplexConfig)) + multiplexIds << dependency->multiplexConfigurationId; + } + } else { + // (2b), (3b) or (3c) + const bool profileMatch = !profilesPropertyIsSet || profiles.empty() + || profiles.contains(dependency->profileName); + if (profileMatch) + multiplexIds << depMultiplexId; + } } + if (multiplexIds.empty()) { + const QString productName = ResolvedProduct::fullDisplayName( + product.name, product.multiplexConfigurationId); + throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' not fulfilled. " + "There are no eligible multiplex candidates.").arg(productName, + name), + dependsItem->location()); + } + + // In case of (2a), at most 1 match is allowed + if (productIsMultiplexed && !profilesPropertyIsSet && multiplexIds.size() > 1) { + const QString productName = ResolvedProduct::fullDisplayName( + product.name, product.multiplexConfigurationId); + QStringList candidateNames; + for (const auto &id : qAsConst(multiplexIds)) + candidateNames << ResolvedProduct::fullDisplayName(name, id); + throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' is ambiguous. " + "Eligible multiplex candidates: %3.").arg( + productName, name, candidateNames.join(QLatin1String(", "))), + dependsItem->location()); + } + + dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), + VariantValue::create(multiplexIds)); } void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productItem) @@ -1216,7 +1296,8 @@ void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productI // evaluate the product's exported properties in isolation in the project resolver. Item * const importer = Item::create(productItem->pool(), ItemType::Product); importer->setProperty(QStringLiteral("name"), - VariantValue::create(shadowProductPrefix() + productContext.name)); + VariantValue::create(StringConstants::shadowProductPrefix() + + productContext.name)); importer->setFile(productItem->file()); importer->setLocation(productItem->location()); importer->setScope(projectContext->scope); @@ -1281,7 +1362,6 @@ void ModuleLoader::createSortedModuleList(const Item::Module &parentModule, Item for (const Item::Module &dep : parentModule.item->modules()) createSortedModuleList(dep, modules); modules.push_back(parentModule); - return; } Item::Modules ModuleLoader::modulesSortedByDependency(const Item *productItem) @@ -1350,8 +1430,7 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext) // set by the dependency module's merger (namely, scopes of defining items; see // ModuleMerger::replaceItemInScopes()). Item::Modules topSortedModules = modulesSortedByDependency(item); - for (Item::Module &module : topSortedModules) - ModuleMerger(m_logger, item, module).start(); + ModuleMerger::merge(m_logger, item, productContext->name, &topSortedModules); // Re-sort the modules by name. This is more stable; see QBS-818. // The list of modules in the product now has the same order as before, @@ -1585,7 +1664,7 @@ void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext const Item::PropertyMap &overriddenProperties = propertiesItem->properties(); for (Item::PropertyMap::ConstIterator it = overriddenProperties.constBegin(); it != overriddenProperties.constEnd(); ++it) { - loadedItem->setProperty(it.key(), overriddenProperties.value(it.key())); + loadedItem->setProperty(it.key(), it.value()); } } @@ -1806,7 +1885,7 @@ ProbeConstPtr ModuleLoader::findCurrentProbe( bool condition, const QVariantMap &initialProperties) const { - const QList<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location); + const std::vector<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location); for (const ProbeConstPtr &probe : cachedProbes) { if (probeMatches(probe, condition, initialProperties, QString(), CompareScript::No)) return probe; @@ -1964,7 +2043,7 @@ bool ModuleLoader::mergeExportItems(const ProductContext &productContext) productContext.project->topLevelProject->productModules.insert(productContext.name, pmi); if (hasDependenciesOnProductType) m_exportsWithDeferredDependsItems.insert(merged); - return exportItems.size() > 0; + return !exportItems.empty(); } Item *ModuleLoader::loadItemFromFile(const QString &filePath, @@ -2171,9 +2250,10 @@ void ModuleLoader::setSearchPathsForProduct(ModuleLoader::ProductContext *produc ModuleLoader::ShadowProductInfo ModuleLoader::getShadowProductInfo( const ModuleLoader::ProductContext &product) const { - const bool isShadowProduct = product.name.startsWith(shadowProductPrefix()); + const bool isShadowProduct = product.name.startsWith(StringConstants::shadowProductPrefix()); return std::make_pair(isShadowProduct, isShadowProduct - ? product.name.mid(shadowProductPrefix().size()) : QString()); + ? product.name.mid(StringConstants::shadowProductPrefix().size()) + : QString()); } void ModuleLoader::collectProductsByName(const TopLevelProjectContext &topLevelProject) @@ -2705,7 +2785,7 @@ void ModuleLoader::resolveParameterDeclarations(const Item *module) for (Item *param : moduleChildren) { if (param->type() != ItemType::Parameter) continue; - const auto paramDecls = param->propertyDeclarations(); + const auto ¶mDecls = param->propertyDeclarations(); for (auto it = paramDecls.begin(); it != paramDecls.end(); ++it) decls.insert(it.key(), it.value()); } @@ -2756,7 +2836,8 @@ QVariantMap ModuleLoader::extractParameters(Item *dependsItem) const QScriptValue sv = m_evaluator->scriptValue(dependsItem); try { result = safeToVariant(sv); - } catch (ErrorInfo ei) { + } catch (const ErrorInfo &exception) { + auto ei = exception; ei.prepend(Tr::tr("Error in dependency parameter."), dependsItem->location()); throw ei; } @@ -3024,72 +3105,67 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, FallbackMode fallbackMode, bool isRequired, Item *moduleInstance) { - bool triedToLoadModule = false; + auto existingPaths = findExistingModulePaths(m_reader->allSearchPaths(), moduleName); + + if (existingPaths.isEmpty()) { // no suitable names found, try to use providers + bool moduleAlreadyKnown = false; + ModuleProviderResult result; + for (QualifiedId providerName = moduleName; !providerName.empty(); + providerName.pop_back()) { + if (!productContext->knownModuleProviders.insert(providerName).second) { + moduleAlreadyKnown = true; + break; + } + qCDebug(lcModuleLoader) << "Module" << moduleName.toString() + << "not found, checking for module providers"; + result = findModuleProvider(providerName, *productContext, + ModuleProviderLookup::Regular, dependsItemLocation); + if (result.providerFound) + break; + } + if (fallbackMode == FallbackMode::Enabled && !result.providerFound + && !moduleAlreadyKnown) { + qCDebug(lcModuleLoader) << "Specific module provider not found for" + << moduleName.toString() << ", setting up fallback."; + result = findModuleProvider(moduleName, *productContext, + ModuleProviderLookup::Fallback, dependsItemLocation); + } + if (result.providerAddedSearchPaths) { + qCDebug(lcModuleLoader) << "Re-checking for module" << moduleName.toString() + << "with newly added search paths from module provider"; + existingPaths = findExistingModulePaths(m_reader->allSearchPaths(), moduleName); + } + } + const QString fullName = moduleName.toString(); + bool triedToLoadModule = false; std::vector<PrioritizedItem> candidates; - const QStringList &searchPaths = m_reader->allSearchPaths(); - bool matchingDirectoryFound = false; - for (int i = 0; i < searchPaths.size(); ++i) { - const QString &path = searchPaths.at(i); - const QString dirPath = findExistingModulePath(path, moduleName); - if (dirPath.isEmpty()) - continue; - matchingDirectoryFound = true; - QStringList moduleFileNames = m_moduleDirListCache.value(dirPath); - if (moduleFileNames.empty()) { - QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards()); - while (dirIter.hasNext()) - moduleFileNames += dirIter.next(); - - m_moduleDirListCache.insert(dirPath, moduleFileNames); - } - for (const QString &filePath : qAsConst(moduleFileNames)) { - triedToLoadModule = true; + candidates.reserve(size_t(existingPaths.size())); + for (int i = 0; i < existingPaths.size(); ++i) { + const QString &dirPath = existingPaths.at(i); + QStringList &moduleFileNames = getModuleFileNames(dirPath); + for (auto it = moduleFileNames.begin(); it != moduleFileNames.end(); ) { + const QString &filePath = *it; + bool triedToLoad = true; Item *module = loadModuleFile(productContext, fullName, isBaseModule(moduleName), - filePath, &triedToLoadModule, moduleInstance); + filePath, &triedToLoad, moduleInstance); if (module) candidates.emplace_back(module, 0, i); - if (!triedToLoadModule) - m_moduleDirListCache[dirPath].removeOne(filePath); + if (!triedToLoad) + it = moduleFileNames.erase(it); + else + ++it; + triedToLoadModule = triedToLoadModule || triedToLoad; } } if (candidates.empty()) { - if (!matchingDirectoryFound) { - bool moduleAlreadyKnown = false; - ModuleProviderResult result; - for (QualifiedId providerName = moduleName; !providerName.empty(); - providerName.pop_back()) { - if (!productContext->knownModuleProviders.insert(providerName).second) { - moduleAlreadyKnown = true; - break; - } - qCDebug(lcModuleLoader) << "Module" << moduleName.toString() - << "not found, checking for module providers"; - result = findModuleProvider(providerName, *productContext, - ModuleProviderLookup::Regular, dependsItemLocation); - if (result.providerFound) - break; - } - if (fallbackMode == FallbackMode::Enabled && !result.providerFound - && !moduleAlreadyKnown) { - qCDebug(lcModuleLoader) << "Specific module provider not found for" - << moduleName.toString() << ", setting up fallback."; - result = findModuleProvider(moduleName, *productContext, - ModuleProviderLookup::Fallback, dependsItemLocation); - } - if (result.providerAddedSearchPaths) { - qCDebug(lcModuleLoader) << "Re-checking for module" << moduleName.toString() - << "with newly added search paths from module provider"; - return searchAndLoadModuleFile(productContext, dependsItemLocation, moduleName, - fallbackMode, isRequired, moduleInstance); - } - } if (!isRequired) return createNonPresentModule(fullName, QStringLiteral("not found"), nullptr); - if (Q_UNLIKELY(triedToLoadModule)) + if (Q_UNLIKELY(triedToLoadModule)) { throw ErrorInfo(Tr::tr("Module %1 could not be loaded.").arg(fullName), dependsItemLocation); + } return nullptr; } @@ -3119,6 +3195,17 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext, return moduleItem; } +QStringList &ModuleLoader::getModuleFileNames(const QString &dirPath) +{ + QStringList &moduleFileNames = m_moduleDirListCache[dirPath]; + if (moduleFileNames.empty()) { + QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards()); + while (dirIter.hasNext()) + moduleFileNames += dirIter.next(); + } + return moduleFileNames; +} + // returns QVariant::Invalid for types that do not need conversion static QVariant::Type variantType(PropertyDeclaration::Type t) { @@ -3227,7 +3314,7 @@ Item *ModuleLoader::getModulePrototype(ProductContext *productContext, } } Item * const module = loadItemFromFile(filePath, CodeLocation()); - prototypeList.push_back(std::make_pair(module, productContext->profileName)); + prototypeList.emplace_back(module, productContext->profileName); if (module->type() != ItemType::Module) { qCDebug(lcModuleLoader).nospace() << "Alleged module " << fullModuleName << " has type '" @@ -3285,6 +3372,9 @@ void ModuleLoader::setupBaseModulePrototype(Item *prototype) prototype->setProperty(QStringLiteral("hostPlatform"), VariantValue::create(QString::fromStdString( HostOsInfo::hostOSIdentifier()))); + prototype->setProperty(QStringLiteral("hostArchitecture"), + VariantValue::create(QString::fromStdString( + HostOsInfo::hostOSArchitecture()))); prototype->setProperty(QStringLiteral("libexecPath"), VariantValue::create(m_parameters.libexecPath())); @@ -3327,7 +3417,7 @@ static std::vector<std::pair<QualifiedId, ItemValuePtr>> instanceItemProperties( if (itemValue->item()->type() == ItemType::ModulePrefix) f(itemValue->item()); else - result.push_back(std::make_pair(name, itemValue)); + result.emplace_back(name, itemValue); name.removeLast(); } }; @@ -3496,7 +3586,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It if (Q_UNLIKELY(configureScript->sourceCode() == StringConstants::undefinedValue())) throw ErrorInfo(Tr::tr("Probe.configure must be set."), probe->location()); using ProbeProperty = std::pair<QString, QScriptValue>; - QList<ProbeProperty> probeBindings; + std::vector<ProbeProperty> probeBindings; QVariantMap initialProperties; for (Item *obj = probe; obj; obj = obj->prototype()) { const Item::PropertyMap &props = obj->properties(); @@ -3505,7 +3595,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It if (name == StringConstants::configureProperty()) continue; const QScriptValue value = m_evaluator->value(probe, name); - probeBindings += ProbeProperty(name, value); + probeBindings << ProbeProperty(name, value); if (name != StringConstants::conditionProperty()) initialProperties.insert(name, value.toVariant()); } @@ -3516,7 +3606,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It const QString &sourceCode = configureScript->sourceCode().toString(); ProbeConstPtr resolvedProbe; if (parent->type() == ItemType::Project - || productContext->name.startsWith(shadowProductPrefix())) { + || productContext->name.startsWith(StringConstants::shadowProductPrefix())) { resolvedProbe = findOldProjectProbe(probeId, condition, initialProperties, sourceCode); } else { const QString &uniqueProductName = productContext->uniqueName(); @@ -3544,7 +3634,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It engine->currentContext()->pushScope(fileCtxScopes.fileScope); engine->currentContext()->pushScope(fileCtxScopes.importScope); configureScope = engine->newObject(); - for (const ProbeProperty &b : qAsConst(probeBindings)) + for (const ProbeProperty &b : probeBindings) configureScope.setProperty(b.first, b.second); engine->currentContext()->pushScope(configureScope); engine->clearRequestedProperties(); @@ -3560,7 +3650,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It importedFilesUsedInConfigure = resolvedProbe->importedFilesUsed(); } QVariantMap properties; - for (const ProbeProperty &b : qAsConst(probeBindings)) { + for (const ProbeProperty &b : probeBindings) { QVariant newValue; if (resolvedProbe) { newValue = resolvedProbe->properties().value(b.first); @@ -3678,12 +3768,36 @@ QString ModuleLoader::findExistingModulePath(const QString &searchPath, const QualifiedId &moduleName) { QString dirPath = searchPath + QStringLiteral("/modules"); + + // isFileCaseCorrect is a very expensive call on macOS, so we cache the value for the + // modules and search paths we've already processed + auto &moduleInfo = m_existingModulePathCache[{searchPath, moduleName}]; + if (moduleInfo.first) // poor man's std::optional<QString> + return moduleInfo.second; + for (const QString &moduleNamePart : moduleName) { dirPath = FileInfo::resolvePath(dirPath, moduleNamePart); - if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath)) - return {}; + if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath)) { + moduleInfo.first = true; + return moduleInfo.second = QString(); + } } - return dirPath; + + moduleInfo.first = true; + return moduleInfo.second = dirPath; +} + +QStringList ModuleLoader::findExistingModulePaths( + const QStringList &searchPaths, const QualifiedId &moduleName) +{ + QStringList result; + result.reserve(searchPaths.size()); + for (const auto &path: searchPaths) { + const QString dirPath = findExistingModulePath(path, moduleName); + if (!dirPath.isEmpty()) + result.append(dirPath); + } + return result; } QVariantMap ModuleLoader::moduleProviderConfig(ModuleLoader::ProductContext &product) @@ -3769,6 +3883,7 @@ ModuleLoader::ModuleProviderResult ModuleLoader::findModuleProvider(const Qualif const QString searchPathBaseDir = ModuleProviderInfo::outputDirPath(projectBuildDir, name); const QVariant moduleConfig = moduleProviderConfig(product).value(name.toString()); QTextStream stream(&dummyItemFile); + using Qt::endl; stream.setCodec("UTF-8"); stream << "import qbs.FileInfo" << endl; stream << "import qbs.Utilities" << endl; diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h index 85a2467f2..942f93c83 100644 --- a/src/lib/corelib/language/moduleloader.h +++ b/src/lib/corelib/language/moduleloader.h @@ -218,7 +218,7 @@ private: { Q_DISABLE_COPY(TopLevelProjectContext) public: - TopLevelProjectContext() {} + TopLevelProjectContext() = default; ~TopLevelProjectContext() { qDeleteAll(projects); } std::vector<ProjectContext *> projects; @@ -252,6 +252,7 @@ private: VariantValuePtr multiplexedType; QString toIdString(size_t row) const; + static QVariantMap multiplexIdToVariantMap(const QString &multiplexId); }; void dump(const MultiplexInfo &mpi); @@ -317,6 +318,7 @@ private: Item *searchAndLoadModuleFile(ProductContext *productContext, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, FallbackMode fallbackMode, bool isRequired, Item *moduleInstance); + QStringList &getModuleFileNames(const QString &dirPath); Item *loadModuleFile(ProductContext *productContext, const QString &fullModuleName, bool isBaseModule, const QString &filePath, bool *triedToLoad, Item *moduleInstance); Item *getModulePrototype(ProductContext *productContext, const QString &fullModuleName, @@ -337,8 +339,9 @@ private: QStringList readExtraSearchPaths(Item *item, bool *wasSet = nullptr); void copyProperties(const Item *sourceProject, Item *targetProject); Item *wrapInProjectIfNecessary(Item *item); - static QString findExistingModulePath(const QString &searchPath, - const QualifiedId &moduleName); + QString findExistingModulePath(const QString &searchPath, const QualifiedId &moduleName); + QStringList findExistingModulePaths( + const QStringList &searchPaths, const QualifiedId &moduleName); enum class ModuleProviderLookup { Regular, Fallback }; struct ModuleProviderResult @@ -411,6 +414,7 @@ private: ItemReader *m_reader; Evaluator *m_evaluator; QMap<QString, QStringList> m_moduleDirListCache; + QHash<std::pair<QString, QualifiedId>, std::pair<bool, QString>> m_existingModulePathCache; // The keys are file paths, the values are module prototype items accompanied by a profile. std::unordered_map<QString, std::vector<std::pair<Item *, QString>>> m_modulePrototypes; @@ -425,8 +429,8 @@ private: struct DependsChainEntry { - DependsChainEntry(const QualifiedId &name, const CodeLocation &location) - : name(name), location(location) + DependsChainEntry(QualifiedId name, const CodeLocation &location) + : name(std::move(name)), location(location) { } @@ -437,10 +441,10 @@ private: class DependsChainManager; std::vector<DependsChainEntry> m_dependsChain; - QHash<QString, QList<ProbeConstPtr>> m_oldProjectProbes; + QHash<QString, std::vector<ProbeConstPtr>> m_oldProjectProbes; QHash<QString, std::vector<ProbeConstPtr>> m_oldProductProbes; FileTime m_lastResolveTime; - QHash<CodeLocation, QList<ProbeConstPtr>> m_currentProbes; + QHash<CodeLocation, std::vector<ProbeConstPtr>> m_currentProbes; QVariantMap m_storedProfiles; QVariantMap m_localProfiles; std::multimap<QString, const ProductContext *> m_productsByName; diff --git a/src/lib/corelib/language/modulemerger.cpp b/src/lib/corelib/language/modulemerger.cpp index 053e90d53..c5deaae04 100644 --- a/src/lib/corelib/language/modulemerger.cpp +++ b/src/lib/corelib/language/modulemerger.cpp @@ -50,15 +50,18 @@ namespace qbs { namespace Internal { -ModuleMerger::ModuleMerger(Logger &logger, Item *root, Item::Module &moduleToMerge) +ModuleMerger::ModuleMerger(Logger &logger, Item *productItem, const QString &productName, + const Item::Modules::iterator &modulesBegin, + const Item::Modules::iterator &modulesEnd) : m_logger(logger) - , m_rootItem(root) - , m_mergedModule(moduleToMerge) - , m_required(moduleToMerge.required) - , m_isBaseModule(moduleToMerge.name.first() == StringConstants::qbsModule()) - , m_versionRange(moduleToMerge.versionRange) + , m_productItem(productItem) + , m_mergedModule(*modulesBegin) + , m_isBaseModule(m_mergedModule.name.first() == StringConstants::qbsModule()) + , m_isShadowProduct(productName.startsWith(StringConstants::shadowProductPrefix())) + , m_modulesBegin(std::next(modulesBegin)) + , m_modulesEnd(modulesEnd) { - QBS_CHECK(moduleToMerge.item->type() == ItemType::ModuleInstance); + QBS_CHECK(modulesBegin->item->type() == ItemType::ModuleInstance); } void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerItem, Item *toReplace) @@ -83,48 +86,39 @@ void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerIt } } -void ModuleMerger::replaceItemInScopes(Item *toReplace) -{ - // In insertProperties(), we potentially call setDefiningItem() with the "wrong" - // (to-be-replaced) module instance as an argument. If such module instances - // are dependencies of other modules, they have the depending module's instance - // as their "instance scope", which is the scope of their scope. This function takes - // care that the "wrong" definingItem of values in sub-modules still has the "right" - // instance scope, namely our merged module instead of some other instance. - for (const Item::Module &module : toReplace->modules()) { - for (const ValuePtr &property : module.item->properties()) { - ValuePtr v = property; - do { - if (v->definingItem() && v->definingItem()->scope() - && v->definingItem()->scope()->scope() == toReplace) { - v->definingItem()->scope()->setScope(m_mergedModule.item); - } - v = v->next(); - } while (v); - } - } -} - void ModuleMerger::start() { + // Iterate over any module that our product depends on. These modules + // may depend on m_mergedModule and contribute property assignments. + Item::PropertyMap props; + for (auto module = m_modulesBegin; module != m_modulesEnd; module++) + mergeModule(&props, *module); + + // Module property assignments in the product have the highest priority + // and are thus prepended. Item::Module m; - m.item = m_rootItem; - const Item::PropertyMap props = dfs(m, Item::PropertyMap()); - if (m_required) - m_mergedModule.required = true; - m_mergedModule.versionRange.narrowDown(m_versionRange); - Item::PropertyMap mergedProps = m_mergedModule.item->properties(); + m.item = m_productItem; + mergeModule(&props, m); + // The module's prototype is the essential unmodified module as loaded + // from the cache. Item *moduleProto = m_mergedModule.item->prototype(); while (moduleProto->prototype()) moduleProto = moduleProto->prototype(); + // The prototype item might contain default values which get appended in + // case of list properties. Scalar properties will only be set if not + // already specified above. + Item::PropertyMap mergedProps = m_mergedModule.item->properties(); for (auto it = props.constBegin(); it != props.constEnd(); ++it) { appendPrototypeValueToNextChain(moduleProto, it.key(), it.value()); mergedProps[it.key()] = it.value(); } + m_mergedModule.item->setProperties(mergedProps); + // Update all sibling instances of the to-be-merged module to behave identical + // to the merged module. for (Item *moduleInstanceContainer : qAsConst(m_moduleInstanceContainers)) { Item::Modules modules; for (const Item::Module &dep : moduleInstanceContainer->modules()) { @@ -133,11 +127,9 @@ void ModuleMerger::start() if (isTheModule && m.item != m_mergedModule.item) { QBS_CHECK(m.item->type() == ItemType::ModuleInstance); replaceItemInValues(m.name, moduleInstanceContainer, m.item); - replaceItemInScopes(m.item); m.item = m_mergedModule.item; - if (m_required) - m.required = true; - m.versionRange.narrowDown(m_versionRange); + m.required = m_mergedModule.required; + m.versionRange = m_mergedModule.versionRange; } modules << m; } @@ -145,94 +137,26 @@ void ModuleMerger::start() } } -Item::PropertyMap ModuleMerger::dfs(const Item::Module &m, Item::PropertyMap props) +void ModuleMerger::mergeModule(Item::PropertyMap *dstProps, const Item::Module &module) { - Item *moduleInstance = nullptr; - size_t numberOfOutprops = m.item->modules().size(); - for (const Item::Module &dep : m.item->modules()) { - if (dep.name == m_mergedModule.name) { - --numberOfOutprops; - moduleInstance = dep.item; - insertProperties(&props, moduleInstance, ScalarProperties); - m_moduleInstanceContainers << m.item; - if (dep.required) - m_required = true; - m_versionRange.narrowDown(dep.versionRange); - break; - } - } - - std::vector<Item::PropertyMap> outprops; - outprops.reserve(numberOfOutprops); - for (const Item::Module &dep : m.item->modules()) { - if (dep.item != moduleInstance) - outprops.push_back(dfs(dep, props)); - } - - if (!outprops.empty()) { - props = outprops.front(); - for (size_t i = 1; i < outprops.size(); ++i) - mergeOutProps(&props, outprops.at(i)); - } - - if (moduleInstance) - insertProperties(&props, moduleInstance, ListProperties); - - const bool isNonPresentModule = m.item->type() != ItemType::Product - && !m.item->isPresentModule(); - return isNonPresentModule ? Item::PropertyMap() : props; -} - -void ModuleMerger::mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap &src) -{ - for (auto it = src.constBegin(); it != src.constEnd(); ++it) { - ValuePtr &v = (*dst)[it.key()]; - if (!v) { - v = it.value(); - QBS_ASSERT(it.value(), continue); - continue; - } - if (v->type() != Value::JSSourceValueType) - continue; - if (it.value()->type() != Value::JSSourceValueType) - continue; - // possible conflict - const JSSourceValuePtr dstVal = std::static_pointer_cast<JSSourceValue>(v); - JSSourceValuePtr srcVal = std::static_pointer_cast<JSSourceValue>(it.value()); - - const PropertyDeclaration pd = m_decls.value(srcVal); - QBS_CHECK(pd.isValid()); - - if (pd.isScalar()) { - if (dstVal->sourceCode() != srcVal->sourceCode()) { - m_logger.qbsWarning() << Tr::tr("Conflicting scalar values at %1 and %2.").arg( - dstVal->location().toString(), - srcVal->location().toString()); - // TODO: yield error with a hint how to solve the conflict. - } - v = it.value(); - } else { - lastInNextChain(dstVal)->setNext(srcVal); - } - } -} + const Item::Module *dep = findModule(module.item, m_mergedModule.name); + if (!dep) + return; -void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, PropertiesType type) -{ - Set<const Item *> &seenInstances = type == ScalarProperties - ? m_seenInstancesTopDown : m_seenInstancesBottomUp; + const bool mergingProductItem = (module.item == m_productItem); + Item *srcItem = dep->item; Item *origSrcItem = srcItem; do { - if (seenInstances.insert(srcItem).second) { - for (Item::PropertyMap::const_iterator it = srcItem->properties().constBegin(); - it != srcItem->properties().constEnd(); ++it) { + if (m_seenInstances.insert(srcItem).second) { + for (auto it = srcItem->properties().constBegin(); + it != srcItem->properties().constEnd(); ++it) { const ValuePtr &srcVal = it.value(); if (srcVal->type() == Value::ItemValueType) continue; if (it.key() == StringConstants::qbsSourceDirPropertyInternal()) continue; const PropertyDeclaration srcDecl = srcItem->propertyDeclaration(it.key()); - if (!srcDecl.isValid() || srcDecl.isScalar() != (type == ScalarProperties)) + if (!srcDecl.isValid()) continue; // Scalar variant values could stem from product multiplexing, in which case @@ -242,21 +166,51 @@ void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, Prope continue; } - ValuePtr &v = (*dst)[it.key()]; - if (v && type == ScalarProperties) - continue; - ValuePtr clonedVal = srcVal->clone(); - m_decls[clonedVal] = srcDecl; - clonedVal->setDefiningItem(origSrcItem); - if (v) { - QBS_CHECK(!clonedVal->next()); - clonedVal->setNext(v); + ValuePtr clonedSrcVal = srcVal->clone(); + clonedSrcVal->setDefiningItem(origSrcItem); + + ValuePtr &dstVal = (*dstProps)[it.key()]; + if (dstVal) { + if (srcDecl.isScalar()) { + // Scalar properties get replaced. + if ((dstVal->type() == Value::JSSourceValueType) + && (srcVal->type() == Value::JSSourceValueType)) { + // Warn only about conflicting source code values + const JSSourceValuePtr dstJsVal = + std::static_pointer_cast<JSSourceValue>(dstVal); + const JSSourceValuePtr srcJsVal = + std::static_pointer_cast<JSSourceValue>(srcVal); + const bool overriddenInProduct = + m_mergedModule.item->properties().contains(it.key()); + + if (dstJsVal->sourceCode() != srcJsVal->sourceCode() + && !mergingProductItem && !overriddenInProduct + && !m_isShadowProduct) { + m_logger.qbsWarning() + << Tr::tr("Conflicting scalar values at %1 and %2.").arg( + dstJsVal->location().toString(), + srcJsVal->location().toString()); + } + } + } else { + // List properties get prepended + QBS_CHECK(!clonedSrcVal->next()); + clonedSrcVal->setNext(dstVal); + } } - v = clonedVal; + dstVal = clonedSrcVal; } } srcItem = srcItem->prototype(); } while (srcItem && srcItem->type() == ItemType::ModuleInstance); + + // Update dependency constraints + if (dep->required) + m_mergedModule.required = true; + m_mergedModule.versionRange.narrowDown(dep->versionRange); + + // We need to touch the unmerged module instances later once more + m_moduleInstanceContainers << module.item; } void ModuleMerger::appendPrototypeValueToNextChain(Item *moduleProto, const QString &propertyName, @@ -288,5 +242,23 @@ ValuePtr ModuleMerger::lastInNextChain(const ValuePtr &v) return n; } +const Item::Module *ModuleMerger::findModule(const Item *item, const QualifiedId &name) +{ + for (const auto &module : item->modules()) { + if (module.name == name) + return &module; + } + return nullptr; +} + +void ModuleMerger::merge(Logger &logger, Item *product, const QString &productName, + Item::Modules *topSortedModules) +{ + for (auto it = topSortedModules->begin(); it != topSortedModules->end(); ++it) + ModuleMerger(logger, product, productName, it, topSortedModules->end()).start(); +} + + + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/modulemerger.h b/src/lib/corelib/language/modulemerger.h index 3cc3ba08a..469dc86c4 100644 --- a/src/lib/corelib/language/modulemerger.h +++ b/src/lib/corelib/language/modulemerger.h @@ -54,32 +54,33 @@ namespace Internal { class ModuleMerger { public: - ModuleMerger(Logger &logger, Item *root, Item::Module &moduleToMerge); - void start(); + static void merge(Logger &logger, Item *productItem, const QString &productName, + Item::Modules *topSortedModules); private: - Item::PropertyMap dfs(const Item::Module &m, Item::PropertyMap props); - void mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap &src); + ModuleMerger(Logger &logger, Item *productItem, const QString &productName, + const Item::Modules::iterator &modulesBegin, + const Item::Modules::iterator &modulesEnd); + void appendPrototypeValueToNextChain(Item *moduleProto, const QString &propertyName, const ValuePtr &sv); - static ValuePtr lastInNextChain(const ValuePtr &v); - - enum PropertiesType { ScalarProperties, ListProperties }; - void insertProperties(Item::PropertyMap *dst, Item *srcItem, PropertiesType type); + void mergeModule(Item::PropertyMap *props, const Item::Module &m); void replaceItemInValues(QualifiedId moduleName, Item *containerItem, Item *toReplace); - void replaceItemInScopes(Item *toReplace); + void start(); + + static ValuePtr lastInNextChain(const ValuePtr &v); + static const Item::Module *findModule(const Item *item, const QualifiedId &name); Logger &m_logger; - Item * const m_rootItem; + Item * const m_productItem; Item::Module &m_mergedModule; Item *m_clonedModulePrototype = nullptr; - QHash<ValuePtr, PropertyDeclaration> m_decls; - Set<const Item *> m_seenInstancesTopDown; - Set<const Item *> m_seenInstancesBottomUp; + Set<const Item *> m_seenInstances; Set<Item *> m_moduleInstanceContainers; - bool m_required; const bool m_isBaseModule; - VersionRange m_versionRange; + const bool m_isShadowProduct; + const Item::Modules::iterator m_modulesBegin; + const Item::Modules::iterator m_modulesEnd; }; } // namespace Internal diff --git a/src/lib/corelib/language/moduleproviderinfo.h b/src/lib/corelib/language/moduleproviderinfo.h index fef9d9765..4f757d3d9 100644 --- a/src/lib/corelib/language/moduleproviderinfo.h +++ b/src/lib/corelib/language/moduleproviderinfo.h @@ -55,9 +55,12 @@ class ModuleProviderInfo { public: ModuleProviderInfo() = default; - ModuleProviderInfo(const QualifiedId &name, const QVariantMap &config, - const QStringList &searchPaths, bool transientOutput) - : name(name), config(config), searchPaths(searchPaths), transientOutput(transientOutput) + ModuleProviderInfo(QualifiedId name, QVariantMap config, + QStringList searchPaths, bool transientOutput) + : name(std::move(name)) + , config(std::move(config)) + , searchPaths(std::move(searchPaths)) + , transientOutput(transientOutput) {} static QString outputBaseDirName() { return QStringLiteral("genmodules"); } diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp index 049472310..fd6063381 100644 --- a/src/lib/corelib/language/projectresolver.cpp +++ b/src/lib/corelib/language/projectresolver.cpp @@ -71,6 +71,7 @@ #include <QtCore/qregexp.h> #include <algorithm> +#include <memory> #include <queue> namespace qbs { @@ -126,9 +127,7 @@ ProjectResolver::ProjectResolver(Evaluator *evaluator, ModuleLoaderResult loadRe QBS_CHECK(FileInfo::isAbsolute(m_setupParams.buildRoot())); } -ProjectResolver::~ProjectResolver() -{ -} +ProjectResolver::~ProjectResolver() = default; void ProjectResolver::setProgressObserver(ProgressObserver *observer) { @@ -812,7 +811,7 @@ void ProjectResolver::resolveGroupFully(Item *item, ProjectResolver::ProjectCont group->targetOfModule = moduleProp->value().toString(); ErrorInfo fileError; if (!patterns.empty()) { - group->wildcards = std::unique_ptr<SourceWildCards>(new SourceWildCards); + group->wildcards = std::make_unique<SourceWildCards>(); SourceWildCards *wildcards = group->wildcards.get(); wildcards->group = group.get(); wildcards->excludePatterns = m_evaluator->stringListValue( @@ -988,7 +987,7 @@ void ProjectResolver::resolveShadowProduct(Item *item, ProjectResolver::ProjectC try { adaptExportedPropertyValues(item); } catch (const ErrorInfo &) {} - m_productExportInfo.push_back(std::make_pair(m_productContext->product, item)); + m_productExportInfo.emplace_back(m_productContext->product, item); } void ProjectResolver::setupExportedProperties(const Item *item, const QString &namePrefix, @@ -1460,7 +1459,7 @@ void ProjectResolver::matchArtifactProperties(const ResolvedProductPtr &product, const std::vector<SourceArtifactPtr> &artifacts) { for (const SourceArtifactPtr &artifact : artifacts) { - for (const ArtifactPropertiesConstPtr &artifactProperties : product->artifactProperties) { + for (const auto &artifactProperties : product->artifactProperties) { if (!artifact->isTargetOfModule() && artifact->fileTags.intersects(artifactProperties->fileTagsFilter())) { artifact->properties = artifactProperties->propertyMap(); diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h index 428ba144d..a1e24a555 100644 --- a/src/lib/corelib/language/projectresolver.h +++ b/src/lib/corelib/language/projectresolver.h @@ -139,9 +139,9 @@ private: struct ProductDependencyInfo { - ProductDependencyInfo(const ResolvedProductPtr &product, - const QVariantMap ¶meters = QVariantMap()) - : product(product), parameters(parameters) + ProductDependencyInfo(ResolvedProductPtr product, + QVariantMap parameters = QVariantMap()) + : product(std::move(product)), parameters(std::move(parameters)) { } diff --git a/src/lib/corelib/language/property.h b/src/lib/corelib/language/property.h index 204704672..78061bf6f 100644 --- a/src/lib/corelib/language/property.h +++ b/src/lib/corelib/language/property.h @@ -65,9 +65,13 @@ public: { } - Property(const QString &product, const QString &module, const QString &property, - const QVariant &v, Kind k) - : productName(product), moduleName(module), propertyName(property), value(v), kind(k) + Property(QString product, QString module, QString property, + QVariant v, Kind k) + : productName(std::move(product)) + , moduleName(std::move(module)) + , propertyName(std::move(property)) + , value(std::move(v)) + , kind(k) { } diff --git a/src/lib/corelib/language/propertydeclaration.cpp b/src/lib/corelib/language/propertydeclaration.cpp index 5ea6a3d88..abe6a1626 100644 --- a/src/lib/corelib/language/propertydeclaration.cpp +++ b/src/lib/corelib/language/propertydeclaration.cpp @@ -84,20 +84,11 @@ PropertyDeclaration::PropertyDeclaration(const QString &name, Type type, d->flags = flags; } -PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other) - : d(other.d) -{ -} +PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other) = default; -PropertyDeclaration::~PropertyDeclaration() -{ -} +PropertyDeclaration::~PropertyDeclaration() = default; -PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other) -{ - d = other.d; - return *this; -} +PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other) = default; bool PropertyDeclaration::isValid() const { diff --git a/src/lib/corelib/language/propertymapinternal.cpp b/src/lib/corelib/language/propertymapinternal.cpp index 2a35e2a6a..fe0f672c5 100644 --- a/src/lib/corelib/language/propertymapinternal.cpp +++ b/src/lib/corelib/language/propertymapinternal.cpp @@ -58,13 +58,9 @@ namespace Internal { * \sa ResolvedProduct * \sa SourceArtifact */ -PropertyMapInternal::PropertyMapInternal() -{ -} +PropertyMapInternal::PropertyMapInternal() = default; -PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) : m_value(other.m_value) -{ -} +PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) = default; QVariant PropertyMapInternal::moduleProperty(const QString &moduleName, const QString &key, bool *isPresent) const diff --git a/src/lib/corelib/language/qualifiedid.cpp b/src/lib/corelib/language/qualifiedid.cpp index 5cc315bb1..9eb0e9463 100644 --- a/src/lib/corelib/language/qualifiedid.cpp +++ b/src/lib/corelib/language/qualifiedid.cpp @@ -44,9 +44,7 @@ namespace qbs { namespace Internal { -QualifiedId::QualifiedId() -{ -} +QualifiedId::QualifiedId() = default; QualifiedId::QualifiedId(const QString &singlePartName) : QStringList(singlePartName) diff --git a/src/lib/corelib/language/resolvedfilecontext.h b/src/lib/corelib/language/resolvedfilecontext.h index 81a3f7472..d783cf725 100644 --- a/src/lib/corelib/language/resolvedfilecontext.h +++ b/src/lib/corelib/language/resolvedfilecontext.h @@ -65,7 +65,7 @@ public: pool.serializationOp<opType>(m_filePath, m_jsExtensions, m_searchPaths, m_jsImports); } private: - ResolvedFileContext() {} + ResolvedFileContext() = default; ResolvedFileContext(const FileContextBase &ctx); }; diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp index 7c531e764..e79ec54d7 100644 --- a/src/lib/corelib/language/scriptengine.cpp +++ b/src/lib/corelib/language/scriptengine.cpp @@ -478,19 +478,18 @@ QScriptValue ScriptEngine::js_require(QScriptContext *context, QScriptEngine *qt return context->throwError( ScriptEngine::tr("require: internal error. No search paths.")); - const QString uri = moduleName; if (engine->m_logger.debugEnabled()) { engine->m_logger.qbsDebug() - << "[require] loading extension " << uri; + << "[require] loading extension " << moduleName; } - QString uriAsPath = uri; - uriAsPath.replace(QLatin1Char('.'), QLatin1Char('/')); + QString moduleNameAsPath = moduleName; + moduleNameAsPath.replace(QLatin1Char('.'), QLatin1Char('/')); const QStringList searchPaths = engine->m_extensionSearchPathsStack.top(); - const QString dirPath = findExtensionDir(searchPaths, uriAsPath); + const QString dirPath = findExtensionDir(searchPaths, moduleNameAsPath); if (dirPath.isEmpty()) { - if (uri.startsWith(QStringLiteral("qbs."))) - return loadInternalExtension(context, engine, uri); + if (moduleName.startsWith(QStringLiteral("qbs."))) + return loadInternalExtension(context, engine, moduleName); } else { QDirIterator dit(dirPath, StringConstants::jsFileWildcards(), QDir::Files | QDir::Readable); diff --git a/src/lib/corelib/language/value.cpp b/src/lib/corelib/language/value.cpp index 656f38874..342fbd89a 100644 --- a/src/lib/corelib/language/value.cpp +++ b/src/lib/corelib/language/value.cpp @@ -61,9 +61,7 @@ Value::Value(const Value &other) { } -Value::~Value() -{ -} +Value::~Value() = default; Item *Value::definingItem() const { @@ -115,9 +113,7 @@ JSSourceValuePtr JSSourceValue::create(bool createdByPropertiesBlock) return JSSourceValuePtr(new JSSourceValue(createdByPropertiesBlock)); } -JSSourceValue::~JSSourceValue() -{ -} +JSSourceValue::~JSSourceValue() = default; ValuePtr JSSourceValue::clone() const { @@ -200,7 +196,7 @@ VariantValuePtr VariantValue::create(const QVariant &v) ValuePtr VariantValue::clone() const { - return VariantValuePtr(new VariantValue(*this)); + return std::make_shared<VariantValue>(*this); } const VariantValuePtr &VariantValue::falseValue() diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h index f27406f2d..d3a748d92 100644 --- a/src/lib/corelib/language/value.h +++ b/src/lib/corelib/language/value.h @@ -151,14 +151,14 @@ public: struct PropertyData { PropertyData() = default; - PropertyData(const QString &v, const CodeLocation &l) : value(v), location(l) {} + PropertyData(QString v, const CodeLocation &l) : value(std::move(v)), location(l) {} QString value; CodeLocation location; }; - Alternative() { } - Alternative(const PropertyData &c, const PropertyData &o, const JSSourceValuePtr &v) - : condition(c), overrideListProperties(o), value(v) {} + Alternative() = default; + Alternative(PropertyData c, PropertyData o, JSSourceValuePtr v) + : condition(std::move(c)), overrideListProperties(std::move(o)), value(std::move(v)) {} Alternative clone() const { return Alternative(condition, overrideListProperties, diff --git a/src/lib/corelib/logging/logger.cpp b/src/lib/corelib/logging/logger.cpp index 71ca6a96c..2ed29c4c2 100644 --- a/src/lib/corelib/logging/logger.cpp +++ b/src/lib/corelib/logging/logger.cpp @@ -50,9 +50,9 @@ #include <QtCore/qvariant.h> #include <cstdarg> +#include <cstdio> #include <mutex> #include <set> -#include <stdio.h> namespace qbs { namespace Internal { @@ -183,17 +183,20 @@ LogWriter operator<<(LogWriter w, const QVariant &variant) LogWriter operator<<(LogWriter w, int n) { - return w << QString::number(n); + w.write(QString::number(n)); + return w; } LogWriter operator<<(LogWriter w, qint64 n) { - return w << QString::number(n); + w.write(QString::number(n)); + return w; } LogWriter operator<<(LogWriter w, bool b) { - return w << QString::fromLatin1(b ? "true" : "false"); + w.write(QString::fromLatin1(b ? "true" : "false")); + return w; } LogWriter operator<<(LogWriter w, const MessageTag &tag) diff --git a/src/lib/corelib/logging/logger.h b/src/lib/corelib/logging/logger.h index b0b5dd6f3..389dc7e05 100644 --- a/src/lib/corelib/logging/logger.h +++ b/src/lib/corelib/logging/logger.h @@ -70,7 +70,7 @@ public: // a << chain prints the accumulated data LogWriter(const LogWriter &other); ~LogWriter(); - const LogWriter &operator=(const LogWriter &other); + const LogWriter &operator=(const LogWriter &other); // NOLINT void write(char c); void write(const char *str); @@ -90,7 +90,7 @@ private: class QBS_EXPORT MessageTag { public: - explicit MessageTag(const QString &tag) : m_tag(tag) {} + explicit MessageTag(QString tag) : m_tag(std::move(tag)) {} const QString &tag() const { return m_tag; } diff --git a/src/lib/corelib/parser/qmljsast_p.h b/src/lib/corelib/parser/qmljsast_p.h index 8c6f32140..dcee233da 100644 --- a/src/lib/corelib/parser/qmljsast_p.h +++ b/src/lib/corelib/parser/qmljsast_p.h @@ -221,7 +221,7 @@ public: // NOTE: node destructors are never called, // instead we block free the memory // (see the NodePool class) - virtual ~Node() {} + virtual ~Node() = default; virtual ExpressionNode *expressionCast(); virtual BinaryExpression *binaryExpressionCast(); @@ -245,7 +245,7 @@ public: class QML_PARSER_EXPORT ExpressionNode: public Node { public: - ExpressionNode() {} + ExpressionNode() = default; ExpressionNode *expressionCast() override; }; @@ -253,7 +253,7 @@ public: class QML_PARSER_EXPORT Statement: public Node { public: - Statement() {} + Statement() = default; Statement *statementCast() override; }; @@ -2303,7 +2303,7 @@ public: return imports->firstSourceLocation(); else if (members) return members->firstSourceLocation(); - return SourceLocation(); + return {}; } SourceLocation lastSourceLocation() const override @@ -2312,7 +2312,7 @@ public: return members->lastSourceLocation(); else if (imports) return imports->lastSourceLocation(); - return SourceLocation(); + return {}; } // attributes @@ -2519,7 +2519,7 @@ public: else if (const auto varStmt = cast<const VariableStatement *>(sourceElement)) return varStmt->firstSourceLocation(); - return SourceLocation(); + return {}; } SourceLocation lastSourceLocation() const override @@ -2529,7 +2529,7 @@ public: else if (const auto varStmt = cast<const VariableStatement *>(sourceElement)) return varStmt->lastSourceLocation(); - return SourceLocation(); + return {}; } void accept0(Visitor *visitor) override; diff --git a/src/lib/corelib/parser/qmljsastvisitor.cpp b/src/lib/corelib/parser/qmljsastvisitor.cpp index fcb84ec7e..f034a147e 100644 --- a/src/lib/corelib/parser/qmljsastvisitor.cpp +++ b/src/lib/corelib/parser/qmljsastvisitor.cpp @@ -42,13 +42,9 @@ namespace QbsQmlJS { namespace AST { -Visitor::Visitor() -{ -} +Visitor::Visitor() = default; -Visitor::~Visitor() -{ -} +Visitor::~Visitor() = default; } // namespace AST } // namespace QbsQmlJS diff --git a/src/lib/corelib/parser/qmljsengine_p.cpp b/src/lib/corelib/parser/qmljsengine_p.cpp index 211743190..92ac6452a 100644 --- a/src/lib/corelib/parser/qmljsengine_p.cpp +++ b/src/lib/corelib/parser/qmljsengine_p.cpp @@ -117,12 +117,9 @@ double integerFromString(const QString &str, int radix) } -Engine::Engine() - : _lexer(nullptr), _directives(nullptr) -{ } +Engine::Engine() = default; -Engine::~Engine() -{ } +Engine::~Engine() = default; void Engine::setCode(const QString &code) { _code = code; } diff --git a/src/lib/corelib/parser/qmljsengine_p.h b/src/lib/corelib/parser/qmljsengine_p.h index 6ff53a6e9..c55d525f8 100644 --- a/src/lib/corelib/parser/qmljsengine_p.h +++ b/src/lib/corelib/parser/qmljsengine_p.h @@ -59,6 +59,7 @@ #include <QtCore/qstring.h> #include <set> +#include <utility> namespace QbsQmlJS { @@ -74,8 +75,8 @@ public: DiagnosticMessage() : kind(Error) {} - DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message) - : kind(kind), loc(loc), message(message) {} + DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, QString message) + : kind(kind), loc(loc), message(std::move(message)) {} bool isWarning() const { return kind == Warning; } @@ -90,8 +91,8 @@ public: class QBS_AUTOTEST_EXPORT Engine { - Lexer *_lexer; - Directives *_directives; + Lexer *_lexer{nullptr}; + Directives *_directives{nullptr}; MemoryPool _pool; QList<AST::SourceLocation> _comments; QString _extraCode; diff --git a/src/lib/corelib/parser/qmljslexer.cpp b/src/lib/corelib/parser/qmljslexer.cpp index dc6ac8a0f..815f1ef0d 100644 --- a/src/lib/corelib/parser/qmljslexer.cpp +++ b/src/lib/corelib/parser/qmljslexer.cpp @@ -78,8 +78,8 @@ static QChar convertHex(QChar c1, QChar c2) static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4) { - return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()), - (convertHex(c1.unicode()) << 4) + convertHex(c2.unicode())); + return {uchar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode())), + uchar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()))}; } Lexer::Lexer(Engine *engine) @@ -178,7 +178,7 @@ int Lexer::lex() _tokenSpell = QStringRef(); _tokenKind = scanToken(); - _tokenLength = _codePtr - _tokenStartPtr - 1; + _tokenLength = int(_codePtr - _tokenStartPtr - 1); _delimited = false; _restrictedKeyword = false; @@ -397,7 +397,8 @@ again: scanChar(); if (_engine) { - _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4, + _engine->addComment(tokenOffset() + 2, + int(_codePtr - _tokenStartPtr - 1 - 4), tokenStartLine(), tokenStartColumn() + 2); } @@ -412,7 +413,7 @@ again: scanChar(); } if (_engine) { - _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2, + _engine->addComment(tokenOffset() + 2, int(_codePtr - _tokenStartPtr - 1 - 2), tokenStartLine(), tokenStartColumn() + 2); } goto again; @@ -554,7 +555,8 @@ again: if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) { break; } else if (_char == quote) { - _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode); + _tokenSpell = _engine->midRef( + int(startCode - _code.unicode() - 1), int(_codePtr - startCode)); scanChar(); return T_STRING_LITERAL; @@ -706,7 +708,7 @@ again: if (! identifierWithEscapeChars) { identifierWithEscapeChars = true; _tokenText.resize(0); - _tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1); + _tokenText.insert(0, _tokenStartPtr, int(_codePtr - _tokenStartPtr - 1)); _validTokenText = true; } @@ -719,7 +721,7 @@ again: return T_ERROR; } } else { - _tokenLength = _codePtr - _tokenStartPtr - 1; + _tokenLength = int(_codePtr - _tokenStartPtr - 1); int kind = T_IDENTIFIER; @@ -727,10 +729,12 @@ again: kind = classify(_tokenStartPtr, _tokenLength, _qmlMode); if (_engine) { - if (kind == T_IDENTIFIER && identifierWithEscapeChars) + if (kind == T_IDENTIFIER && identifierWithEscapeChars) { _tokenSpell = _engine->newStringRef(_tokenText); - else - _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength); + } else { + _tokenSpell = _engine->midRef( + int(_tokenStartPtr - _code.unicode()), _tokenLength); + } } return kind; @@ -891,7 +895,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix) scanChar(); } - _tokenLength = _codePtr - _tokenStartPtr - 1; + _tokenLength = int(_codePtr - _tokenStartPtr - 1); return true; case '\\': @@ -995,7 +999,7 @@ int Lexer::tokenEndLine() const int Lexer::tokenEndColumn() const { - return _codePtr - _lastLinePtr; + return int(_codePtr - _lastLinePtr); } QString Lexer::tokenText() const diff --git a/src/lib/corelib/parser/qmljslexer_p.h b/src/lib/corelib/parser/qmljslexer_p.h index e9dff1dd4..cf41fb255 100644 --- a/src/lib/corelib/parser/qmljslexer_p.h +++ b/src/lib/corelib/parser/qmljslexer_p.h @@ -62,7 +62,7 @@ class Engine; class QML_PARSER_EXPORT Directives { public: - virtual ~Directives() {} + virtual ~Directives() = default; virtual void pragmaLibrary() { diff --git a/src/lib/corelib/parser/qmljsmemorypool_p.h b/src/lib/corelib/parser/qmljsmemorypool_p.h index 897348712..f7de7bbfb 100644 --- a/src/lib/corelib/parser/qmljsmemorypool_p.h +++ b/src/lib/corelib/parser/qmljsmemorypool_p.h @@ -154,8 +154,8 @@ class QML_PARSER_EXPORT Managed void operator = (const Managed &other); public: - Managed() {} - ~Managed() {} + Managed() = default; + ~Managed() = default; void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); } void operator delete(void *) {} diff --git a/src/lib/corelib/parser/qmljsparser.cpp b/src/lib/corelib/parser/qmljsparser.cpp index 6390c8a9d..d2c87c7cb 100644 --- a/src/lib/corelib/parser/qmljsparser.cpp +++ b/src/lib/corelib/parser/qmljsparser.cpp @@ -40,7 +40,7 @@ #include <QtCore/qdebug.h> #include <QtCore/qcoreapplication.h> -#include <string.h> +#include <cstring> #include "qmljsengine_p.h" #include "qmljslexer_p.h" @@ -328,7 +328,7 @@ case 26: { } break; case 27: { - const auto node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0); + const auto node = new (pool) AST::UiObjectInitializer(nullptr); node->lbraceToken = loc(1); node->rbraceToken = loc(2); sym(1).Node = node; @@ -614,7 +614,7 @@ case 80: { } break; case 81: { - const auto node = new (pool) AST::ArrayLiteral((AST::Elision *) 0); + const auto node = new (pool) AST::ArrayLiteral(static_cast<AST::Elision *>(nullptr)); node->lbracketToken = loc(1); node->rbracketToken = loc(2); sym(1).Node = node; @@ -635,8 +635,7 @@ case 83: { } break; case 84: { - const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), - (AST::Elision *) 0); + const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), nullptr); node->lbracketToken = loc(1); node->commaToken = loc(3); node->rbracketToken = loc(4); @@ -700,7 +699,7 @@ case 89: { } break; case 90: { - sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression); + sym(1).Node = new (pool) AST::ElementList(nullptr, sym(1).Expression); } break; case 91: { @@ -708,8 +707,7 @@ case 91: { } break; case 92: { - const auto node = new (pool) AST::ElementList(sym(1).ElementList, - (AST::Elision *) 0, sym(3).Expression); + const auto node = new (pool) AST::ElementList(sym(1).ElementList, nullptr, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; diff --git a/src/lib/corelib/tools/buildoptions.cpp b/src/lib/corelib/tools/buildoptions.cpp index 75417ab0b..e4e9ba17f 100644 --- a/src/lib/corelib/tools/buildoptions.cpp +++ b/src/lib/corelib/tools/buildoptions.cpp @@ -91,19 +91,11 @@ BuildOptions::BuildOptions() : d(new Internal::BuildOptionsPrivate) { } -BuildOptions::BuildOptions(const BuildOptions &other) : d(other.d) -{ -} +BuildOptions::BuildOptions(const BuildOptions &other) = default; -BuildOptions &BuildOptions::operator=(const BuildOptions &other) -{ - d = other.d; - return *this; -} +BuildOptions &BuildOptions::operator=(const BuildOptions &other) = default; -BuildOptions::~BuildOptions() -{ -} +BuildOptions::~BuildOptions() = default; /*! * \brief If non-empty, qbs pretends that only these files have changed. diff --git a/src/lib/corelib/tools/clangclinfo.cpp b/src/lib/corelib/tools/clangclinfo.cpp new file mode 100644 index 000000000..4e1022c28 --- /dev/null +++ b/src/lib/corelib/tools/clangclinfo.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "clangclinfo.h" + +#include "hostosinfo.h" +#include "msvcinfo.h" +#include "stlutils.h" + +namespace qbs { +namespace Internal { + +static std::vector<MSVCInstallInfo> compatibleMsvcs(Logger &logger) +{ + auto msvcs = MSVCInstallInfo::installedMSVCs(logger); + 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; +} + +static QString findCompatibleVcsarsallBat(const std::vector<MSVCInstallInfo> &msvcs) +{ + for (const auto &msvc: msvcs) { + const auto vcvarsallPath = msvc.findVcvarsallBat(); + if (!vcvarsallPath.isEmpty()) + return vcvarsallPath; + } + return {}; +} + +static QString wow6432Key() +{ +#ifdef Q_OS_WIN64 + return QStringLiteral("\\Wow6432Node"); +#else + return {}; +#endif +} + +static QString getToolchainInstallPath(const QFileInfo &compiler) +{ + return compiler.path(); // 1 level up +} + +QVariantMap ClangClInfo::toVariantMap() const +{ + return { + {QStringLiteral("toolchainInstallPath"), toolchainInstallPath}, + {QStringLiteral("vcvarsallPath"), vcvarsallPath}, + }; +} + +ClangClInfo ClangClInfo::fromCompilerFilePath(const QString &path, Logger &logger) +{ + const auto compilerName = QStringLiteral("clang-cl"); + const auto vcvarsallPath = findCompatibleVcsarsallBat(compatibleMsvcs(logger)); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") + .arg(compilerName); + return {}; + } + + const auto toolchainInstallPath = getToolchainInstallPath(path); + return {toolchainInstallPath, vcvarsallPath}; +} + +std::vector<ClangClInfo> ClangClInfo::installedCompilers( + const std::vector<QString> &extraPaths, Logger &logger) +{ + std::vector<QString> compilerPaths; + compilerPaths.reserve(extraPaths.size()); + std::copy_if(extraPaths.begin(), extraPaths.end(), + std::back_inserter(compilerPaths), + [](const QString &path){ return !path.isEmpty(); }); + const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl")); + + 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()) + compilerPaths.push_back(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() && !contains(compilerPaths, compilerPath)) + compilerPaths.push_back(compilerPath); + } + + const auto msvcs = compatibleMsvcs(logger); + const auto vcvarsallPath = findCompatibleVcsarsallBat(msvcs); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") + .arg(compilerName); + return {}; + } + + std::vector<ClangClInfo> result; + result.reserve(compilerPaths.size() + msvcs.size()); + + for (const auto &path: compilerPaths) + result.push_back({getToolchainInstallPath(path), vcvarsallPath}); + + // If we didn't find custom LLVM installation, try to find if it's installed with Visual Studio + for (const auto &msvc : msvcs) { + const auto compilerPath = QStringLiteral("%1/VC/Tools/Llvm/bin/%2") + .arg(msvc.installDir, compilerName); + if (QFileInfo(compilerPath).exists()) { + const auto vcvarsallPath = msvc.findVcvarsallBat(); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("Found LLVM in %1, but vcvarsall.bat is missing.") + .arg(msvc.installDir); + } + + result.push_back({getToolchainInstallPath(compilerPath), vcvarsallPath}); + } + } + + return result; +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/clangclinfo.h b/src/lib/corelib/tools/clangclinfo.h new file mode 100644 index 000000000..76ae169f2 --- /dev/null +++ b/src/lib/corelib/tools/clangclinfo.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QBS_CLANGCLINFO_H +#define QBS_CLANGCLINFO_H + +#include "logging/logger.h" + +#include <QtCore/qstring.h> + +#include <vector> + +namespace qbs { +namespace Internal { + +class ClangClInfo +{ +public: + QString toolchainInstallPath; + QString vcvarsallPath; + + bool isEmpty() const { return toolchainInstallPath.isEmpty() && vcvarsallPath.isEmpty(); } + + QBS_EXPORT QVariantMap toVariantMap() const; + + QBS_EXPORT static ClangClInfo fromCompilerFilePath(const QString &path, Logger &logger); + QBS_EXPORT static std::vector<ClangClInfo> installedCompilers( + const std::vector<QString> &extraPaths, qbs::Internal::Logger &logger); +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_CLANGCLINFO_H diff --git a/src/lib/corelib/tools/cleanoptions.cpp b/src/lib/corelib/tools/cleanoptions.cpp index b888fb1e8..affc9b3f7 100644 --- a/src/lib/corelib/tools/cleanoptions.cpp +++ b/src/lib/corelib/tools/cleanoptions.cpp @@ -58,7 +58,7 @@ public: bool logElapsedTime; }; -} +} // namespace Internal /*! * \class CleanOptions @@ -79,23 +79,15 @@ CleanOptions::CleanOptions() : d(new Internal::CleanOptionsPrivate) { } -CleanOptions::CleanOptions(const CleanOptions &other) : d(other.d) -{ -} +CleanOptions::CleanOptions(const CleanOptions &other) = default; CleanOptions::CleanOptions(CleanOptions &&other) Q_DECL_NOEXCEPT = default; -CleanOptions &CleanOptions::operator=(const CleanOptions &other) -{ - d = other.d; - return *this; -} +CleanOptions &CleanOptions::operator=(const CleanOptions &other) = default; CleanOptions &CleanOptions::operator=(CleanOptions &&other) Q_DECL_NOEXCEPT = default; -CleanOptions::~CleanOptions() -{ -} +CleanOptions::~CleanOptions() = default; /*! * \brief Returns true iff qbs will not actually remove any files, but just show what would happen. diff --git a/src/lib/corelib/tools/codelocation.cpp b/src/lib/corelib/tools/codelocation.cpp index 5eff378e1..542408795 100644 --- a/src/lib/corelib/tools/codelocation.cpp +++ b/src/lib/corelib/tools/codelocation.cpp @@ -75,9 +75,7 @@ public: int column = 0; }; -CodeLocation::CodeLocation() -{ -} +CodeLocation::CodeLocation() = default; CodeLocation::CodeLocation(const QString &aFilePath, int aLine, int aColumn, bool checkPath) : d(new CodeLocationPrivate) @@ -88,19 +86,11 @@ CodeLocation::CodeLocation(const QString &aFilePath, int aLine, int aColumn, boo d->column = aColumn; } -CodeLocation::CodeLocation(const CodeLocation &other) : d(other.d) -{ -} +CodeLocation::CodeLocation(const CodeLocation &other) = default; -CodeLocation &CodeLocation::operator=(const CodeLocation &other) -{ - d = other.d; - return *this; -} +CodeLocation &CodeLocation::operator=(const CodeLocation &other) = default; -CodeLocation::~CodeLocation() -{ -} +CodeLocation::~CodeLocation() = default; QString CodeLocation::filePath() const { diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp index fc0b9377e..ff7ce46cf 100644 --- a/src/lib/corelib/tools/error.cpp +++ b/src/lib/corelib/tools/error.cpp @@ -89,6 +89,8 @@ ErrorItem::ErrorItem() : d(new ErrorItemPrivate) { } +ErrorItem::ErrorItem(ErrorItem &&rhs) noexcept = default; + ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocation, bool isBacktraceItem) : d(new ErrorItemPrivate) @@ -98,19 +100,12 @@ ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocatio d->isBacktraceItem = isBacktraceItem; } -ErrorItem::ErrorItem(const ErrorItem &rhs) : d(rhs.d) -{ -} +ErrorItem::ErrorItem(const ErrorItem &rhs) = default; -ErrorItem &ErrorItem::operator=(const ErrorItem &other) -{ - d = other.d; - return *this; -} +ErrorItem &ErrorItem::operator=(const ErrorItem &other) = default; +ErrorItem &ErrorItem::operator=(ErrorItem &&other) noexcept = default; -ErrorItem::~ErrorItem() -{ -} +ErrorItem::~ErrorItem() = default; QString ErrorItem::description() const { @@ -194,9 +189,9 @@ ErrorInfo::ErrorInfo() : d(new ErrorInfoPrivate) { } -ErrorInfo::ErrorInfo(const ErrorInfo &rhs) : d(rhs.d) -{ -} +ErrorInfo::ErrorInfo(const ErrorInfo &rhs) = default; + +ErrorInfo::ErrorInfo(ErrorInfo &&rhs) noexcept = default; ErrorInfo::ErrorInfo(const QString &description, const CodeLocation &location, bool internalError) : d(new ErrorInfoPrivate) @@ -223,16 +218,11 @@ ErrorInfo::ErrorInfo(const QString &description, const QStringList &backtrace) } } +ErrorInfo &ErrorInfo::operator=(ErrorInfo &&other) noexcept = default; -ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other) -{ - d = other.d; - return *this; -} +ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other) = default; -ErrorInfo::~ErrorInfo() -{ -} +ErrorInfo::~ErrorInfo() = default; void ErrorInfo::appendBacktrace(const QString &description, const CodeLocation &location) { diff --git a/src/lib/corelib/tools/error.h b/src/lib/corelib/tools/error.h index abad85bad..36cf5e0ea 100644 --- a/src/lib/corelib/tools/error.h +++ b/src/lib/corelib/tools/error.h @@ -63,7 +63,9 @@ class QBS_EXPORT ErrorItem public: ErrorItem(); ErrorItem(const ErrorItem &rhs); + ErrorItem(ErrorItem &&rhs) noexcept; ErrorItem &operator=(const ErrorItem &other); + ErrorItem &operator=(ErrorItem &&other) noexcept; ~ErrorItem(); QString description() const; @@ -89,10 +91,12 @@ class QBS_EXPORT ErrorInfo public: ErrorInfo(); ErrorInfo(const ErrorInfo &rhs); + ErrorInfo(ErrorInfo &&rhs) noexcept; ErrorInfo(const QString &description, const CodeLocation &location = CodeLocation(), bool internalError = false); ErrorInfo(const QString &description, const QStringList &backtrace); ErrorInfo &operator=(const ErrorInfo &other); + ErrorInfo &operator=(ErrorInfo &&other) noexcept; ~ErrorInfo(); void appendBacktrace(const QString &description, const CodeLocation &location = CodeLocation()); diff --git a/src/lib/corelib/tools/executablefinder.cpp b/src/lib/corelib/tools/executablefinder.cpp index 4342c82f0..0dc06dd86 100644 --- a/src/lib/corelib/tools/executablefinder.cpp +++ b/src/lib/corelib/tools/executablefinder.cpp @@ -64,9 +64,9 @@ static QStringList populateExecutableSuffixes() QStringList ExecutableFinder::m_executableSuffixes = populateExecutableSuffixes(); -ExecutableFinder::ExecutableFinder(ResolvedProductPtr product, QProcessEnvironment env) +ExecutableFinder::ExecutableFinder(ResolvedProductPtr product, const QProcessEnvironment &env) : m_product(std::move(product)) - , m_environment(std::move(env)) + , m_environment(env) // QProcessEnvironment doesn't have move-ctor, copy here { } diff --git a/src/lib/corelib/tools/executablefinder.h b/src/lib/corelib/tools/executablefinder.h index 9467756fc..ae834d911 100644 --- a/src/lib/corelib/tools/executablefinder.h +++ b/src/lib/corelib/tools/executablefinder.h @@ -53,7 +53,7 @@ namespace Internal { class ExecutableFinder { public: - ExecutableFinder(ResolvedProductPtr product, QProcessEnvironment env); + ExecutableFinder(ResolvedProductPtr product, const QProcessEnvironment &env); QString findExecutable(const QString &path, const QString &workingDirPath); diff --git a/src/lib/corelib/tools/fileinfo.cpp b/src/lib/corelib/tools/fileinfo.cpp index 8b0eedc27..1918117d6 100644 --- a/src/lib/corelib/tools/fileinfo.cpp +++ b/src/lib/corelib/tools/fileinfo.cpp @@ -50,7 +50,7 @@ #include <QtCore/qregexp.h> #if defined(Q_OS_UNIX) -#include <errno.h> +#include <cerrno> #include <sys/stat.h> #include <unistd.h> #elif defined(Q_OS_WIN) diff --git a/src/lib/corelib/tools/generateoptions.cpp b/src/lib/corelib/tools/generateoptions.cpp index 019e2eb48..596e0acb9 100644 --- a/src/lib/corelib/tools/generateoptions.cpp +++ b/src/lib/corelib/tools/generateoptions.cpp @@ -68,19 +68,11 @@ GenerateOptions::GenerateOptions() : d(new Internal::GenerateOptionsPrivate) { } -GenerateOptions::GenerateOptions(const GenerateOptions &other) : d(other.d) -{ -} +GenerateOptions::GenerateOptions(const GenerateOptions &other) = default; -GenerateOptions &GenerateOptions::operator=(const GenerateOptions &other) -{ - d = other.d; - return *this; -} +GenerateOptions &GenerateOptions::operator=(const GenerateOptions &other) = default; -GenerateOptions::~GenerateOptions() -{ -} +GenerateOptions::~GenerateOptions() = default; /*! * Returns the name of the generator used to create the external build system files. diff --git a/src/lib/corelib/tools/hostosinfo.h b/src/lib/corelib/tools/hostosinfo.h index d7f718c19..0876d39ec 100644 --- a/src/lib/corelib/tools/hostosinfo.h +++ b/src/lib/corelib/tools/hostosinfo.h @@ -112,6 +112,13 @@ public: return finalName; } + static QString stripExecutableSuffix(const QString &executable) + { + constexpr QLatin1String suffix(QBS_HOST_EXE_SUFFIX, sizeof(QBS_HOST_EXE_SUFFIX) - 1); + return !suffix.isEmpty() && executable.endsWith(suffix) + ? executable.chopped(suffix.size()) : executable; + } + static QString dynamicLibraryName(const QString &libraryBaseName) { return QLatin1String(QBS_HOST_DYNAMICLIB_PREFIX) + libraryBaseName @@ -194,22 +201,21 @@ std::vector<std::string> HostOsInfo::hostOSIdentifiers() std::vector<std::string> HostOsInfo::canonicalOSIdentifiers(const std::string &name) { std::vector<std::string> list { name }; - if (contains(std::vector<std::string> {"ios-simulator"}, name)) + if (contains({"ios-simulator"}, name)) list << canonicalOSIdentifiers("ios"); - if (contains(std::vector<std::string> {"tvos-simulator"}, name)) + if (contains({"tvos-simulator"}, name)) list << canonicalOSIdentifiers("tvos"); - if (contains(std::vector<std::string> {"watchos-simulator"}, name)) + if (contains({"watchos-simulator"}, name)) list << canonicalOSIdentifiers("watchos"); - if (contains(std::vector<std::string> {"macos", "ios", "tvos", "watchos"}, name)) + if (contains({"macos", "ios", "tvos", "watchos"}, name)) list << canonicalOSIdentifiers("darwin"); - if (contains(std::vector<std::string> {"darwin", "freebsd", "netbsd", "openbsd"}, name)) + if (contains({"darwin", "freebsd", "netbsd", "openbsd"}, name)) list << canonicalOSIdentifiers("bsd"); - if (contains(std::vector<std::string> {"android"}, name)) + if (contains({"android"}, name)) list << canonicalOSIdentifiers("linux"); // Note: recognized non-Unix platforms include: windows, haiku, vxworks - if (contains(std::vector<std::string> { - "bsd", "aix", "hpux", "solaris", "linux", "hurd", "qnx", "integrity"}, name)) + if (contains({"bsd", "aix", "hpux", "solaris", "linux", "hurd", "qnx", "integrity"}, name)) list << canonicalOSIdentifiers("unix"); return list; diff --git a/src/lib/corelib/tools/id.cpp b/src/lib/corelib/tools/id.cpp index 6dd1147f2..33cfd60f7 100644 --- a/src/lib/corelib/tools/id.cpp +++ b/src/lib/corelib/tools/id.cpp @@ -269,9 +269,9 @@ Id Id::withPrefix(const char *prefix) const bool Id::operator==(const char *name) const { - const char *string = getStringFromId(m_id); - if (string && name) - return strcmp(string, name) == 0; + const auto string = getStringFromId(m_id); + if (!string.isNull() && name) + return strcmp(string.data(), name) == 0; else return false; } diff --git a/src/lib/corelib/tools/id.h b/src/lib/corelib/tools/id.h index f0c3b1588..aa327833f 100644 --- a/src/lib/corelib/tools/id.h +++ b/src/lib/corelib/tools/id.h @@ -75,7 +75,7 @@ public: bool operator>(Id id) const { return m_id > id.m_id; } bool alphabeticallyBefore(Id other) const; int uniqueIdentifier() const { return m_id; } - static Id fromUniqueIdentifier(int uid) { return Id(uid); } + static Id fromUniqueIdentifier(int uid) { return {uid}; } static Id fromSetting(const QVariant &variant); // Good to use. private: diff --git a/src/lib/corelib/tools/installoptions.cpp b/src/lib/corelib/tools/installoptions.cpp index 93fd54efe..5e112e6de 100644 --- a/src/lib/corelib/tools/installoptions.cpp +++ b/src/lib/corelib/tools/installoptions.cpp @@ -92,23 +92,15 @@ InstallOptions::InstallOptions() : d(new Internal::InstallOptionsPrivate) { } -InstallOptions::InstallOptions(const InstallOptions &other) : d(other.d) -{ -} +InstallOptions::InstallOptions(const InstallOptions &other) = default; InstallOptions::InstallOptions(InstallOptions &&other) Q_DECL_NOEXCEPT = default; -InstallOptions &InstallOptions::operator=(const InstallOptions &other) -{ - d = other.d; - return *this; -} +InstallOptions &InstallOptions::operator=(const InstallOptions &other) = default; InstallOptions &InstallOptions::operator=(InstallOptions &&other) Q_DECL_NOEXCEPT = default; -InstallOptions::~InstallOptions() -{ -} +InstallOptions::~InstallOptions() = default; /*! * \brief The default install root, relative to the build directory. diff --git a/src/lib/corelib/tools/joblimits.cpp b/src/lib/corelib/tools/joblimits.cpp index 1a3e3a498..54c8c98ba 100644 --- a/src/lib/corelib/tools/joblimits.cpp +++ b/src/lib/corelib/tools/joblimits.cpp @@ -87,13 +87,9 @@ JobLimit::JobLimit() : JobLimit(QString(), -1) JobLimit::JobLimit(const QString &pool, int limit) : d(new Internal::JobLimitPrivate(pool, limit)) { } -JobLimit::JobLimit(const JobLimit &other) : d(other.d) { } -JobLimit &JobLimit::operator=(const JobLimit &other) -{ - d = other.d; - return *this; -} -JobLimit::~JobLimit() {} +JobLimit::JobLimit(const JobLimit &other) = default; +JobLimit &JobLimit::operator=(const JobLimit &other) = default; +JobLimit::~JobLimit() = default; QString JobLimit::pool() const { return d->jobLimit.first; } int JobLimit::limit() const { return d->jobLimit.second; } @@ -108,13 +104,9 @@ void JobLimit::store(Internal::PersistentPool &pool) } JobLimits::JobLimits() : d(new Internal::JobLimitsPrivate) { } -JobLimits::JobLimits(const JobLimits &other) : d(other.d) { } -JobLimits &JobLimits::operator=(const JobLimits &other) -{ - d = other.d; - return *this; -} -JobLimits::~JobLimits() {} +JobLimits::JobLimits(const JobLimits &other) = default; +JobLimits &JobLimits::operator=(const JobLimits &other) = default; +JobLimits::~JobLimits() = default; void JobLimits::setJobLimit(const JobLimit &limit) { diff --git a/src/lib/corelib/tools/jsonhelper.h b/src/lib/corelib/tools/jsonhelper.h index d87802c0a..991d6bd6c 100644 --- a/src/lib/corelib/tools/jsonhelper.h +++ b/src/lib/corelib/tools/jsonhelper.h @@ -78,9 +78,9 @@ template<> inline QProcessEnvironment fromJson(const QJsonValue &v) template<typename T> inline void setValueFromJson(T &targetValue, const QJsonObject &data, const char *jsonProperty) { - const QJsonValue v = data.value(QLatin1String(jsonProperty)); - if (!v.isNull()) - targetValue = fromJson<T>(v); + const auto it = data.find(QLatin1String(jsonProperty)); + if (it != data.end()) + targetValue = fromJson<T>(*it); } } // namespace Internal diff --git a/src/lib/corelib/tools/launcherinterface.cpp b/src/lib/corelib/tools/launcherinterface.cpp index f4e80c5e2..50ac659a9 100644 --- a/src/lib/corelib/tools/launcherinterface.cpp +++ b/src/lib/corelib/tools/launcherinterface.cpp @@ -108,9 +108,7 @@ void LauncherInterface::doStart() return; } m_process = new LauncherProcess(this); - connect(m_process, - static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), - this, &LauncherInterface::handleProcessError); + connect(m_process, &QProcess::errorOccurred, this, &LauncherInterface::handleProcessError); connect(m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &LauncherInterface::handleProcessFinished); diff --git a/src/lib/corelib/tools/launcherpackets.cpp b/src/lib/corelib/tools/launcherpackets.cpp index aaa931a49..9c7946d73 100644 --- a/src/lib/corelib/tools/launcherpackets.cpp +++ b/src/lib/corelib/tools/launcherpackets.cpp @@ -45,7 +45,7 @@ namespace qbs { namespace Internal { -LauncherPacket::~LauncherPacket() { } +LauncherPacket::~LauncherPacket() = default; QByteArray LauncherPacket::serialize() const { diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp index cffec85b2..462f921a4 100644 --- a/src/lib/corelib/tools/msvcinfo.cpp +++ b/src/lib/corelib/tools/msvcinfo.cpp @@ -38,14 +38,20 @@ ****************************************************************************/ #include "msvcinfo.h" +#include "visualstudioversioninfo.h" +#include <logging/logger.h> #include <tools/error.h> #include <tools/profile.h> #include <tools/stringconstants.h> #include <QtCore/qbytearray.h> #include <QtCore/qdir.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> #include <QtCore/qtemporaryfile.h> @@ -54,6 +60,7 @@ #endif #include <algorithm> +#include <memory> #include <mutex> using namespace qbs; @@ -129,16 +136,18 @@ public: #ifdef Q_OS_WIN static QStringList parseCommandLine(const QString &commandLine) { - QStringList list; - const auto buf = new wchar_t[commandLine.size() + 1]; - buf[commandLine.toWCharArray(buf)] = 0; + const auto buf = std::make_unique<wchar_t[]>(size_t(commandLine.size()) + 1); + buf[size_t(commandLine.toWCharArray(buf.get()))] = 0; int argCount = 0; - LPWSTR *args = CommandLineToArgvW(buf, &argCount); + const auto argsDeleter = [](LPWSTR *p){ LocalFree(p); }; + const auto args = std::unique_ptr<LPWSTR[], decltype(argsDeleter)>( + CommandLineToArgvW(buf.get(), &argCount), argsDeleter); if (!args) throw ErrorInfo(mkStr("Could not parse command line arguments: ") + commandLine); + QStringList list; + list.reserve(argCount); for (int i = 0; i < argCount; ++i) - list.push_back(QString::fromWCharArray(args[i])); - delete[] buf; + list.push_back(QString::fromWCharArray(args[size_t(i)])); return list; } #endif @@ -163,7 +172,7 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath, QStringList out = QString::fromLocal8Bit(runProcess(compilerFilePath, QStringList() << QStringLiteral("/nologo") << backendSwitch - << QString::fromWCharArray(_wgetenv(L"COMSPEC")) + << qEnvironmentVariable("COMSPEC") << QStringLiteral("/c") << languageSwitch << QStringLiteral("NUL"), @@ -206,30 +215,32 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath, static QVariantMap getClangClDefines( const QString &compilerFilePath, const QProcessEnvironment &compilerEnv, - MSVC::CompilerLanguage language) + MSVC::CompilerLanguage language, + const QString &arch) { #ifdef Q_OS_WIN QFileInfo clInfo(compilerFilePath); - QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang.exe")); + QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang-cl.exe")); if (!clangInfo.exists()) throw ErrorInfo(QStringLiteral("%1 does not exist").arg(clangInfo.absoluteFilePath())); - QString languageSwitch; - switch (language) { - case MSVC::CLanguage: - languageSwitch = QStringLiteral("c"); - break; - case MSVC::CPlusPlusLanguage: - languageSwitch = QStringLiteral("c++"); - break; - } QStringList args = { - QStringLiteral("-dM"), - QStringLiteral("-E"), - QStringLiteral("-x"), - languageSwitch, - QStringLiteral("NUL"), + QStringLiteral("/d1PP"), // dump macros + QStringLiteral("/E") // preprocess to stdout }; + + if (language == MSVC::CLanguage) + args.append(QStringLiteral("/TC")); + else if (language == MSVC::CPlusPlusLanguage) + args.append(QStringLiteral("/TP")); + + if (arch == QLatin1String("x86")) + args.append(QStringLiteral("-m32")); + else if (arch == QLatin1String("x86_64")) + args.append(QStringLiteral("-m64")); + + args.append(QStringLiteral("NUL")); // filename + const auto lines = QString::fromLocal8Bit( runProcess( clangInfo.absoluteFilePath(), @@ -239,10 +250,8 @@ static QVariantMap getClangClDefines( QVariantMap result; for (const auto &line: lines) { static const auto defineString = QLatin1String("#define "); - if (!line.startsWith(defineString)) { - throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ") - + lines.join(QLatin1Char('\n'))); - } + if (!line.startsWith(defineString)) + continue; QStringView view(line.data() + defineString.size()); const auto it = std::find(view.begin(), view.end(), QLatin1Char(' ')); if (it == view.end()) { @@ -253,15 +262,230 @@ static QVariantMap getClangClDefines( QStringView value(it + 1, view.end()); result.insert(key.toString(), value.isEmpty() ? QVariant() : QVariant(value.toString())); } + if (result.isEmpty()) { + throw ErrorInfo(QStringLiteral("Cannot determine macroses from compiler frontend output: ") + + lines.join(QLatin1Char('\n'))); + } return result; #else Q_UNUSED(compilerFilePath); Q_UNUSED(compilerEnv); Q_UNUSED(language); + Q_UNUSED(arch); return {}; #endif } +static QString formatVswhereOutput(const QString &out, const QString &err) +{ + QString ret; + if (!out.isEmpty()) { + ret.append(Tr::tr("stdout")).append(QLatin1String(":\n")); + for (const QString &line : out.split(QLatin1Char('\n'))) + ret.append(QLatin1Char('\t')).append(line).append(QLatin1Char('\n')); + } + if (!err.isEmpty()) { + ret.append(Tr::tr("stderr")).append(QLatin1String(":\n")); + for (const QString &line : err.split(QLatin1Char('\n'))) + ret.append(QLatin1Char('\t')).append(line).append(QLatin1Char('\n')); + } + return ret; +} + +static QString wow6432Key() +{ +#ifdef Q_OS_WIN64 + return QStringLiteral("\\Wow6432Node"); +#else + return {}; +#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, Logger &logger) +{ + 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)) { + logger.qbsWarning() << Tr::tr("The vswhere tool failed to run").append(QLatin1String(": ")) + .append(vsWhere.errorString()); + return result; + } + if (vsWhere.exitCode() != 0) { + const QString stdOut = QString::fromLocal8Bit(vsWhere.readAllStandardOutput()); + const QString stdErr = QString::fromLocal8Bit(vsWhere.readAllStandardError()); + logger.qbsWarning() << Tr::tr("The vswhere tool failed to run").append(QLatin1String(".\n")) + .append(formatVswhereOutput(stdOut, stdErr)); + return result; + } + QJsonParseError parseError; + QJsonDocument jsonOutput = QJsonDocument::fromJson(vsWhere.readAllStandardOutput(), + &parseError); + if (parseError.error != QJsonParseError::NoError) { + logger.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(Logger &logger) +{ + const std::vector<MSVCInstallInfo> vsInstallations + = retrieveInstancesFromVSWhere(ProductType::VisualStudio, logger); + const std::vector<MSVCInstallInfo> buildToolInstallations + = retrieveInstancesFromVSWhere(ProductType::BuildTools, logger); + 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; +} + +/* + Returns the list of compilers present in all MSVC installations + (Visual Studios or Build Tools) without the architecture, e.g. + [VC\Tools\MSVC\14.16.27023, VC\Tools\MSVC\14.14.26428, ...] +*/ +static std::vector<MSVC> installedCompilersHelper(Logger &logger) +{ + std::vector<MSVC> msvcs; + std::vector<MSVCInstallInfo> installInfos = installedMSVCsFromVsWhere(logger); + 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()) { + logger.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 MSVC::init() { determineCompilerVersion(); @@ -280,6 +504,28 @@ QString MSVC::architectureFromClPath(const QString &clPath) return parentDirName; } +QString MSVC::canonicalArchitecture(const QString &arch) +{ + if (arch == QLatin1String("x64") || arch == QLatin1String("amd64")) + return QStringLiteral("x86_64"); + return arch; +} + +std::pair<QString, QString> MSVC::getHostTargetArchPair(const QString &arch) +{ + QString hostArch; + QString targetArch; + const int index = arch.indexOf(QLatin1Char('_')); + if (index != -1) { + hostArch = arch.mid(0, index); + targetArch = arch.mid(index); + } else { + hostArch = arch; + targetArch = arch; + } + return {canonicalArchitecture(hostArch), canonicalArchitecture(targetArch)}; +} + QString MSVC::binPathForArchitecture(const QString &arch) const { QString archSubDir; @@ -301,10 +547,106 @@ QVariantMap MSVC::compilerDefines(const QString &compilerFilePath, { const auto compilerName = QFileInfo(compilerFilePath).fileName().toLower(); if (compilerName == QLatin1String("clang-cl.exe")) - return getClangClDefines(compilerFilePath, environment, language); + return getClangClDefines(compilerFilePath, environment, language, architecture); return getMsvcDefines(compilerFilePath, environment, language); } +std::vector<MSVCArchInfo> MSVC::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; +} + +QVariantMap MSVC::toVariantMap() const +{ + return { + {QStringLiteral("version"), version}, + {QStringLiteral("internalVsVersion"), internalVsVersion.toString()}, + {QStringLiteral("vsInstallPath"), vsInstallPath}, + {QStringLiteral("vcInstallPath"), vcInstallPath}, + {QStringLiteral("binPath"), binPath}, + {QStringLiteral("architecture"), architecture}, + }; +} + +/*! + \internal + Returns the list of all compilers present in all MSVC installations + separated by host/target arch, e.g. + [ + VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64, + VC\Tools\MSVC\14.16.27023\bin\Hostx64\x86, + VC\Tools\MSVC\14.16.27023\bin\Hostx64\arm, + VC\Tools\MSVC\14.16.27023\bin\Hostx64\arm64, + VC\Tools\MSVC\14.16.27023\bin\Hostx86\x64, + ... + ] + \note that MSVC.architecture can be either "x64" or "amd64" (depending on the MSVC version) + in case of 64-bit platform (but we use the "x86_64" name...) +*/ +std::vector<MSVC> MSVC::installedCompilers(Logger &logger) +{ + std::vector<MSVC> msvcs; + const auto instMsvcs = installedCompilersHelper(logger); + 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); + } + } + return msvcs; +} + void MSVC::determineCompilerVersion() { QString cppFilePath; @@ -332,3 +674,24 @@ void MSVC::determineCompilerVersion() compilerVersion = Version(versionStr.mid(0, 2).toInt(), versionStr.mid(2, 2).toInt(), versionStr.mid(4).toInt()); } + +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> MSVCInstallInfo::installedMSVCs(Logger &logger) +{ + const auto installInfos = installedMSVCsFromVsWhere(logger); + if (installInfos.empty()) + return installedMSVCsFromRegistry(); + return installInfos; +} diff --git a/src/lib/corelib/tools/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h index b5cf04e84..de4470bf0 100644 --- a/src/lib/corelib/tools/msvcinfo.h +++ b/src/lib/corelib/tools/msvcinfo.h @@ -53,6 +53,14 @@ namespace qbs { namespace Internal { +class Logger; + +struct MSVCArchInfo +{ + QString arch; + QString binPath; +}; + /** * Represents one MSVC installation for one specific target architecture. * There are potentially multiple MSVCs in one Visual Studio installation. @@ -75,7 +83,7 @@ public: QString architecture; QProcessEnvironment environment; - MSVC() { } + MSVC() = default; MSVC(const QString &clPath, QString arch): architecture(std::move(arch)) @@ -90,11 +98,19 @@ public: QBS_EXPORT void init(); QBS_EXPORT static QString architectureFromClPath(const QString &clPath); + QBS_EXPORT static QString canonicalArchitecture(const QString &arch); + QBS_EXPORT static std::pair<QString, QString> getHostTargetArchPair(const QString &arch); QBS_EXPORT QString binPathForArchitecture(const QString &arch) const; QBS_EXPORT QString clPathForArchitecture(const QString &arch) const; QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath, CompilerLanguage language) const; + QBS_EXPORT static std::vector<MSVCArchInfo> findSupportedArchitectures(const MSVC &msvc); + + QBS_EXPORT QVariantMap toVariantMap() const; + + QBS_EXPORT static std::vector<MSVC> installedCompilers(Logger &logger); + private: void determineCompilerVersion(); }; @@ -110,6 +126,16 @@ public: } }; +struct QBS_EXPORT MSVCInstallInfo +{ + QString version; + QString installDir; + + QString findVcvarsallBat() const; + + static std::vector<MSVCInstallInfo> installedMSVCs(Logger &logger); +}; + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp index ea8adf023..3f2b57e01 100644 --- a/src/lib/corelib/tools/persistence.cpp +++ b/src/lib/corelib/tools/persistence.cpp @@ -48,7 +48,7 @@ namespace qbs { namespace Internal { -static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-127"; +static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-128"; NoBuildGraphError::NoBuildGraphError(const QString &filePath) : ErrorInfo(Tr::tr("Build graph not found for configuration '%1'. Expected location was '%2'.") @@ -62,10 +62,7 @@ PersistentPool::PersistentPool(Logger &logger) : m_logger(logger) m_stream.setVersion(QDataStream::Qt_4_8); } -PersistentPool::~PersistentPool() -{ - closeStream(); -} +PersistentPool::~PersistentPool() = default; void PersistentPool::load(const QString &filePath) { @@ -89,7 +86,7 @@ void PersistentPool::load(const QString &filePath) } m_stream >> m_headData.projectConfig; - file.release(); + m_file = std::move(file); m_loadedRaw.clear(); m_loaded.clear(); m_storageIndices.clear(); @@ -116,7 +113,8 @@ void PersistentPool::setupWriteStream(const QString &filePath) "Cannot open file '%1' for writing: %2").arg(filePath, file->errorString())); } - m_stream.setDevice(file.release()); + m_stream.setDevice(file.get()); + m_file = std::move(file); m_stream << QByteArray(qstrlen(QBS_PERSISTENCE_MAGIC), 0) << m_headData.projectConfig; m_lastStoredObjectId = 0; m_lastStoredStringId = 0; @@ -140,14 +138,6 @@ void PersistentPool::finalizeWriteStream() } } -void PersistentPool::closeStream() -{ - delete m_stream.device(); - m_stream.setDevice(nullptr); -} - - - void PersistentPool::storeVariant(const QVariant &variant) { const auto type = static_cast<quint32>(variant.type()); diff --git a/src/lib/corelib/tools/persistence.h b/src/lib/corelib/tools/persistence.h index 4bda59f7c..e00310321 100644 --- a/src/lib/corelib/tools/persistence.h +++ b/src/lib/corelib/tools/persistence.h @@ -128,7 +128,6 @@ public: void load(const QString &filePath); void setupWriteStream(const QString &filePath); void finalizeWriteStream(); - void closeStream(); void clear(); const HeadData &headData() const { return m_headData; } @@ -167,6 +166,7 @@ private: static const PersistentObjectId ValueNotFoundId = -1; static const PersistentObjectId EmptyValueId = -2; + std::unique_ptr<QIODevice> m_file; QDataStream m_stream; HeadData m_headData; std::vector<void *> m_loadedRaw; diff --git a/src/lib/corelib/tools/processresult.cpp b/src/lib/corelib/tools/processresult.cpp index 3fb2f8dbc..d5591a7ed 100644 --- a/src/lib/corelib/tools/processresult.cpp +++ b/src/lib/corelib/tools/processresult.cpp @@ -53,19 +53,11 @@ ProcessResult::ProcessResult() : d(new Internal::ProcessResultPrivate) { } -ProcessResult::ProcessResult(const ProcessResult &other) : d(other.d) -{ -} +ProcessResult::ProcessResult(const ProcessResult &other) = default; -ProcessResult &ProcessResult::operator=(const ProcessResult &other) -{ - d = other.d; - return *this; -} +ProcessResult &ProcessResult::operator=(const ProcessResult &other) = default; -ProcessResult::~ProcessResult() -{ -} +ProcessResult::~ProcessResult() = default; /*! * \brief Returns true iff the command finished successfully. diff --git a/src/lib/corelib/tools/processutils.cpp b/src/lib/corelib/tools/processutils.cpp index 04a061e0c..b27592f88 100644 --- a/src/lib/corelib/tools/processutils.cpp +++ b/src/lib/corelib/tools/processutils.cpp @@ -92,7 +92,8 @@ QString processNameByPid(qint64 pid) char buf[PATH_MAX]; memset(buf, 0, sizeof(buf)); sprintf(exePath, "/proc/%lld/exe", pid); - readlink(exePath, buf, sizeof(buf)); + if (readlink(exePath, buf, sizeof(buf)) < 0) + return {}; return FileInfo::fileName(QString::fromUtf8(buf)); #elif defined(Q_OS_BSD4) # if defined(Q_OS_NETBSD) diff --git a/src/lib/corelib/tools/profile.cpp b/src/lib/corelib/tools/profile.cpp index 7e594fd2d..2eac25091 100644 --- a/src/lib/corelib/tools/profile.cpp +++ b/src/lib/corelib/tools/profile.cpp @@ -63,13 +63,13 @@ namespace qbs { /*! * \brief Creates an object giving access to the settings for profile \c name. */ -Profile::Profile(const QString &name, Settings *settings, const QVariantMap &profiles) - : m_name(name), +Profile::Profile(QString name, Settings *settings, QVariantMap profiles) + : m_name(std::move(name)), m_settings(settings), - m_values(profiles.value(name).toMap()), - m_profiles(profiles) + m_values(profiles.value(m_name).toMap()), + m_profiles(std::move(profiles)) { - QBS_ASSERT(name == cleanName(name), return); + QBS_ASSERT(m_name == cleanName(m_name), return); } bool Profile::exists() const diff --git a/src/lib/corelib/tools/profile.h b/src/lib/corelib/tools/profile.h index aa8b7ef10..0eee23ae4 100644 --- a/src/lib/corelib/tools/profile.h +++ b/src/lib/corelib/tools/profile.h @@ -55,7 +55,7 @@ class Settings; class QBS_EXPORT Profile { public: - Profile(const QString &name, Settings *settings, const QVariantMap &profiles = QVariantMap()); + Profile(QString name, Settings *settings, QVariantMap profiles = QVariantMap()); bool exists() const; QVariant value(const QString &key, const QVariant &defaultValue = QVariant(), diff --git a/src/lib/corelib/tools/progressobserver.h b/src/lib/corelib/tools/progressobserver.h index 72b9694ba..fc49d9eed 100644 --- a/src/lib/corelib/tools/progressobserver.h +++ b/src/lib/corelib/tools/progressobserver.h @@ -51,7 +51,7 @@ namespace Internal { class ProgressObserver { public: - virtual ~ProgressObserver() { } + virtual ~ProgressObserver() = default; virtual void initialize(const QString &task, int maximum) = 0; virtual void setProgressValue(int value) = 0; diff --git a/src/lib/corelib/tools/projectgeneratormanager.cpp b/src/lib/corelib/tools/projectgeneratormanager.cpp index 3991adfb9..53d72bcd1 100644 --- a/src/lib/corelib/tools/projectgeneratormanager.cpp +++ b/src/lib/corelib/tools/projectgeneratormanager.cpp @@ -52,9 +52,7 @@ namespace qbs { using namespace Internal; -ProjectGeneratorManager::~ProjectGeneratorManager() -{ -} +ProjectGeneratorManager::~ProjectGeneratorManager() = default; ProjectGeneratorManager *ProjectGeneratorManager::instance() { @@ -62,9 +60,7 @@ ProjectGeneratorManager *ProjectGeneratorManager::instance() return &generatorPlugin; } -ProjectGeneratorManager::ProjectGeneratorManager() -{ -} +ProjectGeneratorManager::ProjectGeneratorManager() = default; QStringList ProjectGeneratorManager::loadedGeneratorNames() { diff --git a/src/lib/corelib/tools/qttools.h b/src/lib/corelib/tools/qttools.h index c3b4d3a9f..04fd7d95e 100644 --- a/src/lib/corelib/tools/qttools.h +++ b/src/lib/corelib/tools/qttools.h @@ -42,6 +42,7 @@ #include <QtCore/qhash.h> #include <QtCore/qstringlist.h> +#include <QtCore/qtextstream.h> #include <functional> @@ -66,8 +67,16 @@ template<typename T1, typename T2> struct hash<std::pair<T1, T2>> } // namespace std QT_BEGIN_NAMESPACE + uint qHash(const QStringList &list); uint qHash(const QProcessEnvironment &env); + +#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) +namespace Qt { +inline QTextStream &endl(QTextStream &stream) { return stream << QT_PREPEND_NAMESPACE(endl); } +} // namespace Qt +#endif + QT_END_NAMESPACE namespace qbs { @@ -82,6 +91,16 @@ QSet<T> toSet(const QList<T> &list) #endif } +template<class T> +QList<T> toList(const QSet<T> &set) +{ +#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) + return set.toList(); +#else + return QList<T>(set.begin(), set.end()); +#endif +} + } // namespace qbs diff --git a/src/lib/corelib/tools/scannerpluginmanager.cpp b/src/lib/corelib/tools/scannerpluginmanager.cpp index d6b564832..378f0e11b 100644 --- a/src/lib/corelib/tools/scannerpluginmanager.cpp +++ b/src/lib/corelib/tools/scannerpluginmanager.cpp @@ -51,9 +51,7 @@ public: std::map<FileTag, std::vector<ScannerPlugin* >> scannerPlugins; }; -ScannerPluginManager::~ScannerPluginManager() -{ -} +ScannerPluginManager::~ScannerPluginManager() = default; ScannerPluginManager *ScannerPluginManager::instance() { diff --git a/src/lib/corelib/tools/set.h b/src/lib/corelib/tools/set.h index eb3bf6632..d2af77d73 100644 --- a/src/lib/corelib/tools/set.h +++ b/src/lib/corelib/tools/set.h @@ -98,7 +98,7 @@ public: const_iterator constBegin() const { return m_data.cbegin(); } const_iterator constEnd() const { return m_data.cend(); } - Set() { } + Set() = default; Set(const std::initializer_list<T> &list); Set &unite(const Set &other); diff --git a/src/lib/corelib/tools/settings.cpp b/src/lib/corelib/tools/settings.cpp index 7312cd622..fccb9c9b2 100644 --- a/src/lib/corelib/tools/settings.cpp +++ b/src/lib/corelib/tools/settings.cpp @@ -91,8 +91,8 @@ Settings::Settings(const QString &baseDir) : Settings(baseDir, systemSettingsBas Settings::Settings(const QString &baseDir, const QString &systemBaseDir) : m_settings(SettingsCreator(baseDir).getQSettings()), - m_systemSettings(new QSettings(systemBaseDir + QStringLiteral("/qbs.conf"), - QSettings::IniFormat)), + m_systemSettings(std::make_unique<QSettings>(systemBaseDir + QStringLiteral("/qbs.conf"), + QSettings::IniFormat)), m_baseDir(baseDir) { // Actual qbs settings are stored transparently within a group, because QSettings @@ -100,11 +100,7 @@ Settings::Settings(const QString &baseDir, const QString &systemBaseDir) m_settings->beginGroup(QStringLiteral("org/qt-project/qbs")); } -Settings::~Settings() -{ - delete m_settings; - delete m_systemSettings; -} +Settings::~Settings() = default; QVariant Settings::value(const QString &key, Scopes scopes, const QVariant &defaultValue) const { @@ -241,7 +237,7 @@ void Settings::fixupKeys(QStringList &keys) const QSettings *Settings::settingsForScope(Settings::Scope scope) const { - return scope == UserScope ? m_settings : m_systemSettings; + return scope == UserScope ? m_settings.get() : m_systemSettings.get(); } QSettings *Settings::targetForWriting() const diff --git a/src/lib/corelib/tools/settings.h b/src/lib/corelib/tools/settings.h index d4de08490..638216669 100644 --- a/src/lib/corelib/tools/settings.h +++ b/src/lib/corelib/tools/settings.h @@ -45,6 +45,8 @@ #include <QtCore/qstring.h> #include <QtCore/qvariant.h> +#include <memory> + QT_BEGIN_NAMESPACE class QSettings; class QStringList; @@ -94,8 +96,8 @@ private: QSettings *targetForWriting() const; void checkForWriteError(); - QSettings * const m_settings; - QSettings * const m_systemSettings; + const std::unique_ptr<QSettings> m_settings; + const std::unique_ptr<QSettings> m_systemSettings; const QString m_baseDir; Scope m_scopeForWriting = UserScope; }; diff --git a/src/lib/corelib/tools/settingscreator.cpp b/src/lib/corelib/tools/settingscreator.cpp index eaaf2802c..36e67440c 100644 --- a/src/lib/corelib/tools/settingscreator.cpp +++ b/src/lib/corelib/tools/settingscreator.cpp @@ -1,3 +1,4 @@ +#include <memory> #include <utility> /**************************************************************************** @@ -64,11 +65,11 @@ SettingsCreator::SettingsCreator(QString baseDir) { } -QSettings *SettingsCreator::getQSettings() +std::unique_ptr<QSettings> SettingsCreator::getQSettings() { createQSettings(); migrate(); - return m_settings.release(); + return std::move(m_settings); } void SettingsCreator::migrate() @@ -104,7 +105,7 @@ void SettingsCreator::migrate() // Adapt all paths in settings that point to the old location. At the time of this writing, // that's only preferences.qbsSearchPaths as written by libqtprofilesetup, but we don't want // to hardcode that here. - m_settings.reset(new QSettings(m_newSettingsFilePath, format())); + m_settings = std::make_unique<QSettings>(m_newSettingsFilePath, format()); const auto allKeys = m_settings->allKeys(); for (const QString &key : allKeys) { QVariant v = m_settings->value(key); @@ -136,7 +137,7 @@ void SettingsCreator::createQSettings() m_newSettingsDir = m_settingsBaseDir + QLatin1String("/qbs/") + m_qbsVersion.toString(); m_settingsFileName = fi.fileName(); m_newSettingsFilePath = m_newSettingsDir + QLatin1Char('/') + m_settingsFileName; - m_settings.reset(new QSettings(m_newSettingsFilePath, tmp->format())); + m_settings = std::make_unique<QSettings>(m_newSettingsFilePath, tmp->format()); } Version SettingsCreator::predecessor() const diff --git a/src/lib/corelib/tools/settingscreator.h b/src/lib/corelib/tools/settingscreator.h index 39da80a7f..ab491105c 100644 --- a/src/lib/corelib/tools/settingscreator.h +++ b/src/lib/corelib/tools/settingscreator.h @@ -58,7 +58,7 @@ class SettingsCreator public: SettingsCreator(QString baseDir); - QSettings *getQSettings(); + std::unique_ptr<QSettings> getQSettings(); private: void migrate(); diff --git a/src/lib/corelib/tools/settingsmodel.cpp b/src/lib/corelib/tools/settingsmodel.cpp index d67f1da5c..7283e959c 100644 --- a/src/lib/corelib/tools/settingsmodel.cpp +++ b/src/lib/corelib/tools/settingsmodel.cpp @@ -125,7 +125,7 @@ public: SettingsModel::SettingsModel(const QString &settingsDir, Settings::Scope scope, QObject *parent) : QAbstractItemModel(parent), d(new SettingsModelPrivate) { - d->settings.reset(new qbs::Settings(settingsDir)); + d->settings = std::make_unique<qbs::Settings>(settingsDir); d->settings->setScopeForWriting(scope); d->readSettings(); } @@ -155,7 +155,7 @@ void SettingsModel::updateSettingsDir(const QString &settingsDir) { const Settings::Scope scope = d->scope(); beginResetModel(); - d->settings.reset(new qbs::Settings(settingsDir)); + d->settings = std::make_unique<qbs::Settings>(settingsDir); d->settings->setScopeForWriting(scope); d->readSettings(); endResetModel(); diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp index 41af7b926..a06ffc4bd 100644 --- a/src/lib/corelib/tools/setupprojectparameters.cpp +++ b/src/lib/corelib/tools/setupprojectparameters.cpp @@ -107,21 +107,15 @@ SetupProjectParameters::SetupProjectParameters() : d(new Internal::SetupProjectP { } -SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) : d(other.d) -{ -} +SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) = default; -SetupProjectParameters::SetupProjectParameters(SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default; +SetupProjectParameters::SetupProjectParameters( + SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default; -SetupProjectParameters::~SetupProjectParameters() -{ -} +SetupProjectParameters::~SetupProjectParameters() = default; -SetupProjectParameters &SetupProjectParameters::operator=(const SetupProjectParameters &other) -{ - d = other.d; - return *this; -} +SetupProjectParameters &SetupProjectParameters::operator=( + const SetupProjectParameters &other) = default; namespace Internal { template<> ErrorHandlingMode fromJson(const QJsonValue &v) @@ -355,7 +349,7 @@ static void provideValuesTree(const QVariantMap &values, QVariantMap *valueTree) valueTree->clear(); for (QVariantMap::const_iterator it = values.constBegin(); it != values.constEnd(); ++it) { - const QString name = it.key(); + const QString &name = it.key(); int idx = name.lastIndexOf(QLatin1Char('.')); const QStringList nameElements = (idx == -1) ? QStringList() << name diff --git a/src/lib/corelib/tools/shellutils.cpp b/src/lib/corelib/tools/shellutils.cpp index 01c177cce..dae98f337 100644 --- a/src/lib/corelib/tools/shellutils.cpp +++ b/src/lib/corelib/tools/shellutils.cpp @@ -205,12 +205,12 @@ void CommandLine::setProgram(const std::string &program, bool raw) void CommandLine::appendArgument(const QString &value) { - m_arguments.push_back(value); + m_arguments.emplace_back(value); } void CommandLine::appendArgument(const std::string &value) { - m_arguments.push_back(QString::fromStdString(value)); + m_arguments.emplace_back(QString::fromStdString(value)); } void CommandLine::appendArguments(const QList<QString> &args) diff --git a/src/lib/corelib/tools/shellutils.h b/src/lib/corelib/tools/shellutils.h index 6f1d82afb..f4ad35044 100644 --- a/src/lib/corelib/tools/shellutils.h +++ b/src/lib/corelib/tools/shellutils.h @@ -77,7 +77,7 @@ public: private: struct Argument { - Argument(const QString &value = QString()) : value(value) { } + Argument(QString value = QString()) : value(std::move(value)) { } QString value; bool isFilePath = false; bool shouldQuote = true; diff --git a/src/lib/corelib/tools/stlutils.h b/src/lib/corelib/tools/stlutils.h index ad00070cf..5c21c0672 100644 --- a/src/lib/corelib/tools/stlutils.h +++ b/src/lib/corelib/tools/stlutils.h @@ -54,11 +54,18 @@ C sorted(const C &container) return result; } -template <class C> -bool contains(const C &container, const typename C::value_type &v) +template <class C, class T> +bool contains(const C &container, const T &v) { - const auto &end = container.cend(); - return std::find(container.cbegin(), end, v) != end; + const auto &end = std::cend(container); + return std::find(std::cbegin(container), end, v) != end; +} + +template <class T, size_t N, class U> +bool contains(const T (&container)[N], const U &v) +{ + const auto &end = std::cend(container); + return std::find(std::cbegin(container), end, v) != end; } template <class C> diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h index 79cbcd125..f2bc78446 100644 --- a/src/lib/corelib/tools/stringconstants.h +++ b/src/lib/corelib/tools/stringconstants.h @@ -153,6 +153,7 @@ public: QBS_STRING_CONSTANT(searchPathsProperty, "searchPaths") QBS_STRING_CONSTANT(setupBuildEnvironmentProperty, "setupBuildEnvironment") QBS_STRING_CONSTANT(setupRunEnvironmentProperty, "setupRunEnvironment") + QBS_STRING_CONSTANT(shadowProductPrefix, "__shadow__") QBS_STRING_CONSTANT(sourceCodeProperty, "sourceCode") QBS_STRING_CONSTANT(sourceDirectoryProperty, "sourceDirectory") QBS_STRING_CONSTANT(submodulesProperty, "submodules") diff --git a/src/lib/corelib/tools/stringutils.h b/src/lib/corelib/tools/stringutils.h index 7b551a544..59acdccbd 100644 --- a/src/lib/corelib/tools/stringutils.h +++ b/src/lib/corelib/tools/stringutils.h @@ -77,14 +77,14 @@ static inline std::string trimmed(const std::string &s) // trim from start static const auto ltrim = [](std::string &s) -> std::string & { s.erase(s.begin(), std::find_if(s.begin(), s.end(), - std::not1(std::ptr_fun<int, int>(std::isspace)))); + [](char c){ return !std::isspace(c); })); return s; }; // trim from end static const auto rtrim = [](std::string &s) -> std::string & { s.erase(std::find_if(s.rbegin(), s.rend(), - std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); + [](char c){ return !std::isspace(c); }).base(), s.end()); return s; }; diff --git a/src/lib/corelib/tools/toolchains.cpp b/src/lib/corelib/tools/toolchains.cpp index 0d793f8aa..6263fb199 100644 --- a/src/lib/corelib/tools/toolchains.cpp +++ b/src/lib/corelib/tools/toolchains.cpp @@ -49,9 +49,11 @@ namespace qbs { namespace Internal { static const QString clangToolchain() { return QStringLiteral("clang"); } +static const QString clangClToolchain() { return QStringLiteral("clang-cl"); } static const QString gccToolchain() { return QStringLiteral("gcc"); } static const QString llvmToolchain() { return QStringLiteral("llvm"); } static const QString mingwToolchain() { return QStringLiteral("mingw"); } +static const QString msvcToolchain() { return QStringLiteral("msvc"); } } using namespace Internal; @@ -64,7 +66,8 @@ QStringList canonicalToolchain(const QStringList &toolchain) llvmToolchain(), mingwToolchain(), gccToolchain(), - QStringLiteral("msvc") + clangClToolchain(), + msvcToolchain() }; // Canonicalize each toolchain in the toolchain list, @@ -110,6 +113,8 @@ QStringList canonicalToolchain(const QString &name) else if (toolchainName == llvmToolchain() || toolchainName == mingwToolchain()) { toolchains << canonicalToolchain(QStringLiteral("gcc")); + } else if (toolchainName == clangClToolchain()) { + toolchains << canonicalToolchain(msvcToolchain()); } return toolchains; } diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri index 89d752671..00d87ecc7 100644 --- a/src/lib/corelib/tools/tools.pri +++ b/src/lib/corelib/tools/tools.pri @@ -10,6 +10,7 @@ QBS_SYSTEM_SETTINGS_DIR = $$(QBS_SYSTEM_SETTINGS_DIR) HEADERS += \ $$PWD/architectures.h \ $$PWD/buildgraphlocker.h \ + $$PWD/clangclinfo.h \ $$PWD/codelocation.h \ $$PWD/commandechomode.h \ $$PWD/dynamictypecheck.h \ @@ -68,6 +69,7 @@ HEADERS += \ SOURCES += \ $$PWD/architectures.cpp \ $$PWD/buildgraphlocker.cpp \ + $$PWD/clangclinfo.cpp \ $$PWD/codelocation.cpp \ $$PWD/commandechomode.cpp \ $$PWD/error.cpp \ diff --git a/src/lib/corelib/tools/version.cpp b/src/lib/corelib/tools/version.cpp index dfb7f49b7..f653256b3 100644 --- a/src/lib/corelib/tools/version.cpp +++ b/src/lib/corelib/tools/version.cpp @@ -44,50 +44,6 @@ namespace qbs { -Version::Version(int major, int minor, int patch, int buildNr) - : m_major(major), m_minor(minor), m_patch(patch), m_build(buildNr) -{ -} - -int Version::majorVersion() const -{ - return m_major; -} - -void Version::setMajorVersion(int major) -{ - m_major = major; -} - -int Version::minorVersion() const -{ - return m_minor; -} - -void Version::setMinorVersion(int minor) -{ - m_minor = minor; -} -int Version::patchLevel() const -{ - return m_patch; -} - -void Version::setPatchLevel(int patch) -{ - m_patch = patch; -} - -int Version::buildNumber() const -{ - return m_build; -} - -void Version::setBuildNumber(int nr) -{ - m_build = nr; -} - Version Version::fromString(const QString &versionString, bool buildNumberAllowed) { QString pattern = QStringLiteral("(\\d+)"); // At least one number. @@ -118,32 +74,6 @@ QString Version::toString(const QChar &separator, const QChar &buildSeparator) c QString::number(m_patch), separator); } -int compare(const Version &lhs, const Version &rhs) -{ - if (lhs.majorVersion() < rhs.majorVersion()) - return -1; - if (lhs.majorVersion() > rhs.majorVersion()) - return 1; - if (lhs.minorVersion() < rhs.minorVersion()) - return -1; - if (lhs.minorVersion() > rhs.minorVersion()) - return 1; - if (lhs.patchLevel() < rhs.patchLevel()) - return -1; - if (lhs.patchLevel() > rhs.patchLevel()) - return 1; - if (lhs.buildNumber() < rhs.buildNumber()) - return -1; - if (lhs.buildNumber() > rhs.buildNumber()) - return 1; - return 0; -} - -VersionRange::VersionRange(const Version &minVersion, const Version &maxVersion) - : minimum(minVersion), maximum(maxVersion) -{ -} - VersionRange &VersionRange::narrowDown(const VersionRange &other) { if (other.minimum > minimum) diff --git a/src/lib/corelib/tools/version.h b/src/lib/corelib/tools/version.h index a0239a6e4..63ad3f88c 100644 --- a/src/lib/corelib/tools/version.h +++ b/src/lib/corelib/tools/version.h @@ -54,22 +54,24 @@ namespace qbs { class QBS_EXPORT Version { public: - explicit Version(int majorVersion = 0, int minorVersion = 0, int patchLevel = 0, - int buildNr = 0); + constexpr explicit Version(int majorVersion = 0, int minorVersion = 0, int patchLevel = 0, + int buildNr = 0) + : m_major(majorVersion), m_minor(minorVersion), m_patch(patchLevel), m_build(buildNr) + { } - bool isValid() const { return m_major || m_minor || m_patch || m_build; } + constexpr bool isValid() const { return m_major || m_minor || m_patch || m_build; } - int majorVersion() const; - void setMajorVersion(int majorVersion); + constexpr int majorVersion() const { return m_major; } + constexpr void setMajorVersion(int majorVersion) { m_major = majorVersion; } - int minorVersion() const; - void setMinorVersion(int minorVersion); + constexpr int minorVersion() const { return m_minor; } + constexpr void setMinorVersion(int minorVersion) { m_minor = minorVersion;} - int patchLevel() const; - void setPatchLevel(int patchLevel); + constexpr int patchLevel() const { return m_patch; } + constexpr void setPatchLevel(int patchLevel) { m_patch = patchLevel; } - int buildNumber() const; - void setBuildNumber(int nr); + constexpr int buildNumber() const { return m_build; } + constexpr void setBuildNumber(int nr) { m_build = nr; } static Version fromString(const QString &versionString, bool buildNumberAllowed = false); QString toString(const QChar &separator = QLatin1Char('.'), @@ -85,8 +87,10 @@ private: class VersionRange { public: - VersionRange() = default; - VersionRange(const Version &minVersion, const Version &maxVersion); + constexpr VersionRange() = default; + constexpr VersionRange(const Version &minVersion, const Version &maxVersion) + : minimum(minVersion), maximum(maxVersion) + { } Version minimum; Version maximum; // exclusive @@ -94,13 +98,39 @@ public: VersionRange &narrowDown(const VersionRange &other); }; -QBS_EXPORT int compare(const Version &lhs, const Version &rhs); -inline bool operator==(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) == 0; } -inline bool operator!=(const Version &lhs, const Version &rhs) { return !operator==(lhs, rhs); } -inline bool operator<(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) < 0; } -inline bool operator>(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) > 0; } -inline bool operator<=(const Version &lhs, const Version &rhs) { return !operator>(lhs, rhs); } -inline bool operator>=(const Version &lhs, const Version &rhs) { return !operator<(lhs, rhs); } +constexpr inline int compare(const Version &lhs, const Version &rhs) +{ + if (lhs.majorVersion() < rhs.majorVersion()) + return -1; + if (lhs.majorVersion() > rhs.majorVersion()) + return 1; + if (lhs.minorVersion() < rhs.minorVersion()) + return -1; + if (lhs.minorVersion() > rhs.minorVersion()) + return 1; + if (lhs.patchLevel() < rhs.patchLevel()) + return -1; + if (lhs.patchLevel() > rhs.patchLevel()) + return 1; + if (lhs.buildNumber() < rhs.buildNumber()) + return -1; + if (lhs.buildNumber() > rhs.buildNumber()) + return 1; + return 0; +} + +constexpr inline bool operator==(const Version &lhs, const Version &rhs) +{ return compare(lhs, rhs) == 0; } +constexpr inline bool operator!=(const Version &lhs, const Version &rhs) +{ return !operator==(lhs, rhs); } +constexpr inline bool operator<(const Version &lhs, const Version &rhs) +{ return compare(lhs, rhs) < 0; } +constexpr inline bool operator>(const Version &lhs, const Version &rhs) +{ return compare(lhs, rhs) > 0; } +constexpr inline bool operator<=(const Version &lhs, const Version &rhs) +{ return !operator>(lhs, rhs); } +constexpr inline bool operator>=(const Version &lhs, const Version &rhs) +{ return !operator<(lhs, rhs); } } // namespace qbs diff --git a/src/lib/corelib/tools/visualstudioversioninfo.cpp b/src/lib/corelib/tools/visualstudioversioninfo.cpp index d4f8844fa..b5ee3e719 100644 --- a/src/lib/corelib/tools/visualstudioversioninfo.cpp +++ b/src/lib/corelib/tools/visualstudioversioninfo.cpp @@ -46,9 +46,7 @@ namespace qbs { namespace Internal { -VisualStudioVersionInfo::VisualStudioVersionInfo() -{ -} +VisualStudioVersionInfo::VisualStudioVersionInfo() = default; VisualStudioVersionInfo::VisualStudioVersionInfo(const Version &version) : m_version(version) @@ -176,7 +174,7 @@ QString VisualStudioVersionInfo::platformToolsetVersion() const {16, QStringLiteral("v142")}, // VS 2019 {15, QStringLiteral("v141")} // VS 2017 }; - for (auto p : table) { + for (const auto &p : table) { if (p.first == m_version.majorVersion()) return p.second; } diff --git a/src/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp index f8f98e7b7..95451435a 100644 --- a/src/lib/corelib/tools/vsenvironmentdetector.cpp +++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp @@ -193,13 +193,13 @@ bool VsEnvironmentDetector::startDetection(const std::vector<MSVC *> &compatible static void batClearVars(QTextStream &s, const QStringList &varnames) { for (const QString &varname : varnames) - s << "set " << varname << '=' << endl; + s << "set " << varname << '=' << Qt::endl; } static void batPrintVars(QTextStream &s, const QStringList &varnames) { for (const QString &varname : varnames) - s << "echo " << varname << "=%" << varname << '%' << endl; + s << "echo " << varname << "=%" << varname << '%' << Qt::endl; } static QString vcArchitecture(const MSVC *msvc) @@ -232,7 +232,10 @@ void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcv << QStringLiteral("INCLUDE") << QStringLiteral("LIB") << QStringLiteral("WindowsSdkDir") << QStringLiteral("WindowsSDKVersion") << QStringLiteral("VSINSTALLDIR"); QTextStream s(device); + using Qt::endl; s << "@echo off" << endl; + // Avoid execution of powershell (in vsdevcmd.bat), which is not in the cleared PATH + s << "set VSCMD_SKIP_SENDTELEMETRY=1" << endl; for (const MSVC *msvc : msvcs) { s << "echo --" << msvc->architecture << "--" << endl << "setlocal" << endl; diff --git a/src/lib/scriptengine/use_scriptengine.pri b/src/lib/scriptengine/use_scriptengine.pri index 6450e171f..e8f82a949 100644 --- a/src/lib/scriptengine/use_scriptengine.pri +++ b/src/lib/scriptengine/use_scriptengine.pri @@ -3,7 +3,15 @@ isEmpty(QBSLIBDIR) { QBSLIBDIR = $$shadowed($$PWD/../../../$${QBS_LIBRARY_DIRNAME}) } - LIBS += -L$$QBSLIBDIR -lqbsscriptengine$$qtPlatformTargetSuffix() + + LIBS += -L$$QBSLIBDIR + macos { + LIBS += -lqbsscriptengine + } + else { + LIBS += -lqbsscriptengine$$qtPlatformTargetSuffix() + } + } INCLUDEPATH += \ diff --git a/src/libexec/qbs_processlauncher/launchersockethandler.cpp b/src/libexec/qbs_processlauncher/launchersockethandler.cpp index 53bd81a9a..dac1b0b2e 100644 --- a/src/libexec/qbs_processlauncher/launchersockethandler.cpp +++ b/src/libexec/qbs_processlauncher/launchersockethandler.cpp @@ -273,8 +273,7 @@ void LauncherSocketHandler::sendPacket(const LauncherPacket &packet) Process *LauncherSocketHandler::setupProcess(quintptr token) { const auto p = new Process(token, this); - connect(p, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), - this, &LauncherSocketHandler::handleProcessError); + connect(p, &QProcess::errorOccurred, this, &LauncherSocketHandler::handleProcessError); connect(p, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &LauncherSocketHandler::handleProcessFinished); connect(p, &Process::failedToStop, this, &LauncherSocketHandler::handleStopFailure); diff --git a/src/packages/archive/archive.qbs b/src/packages/archive/archive.qbs index 468606368..9a9b09ba7 100644 --- a/src/packages/archive/archive.qbs +++ b/src/packages/archive/archive.qbs @@ -69,7 +69,7 @@ QbsProduct { inputFilePaths.sort(); var tf; try { - tf = new TextFile(outputFilePath, TextFile.ReadWrite); + tf = new TextFile(outputFilePath, TextFile.WriteOnly); for (var i = 0; i < inputFilePaths.length; ++i) { var relativePath = FileInfo.relativePath(baseDirectory, inputFilePaths[i]); tf.writeLine(relativePath); diff --git a/src/packages/chocolatey/chocolatey.qbs b/src/packages/chocolatey/chocolatey.qbs index 27cc1e489..e878f8e0d 100644 --- a/src/packages/chocolatey/chocolatey.qbs +++ b/src/packages/chocolatey/chocolatey.qbs @@ -14,7 +14,7 @@ Product { id: choco condition: qbs.targetOS.contains("windows") names: ["choco"] - platformPaths: { // TODO: Change to platformSearchPaths in qbs 1.15 + platformSearchPaths: { var chocolateyInstall = Environment.getEnv("ChocolateyInstall"); if (chocolateyInstall) return [FileInfo.joinPaths(chocolateyInstall, "bin")]; diff --git a/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp b/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp index bc13ec480..93be2804b 100644 --- a/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp +++ b/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp @@ -58,9 +58,7 @@ using namespace Internal; const QString ClangCompilationDatabaseGenerator::DefaultDatabaseFileName = QStringLiteral("compile_commands.json"); -ClangCompilationDatabaseGenerator::ClangCompilationDatabaseGenerator() -{ -} +ClangCompilationDatabaseGenerator::ClangCompilationDatabaseGenerator() = default; QString ClangCompilationDatabaseGenerator::generatorName() const { diff --git a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp index 911873cf4..0bbfbaafb 100644 --- a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp +++ b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp @@ -499,7 +499,7 @@ void ArmGeneralSettingsGroup::buildLibraryOptionsTwoPage( } void ArmGeneralSettingsGroup::buildLibraryConfigPage( - const QString baseDirectory, + const QString &baseDirectory, const ProductData &qbsProduct) { const LibraryConfigPageOptions opts(baseDirectory, qbsProduct); @@ -523,7 +523,7 @@ void ArmGeneralSettingsGroup::buildLibraryConfigPage( } void ArmGeneralSettingsGroup::buildOutputPage( - const QString baseDirectory, + const QString &baseDirectory, const ProductData &qbsProduct) { const OutputPageOptions opts(baseDirectory, qbsProduct); diff --git a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h index 420e98008..0b1564b3c 100644 --- a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h +++ b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h @@ -49,9 +49,9 @@ private: void buildTargetPage(const ProductData &qbsProduct); void buildLibraryOptionsOnePage(const ProductData &qbsProduct); void buildLibraryOptionsTwoPage(const ProductData &qbsProduct); - void buildLibraryConfigPage(const QString baseDirectory, + void buildLibraryConfigPage(const QString &baseDirectory, const ProductData &qbsProduct); - void buildOutputPage(const QString baseDirectory, + void buildOutputPage(const QString &baseDirectory, const ProductData &qbsProduct); }; diff --git a/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp b/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp index 2d3780e4f..8a9d13b9b 100644 --- a/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp +++ b/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp @@ -175,7 +175,7 @@ struct OptimizationsPageOptions final QLatin1String("--merge_duplicate_sections")); } - bool mergeDuplicateSections = 0; + bool mergeDuplicateSections = true; }; // Output page options. @@ -192,7 +192,7 @@ struct OutputPageOptions final } QString outputFile; - bool enableDebugInfo = 1; + bool enableDebugInfo = true; }; // List page options. diff --git a/src/plugins/generator/iarew/iarew.pro b/src/plugins/generator/iarew/iarew.pro index 074635047..542449510 100644 --- a/src/plugins/generator/iarew/iarew.pro +++ b/src/plugins/generator/iarew/iarew.pro @@ -37,7 +37,6 @@ SOURCES += \ $$PWD/iarewsourcefilespropertygroup.cpp \ $$PWD/iarewtoolchainpropertygroup.cpp \ $$PWD/iarewutils.cpp \ - $$PWD/iarewversioninfo.cpp \ $$PWD/iarewworkspace.cpp \ $$PWD/iarewworkspacewriter.cpp diff --git a/src/plugins/generator/iarew/iarew.qbs b/src/plugins/generator/iarew/iarew.qbs index 7b2270426..82c95ea5d 100644 --- a/src/plugins/generator/iarew/iarew.qbs +++ b/src/plugins/generator/iarew/iarew.qbs @@ -31,7 +31,6 @@ QbsPlugin { "iarewtoolchainpropertygroup.h", "iarewutils.cpp", "iarewutils.h", - "iarewversioninfo.cpp", "iarewversioninfo.h", "iarewworkspace.cpp", "iarewworkspace.h", diff --git a/src/plugins/generator/iarew/iarewfileversionproperty.cpp b/src/plugins/generator/iarew/iarewfileversionproperty.cpp index 446b385b8..4324405a1 100644 --- a/src/plugins/generator/iarew/iarewfileversionproperty.cpp +++ b/src/plugins/generator/iarew/iarewfileversionproperty.cpp @@ -33,21 +33,21 @@ namespace qbs { -static QByteArray buildFileVersion(const IarewVersionInfo &versionInfo) +static QByteArray buildFileVersion(const gen::VersionInfo &versionInfo) { switch (versionInfo.marketingVersion()) { case 3: case 7: case 8: case 10: - return QByteArrayLiteral('3'); + return QByteArrayLiteral("3"); default: return {}; } } IarewFileVersionProperty::IarewFileVersionProperty( - const IarewVersionInfo &versionInfo) + const gen::VersionInfo &versionInfo) { setName(QByteArrayLiteral("fileVersion")); const QByteArray fileVersion = buildFileVersion(versionInfo); diff --git a/src/plugins/generator/iarew/iarewfileversionproperty.h b/src/plugins/generator/iarew/iarewfileversionproperty.h index d377979fa..2ed56c1e6 100644 --- a/src/plugins/generator/iarew/iarewfileversionproperty.h +++ b/src/plugins/generator/iarew/iarewfileversionproperty.h @@ -31,17 +31,16 @@ #ifndef QBS_IAREWFILEVERSIONPROPERTY_H #define QBS_IAREWFILEVERSIONPROPERTY_H +#include <generators/generatorversioninfo.h> #include <generators/xmlproperty.h> namespace qbs { -class IarewVersionInfo; - class IarewFileVersionProperty final : public gen::xml::Property { public: explicit IarewFileVersionProperty( - const IarewVersionInfo &versionInfo); + const gen::VersionInfo &versionInfo); }; } // namespace qbs diff --git a/src/plugins/generator/iarew/iarewgenerator.cpp b/src/plugins/generator/iarew/iarewgenerator.cpp index e6b308182..c5345a6dd 100644 --- a/src/plugins/generator/iarew/iarewgenerator.cpp +++ b/src/plugins/generator/iarew/iarewgenerator.cpp @@ -96,7 +96,7 @@ static void writeWorkspace(const std::shared_ptr<IarewWorkspace> &wokspace, QFileInfo(workspaceFilePath).fileName()); } -IarewGenerator::IarewGenerator(const IarewVersionInfo &versionInfo) +IarewGenerator::IarewGenerator(const gen::VersionInfo &versionInfo) : m_versionInfo(versionInfo) { } diff --git a/src/plugins/generator/iarew/iarewgenerator.h b/src/plugins/generator/iarew/iarewgenerator.h index f8c1298f0..fa1d93bc3 100644 --- a/src/plugins/generator/iarew/iarewgenerator.h +++ b/src/plugins/generator/iarew/iarewgenerator.h @@ -44,7 +44,7 @@ class IarewWorkspace; class IarewGenerator final : public ProjectGenerator, private IGeneratableProjectVisitor { public: - explicit IarewGenerator(const IarewVersionInfo &versionInfo); + explicit IarewGenerator(const gen::VersionInfo &versionInfo); QString generatorName() const final; void generate() final; @@ -59,7 +59,7 @@ private: const GeneratableProjectData &projectData, const GeneratableProductData &productData) final; - const IarewVersionInfo m_versionInfo; + const gen::VersionInfo m_versionInfo; std::shared_ptr<IarewWorkspace> m_workspace; QString m_workspaceFilePath; std::map<QString, std::shared_ptr<IarewProject>> m_projects; diff --git a/src/plugins/generator/iarew/iarewgeneratorplugin.cpp b/src/plugins/generator/iarew/iarewgeneratorplugin.cpp index bd75c7ad5..bdd15c485 100644 --- a/src/plugins/generator/iarew/iarewgeneratorplugin.cpp +++ b/src/plugins/generator/iarew/iarewgeneratorplugin.cpp @@ -45,7 +45,7 @@ static void QbsIarewGeneratorPluginLoad() { - for (const auto &info : qbs::IarewVersionInfo::knownVersions()) { + for (const auto &info : qbs::IarewVersionInfo::knownVersions) { qbs::ProjectGeneratorManager::registerGenerator( std::make_shared<qbs::IarewGenerator>(info)); } diff --git a/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp b/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp index 8b9f79f1c..c44b30ed2 100644 --- a/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp +++ b/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp @@ -33,20 +33,20 @@ namespace qbs { IarewOptionPropertyGroup::IarewOptionPropertyGroup( - QByteArray name, const QVariantList &states, int version) + const QByteArray &name, QVariantList states, int version) : gen::xml::PropertyGroup(QByteArrayLiteral("option")) { // Append name property item. appendChild<gen::xml::Property>(QByteArrayLiteral("name"), - std::move(name)); + name); // Append version property item. if (version >= 0) appendChild<gen::xml::Property>(QByteArrayLiteral("version"), - std::move(version)); + version); // Append state property items. - for (const auto &state : states) { + for (auto &state : states) { if (state.isNull()) continue; appendChild<gen::xml::Property>(QByteArrayLiteral("state"), diff --git a/src/plugins/generator/iarew/iarewoptionpropertygroup.h b/src/plugins/generator/iarew/iarewoptionpropertygroup.h index d24fe3a9d..d80df2838 100644 --- a/src/plugins/generator/iarew/iarewoptionpropertygroup.h +++ b/src/plugins/generator/iarew/iarewoptionpropertygroup.h @@ -41,8 +41,7 @@ class IarewOptionPropertyGroup final : public gen::xml::PropertyGroup { public: - explicit IarewOptionPropertyGroup( - QByteArray name, const QVariantList &states, + explicit IarewOptionPropertyGroup(const QByteArray &name, QVariantList states, int version = -1); }; diff --git a/src/plugins/generator/iarew/iarewproject.cpp b/src/plugins/generator/iarew/iarewproject.cpp index 3e6a03ac2..f33ae4fcb 100644 --- a/src/plugins/generator/iarew/iarewproject.cpp +++ b/src/plugins/generator/iarew/iarewproject.cpp @@ -46,7 +46,7 @@ namespace qbs { IarewProject::IarewProject(const GeneratableProject &genProject, const GeneratableProductData &genProduct, - const IarewVersionInfo &versionInfo) + const gen::VersionInfo &versionInfo) { Q_ASSERT(genProject.projects.size() == genProject.commandLines.size()); Q_ASSERT(genProject.projects.size() == genProduct.data.size()); diff --git a/src/plugins/generator/iarew/iarewproject.h b/src/plugins/generator/iarew/iarewproject.h index 567a58c55..df260fcd8 100644 --- a/src/plugins/generator/iarew/iarewproject.h +++ b/src/plugins/generator/iarew/iarewproject.h @@ -39,14 +39,12 @@ namespace qbs { -class IarewVersionInfo; - class IarewProject final : public gen::xml::Project { public: explicit IarewProject(const GeneratableProject &genProject, const GeneratableProductData &genProduct, - const IarewVersionInfo &versionInfo); + const gen::VersionInfo &versionInfo); private: std::vector<std::unique_ptr<gen::xml::PropertyGroupFactory>> m_factories; }; diff --git a/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp b/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp index 3e7b6dae7..a07d59e0f 100644 --- a/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp +++ b/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp @@ -63,9 +63,10 @@ IarewSettingsPropertyGroup::IarewSettingsPropertyGroup() QByteArrayLiteral("debug"), QVariant{}); } -void IarewSettingsPropertyGroup::setName(QByteArray name) +void IarewSettingsPropertyGroup::setName(const QByteArray &name) { - m_nameProperty->setValue(std::move(name)); + // There is no way to move-construct a QVariant from T, thus name is shallow-copied + m_nameProperty->setValue(QVariant(name)); } QByteArray IarewSettingsPropertyGroup::name() const @@ -95,12 +96,11 @@ void IarewSettingsPropertyGroup::setDataDebugInfo(int debugInfo) } void IarewSettingsPropertyGroup::addOptionsGroup( - QByteArray name, - const QVariantList &states, + const QByteArray &name, + QVariantList states, int version) { - m_dataPropertyGroup->appendChild<IarewOptionPropertyGroup>( - std::move(name), states, std::move(version)); + m_dataPropertyGroup->appendChild<IarewOptionPropertyGroup>(name, std::move(states), version); } } // namespace qbs diff --git a/src/plugins/generator/iarew/iarewsettingspropertygroup.h b/src/plugins/generator/iarew/iarewsettingspropertygroup.h index 4dea76f1a..b1feebcc7 100644 --- a/src/plugins/generator/iarew/iarewsettingspropertygroup.h +++ b/src/plugins/generator/iarew/iarewsettingspropertygroup.h @@ -40,7 +40,7 @@ class IarewSettingsPropertyGroup : public gen::xml::PropertyGroup public: explicit IarewSettingsPropertyGroup(); - void setName(QByteArray name); + void setName(const QByteArray &name); QByteArray name() const; void setArchiveVersion(int archiveVersion); @@ -50,7 +50,7 @@ protected: void setDataVersion(int dataVersion); void setDataDebugInfo(int debugInfo); - void addOptionsGroup(QByteArray name, const QVariantList &states, + void addOptionsGroup(const QByteArray &name, QVariantList states, int version = -1); private: diff --git a/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h b/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h index 5f88cec27..6d0083573 100644 --- a/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h +++ b/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h @@ -36,7 +36,7 @@ namespace qbs { class ArtifactData; -class GeneratableProject; +struct GeneratableProject; class IarewSourceFilePropertyGroup final : public gen::xml::PropertyGroup diff --git a/src/plugins/generator/iarew/iarewversioninfo.cpp b/src/plugins/generator/iarew/iarewversioninfo.cpp deleted file mode 100644 index 41a788e98..000000000 --- a/src/plugins/generator/iarew/iarewversioninfo.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qbs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "iarewversioninfo.h" - -#include <QtCore/qdebug.h> - -namespace qbs { - -IarewVersionInfo::IarewVersionInfo( - const Version &version, - const std::set<gen::utils::Architecture> &archs) - : gen::VersionInfo(version, archs) -{ -} - -std::set<IarewVersionInfo> IarewVersionInfo::knownVersions() -{ - static const std::set<IarewVersionInfo> known = { - {Version(8), {gen::utils::Architecture::Arm}}, - {Version(7), {gen::utils::Architecture::Avr, - gen::utils::Architecture::Msp430}}, - {Version(10), {gen::utils::Architecture::Mcs51}}, - {Version(3), {gen::utils::Architecture::Stm8}}, - }; - return known; -} - -int IarewVersionInfo::marketingVersion() const -{ - const auto mv = gen::VersionInfo::marketingVersion(); - for (const IarewVersionInfo &known : knownVersions()) { - if (known.version().majorVersion() == mv) - return mv; - } - qWarning() << QStringLiteral("Unrecognized IAR EW version: ") - << version().toString(); - return 0; -} - -} // namespace qbs diff --git a/src/plugins/generator/iarew/iarewversioninfo.h b/src/plugins/generator/iarew/iarewversioninfo.h index 4fd1b1fbc..3dc459557 100644 --- a/src/plugins/generator/iarew/iarewversioninfo.h +++ b/src/plugins/generator/iarew/iarewversioninfo.h @@ -44,18 +44,17 @@ #include <generators/generatorversioninfo.h> namespace qbs { - -class IarewVersionInfo final : public gen::VersionInfo -{ -public: - IarewVersionInfo(const Version &version, - const std::set<gen::utils::Architecture> &archs); - - int marketingVersion() const final; - - static std::set<IarewVersionInfo> knownVersions(); +namespace IarewVersionInfo { + +constexpr gen::VersionInfo knownVersions[] = { + {Version(8), {gen::utils::Architecture::Arm}}, + {Version(7), {gen::utils::Architecture::Avr, + gen::utils::Architecture::Msp430}}, + {Version(10), {gen::utils::Architecture::Mcs51}}, + {Version(3), {gen::utils::Architecture::Stm8}}, }; +} // namespace IarewVersionInfo } // namespace qbs #endif // QBS_IAREWVERSIONINFO_H diff --git a/src/plugins/generator/keiluv/keiluv.pro b/src/plugins/generator/keiluv/keiluv.pro index 52d7c0ed4..052277ef8 100644 --- a/src/plugins/generator/keiluv/keiluv.pro +++ b/src/plugins/generator/keiluv/keiluv.pro @@ -28,7 +28,6 @@ SOURCES += \ $$PWD/keiluvproject.cpp \ $$PWD/keiluvprojectwriter.cpp \ $$PWD/keiluvutils.cpp \ - $$PWD/keiluvversioninfo.cpp \ $$PWD/keiluvworkspace.cpp \ $$PWD/keiluvworkspacewriter.cpp diff --git a/src/plugins/generator/keiluv/keiluv.qbs b/src/plugins/generator/keiluv/keiluv.qbs index 65bf6d65b..65f8fa029 100644 --- a/src/plugins/generator/keiluv/keiluv.qbs +++ b/src/plugins/generator/keiluv/keiluv.qbs @@ -21,7 +21,6 @@ QbsPlugin { "keiluvprojectwriter.h", "keiluvutils.cpp", "keiluvutils.h", - "keiluvversioninfo.cpp", "keiluvversioninfo.h", "keiluvworkspace.cpp", "keiluvworkspace.h", diff --git a/src/plugins/generator/keiluv/keiluvgenerator.cpp b/src/plugins/generator/keiluv/keiluvgenerator.cpp index e3c959e8d..f98f55abe 100644 --- a/src/plugins/generator/keiluv/keiluvgenerator.cpp +++ b/src/plugins/generator/keiluv/keiluvgenerator.cpp @@ -84,7 +84,7 @@ static void writeWorkspace(const std::shared_ptr<KeiluvWorkspace> &wokspace, QFileInfo(workspaceFilePath).fileName()); } -KeiluvGenerator::KeiluvGenerator(const KeiluvVersionInfo &versionInfo) +KeiluvGenerator::KeiluvGenerator(const gen::VersionInfo &versionInfo) : m_versionInfo(versionInfo) { } diff --git a/src/plugins/generator/keiluv/keiluvgenerator.h b/src/plugins/generator/keiluv/keiluvgenerator.h index 769519562..25b89b9c8 100644 --- a/src/plugins/generator/keiluv/keiluvgenerator.h +++ b/src/plugins/generator/keiluv/keiluvgenerator.h @@ -45,7 +45,7 @@ class KeiluvGenerator final : public ProjectGenerator, private IGeneratableProjectVisitor { public: - explicit KeiluvGenerator(const KeiluvVersionInfo &versionInfo); + explicit KeiluvGenerator(const gen::VersionInfo &versionInfo); QString generatorName() const final; void generate() final; @@ -60,7 +60,7 @@ private: const GeneratableProjectData &projectData, const GeneratableProductData &productData) final; - const KeiluvVersionInfo m_versionInfo; + const gen::VersionInfo m_versionInfo; std::shared_ptr<KeiluvWorkspace> m_workspace; QString m_workspaceFilePath; std::map<QString, std::shared_ptr<KeiluvProject>> m_projects; diff --git a/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp b/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp index 91b73ef71..abbccc3da 100644 --- a/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp +++ b/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp @@ -45,7 +45,7 @@ static void QbsKeiluvGeneratorPluginLoad() { - for (const auto &info : qbs::KeiluvVersionInfo::knownVersions()) { + for (const auto &info : qbs::KeiluvVersionInfo::knownVersions) { qbs::ProjectGeneratorManager::registerGenerator( std::make_shared<qbs::KeiluvGenerator>(info)); } diff --git a/src/plugins/generator/keiluv/keiluvproject.cpp b/src/plugins/generator/keiluv/keiluvproject.cpp index 476ce8e69..89db73b1f 100644 --- a/src/plugins/generator/keiluv/keiluvproject.cpp +++ b/src/plugins/generator/keiluv/keiluvproject.cpp @@ -40,7 +40,7 @@ namespace qbs { -static QString keilProjectSchema(const KeiluvVersionInfo &info) +static QString keilProjectSchema(const gen::VersionInfo &info) { const auto v = info.marketingVersion(); switch (v) { @@ -51,10 +51,9 @@ static QString keilProjectSchema(const KeiluvVersionInfo &info) } } -KeiluvProject::KeiluvProject( - const qbs::GeneratableProject &genProject, +KeiluvProject::KeiluvProject(const qbs::GeneratableProject &genProject, const qbs::GeneratableProductData &genProduct, - const KeiluvVersionInfo &versionInfo) + const gen::VersionInfo &versionInfo) { Q_ASSERT(genProject.projects.size() == genProject.commandLines.size()); Q_ASSERT(genProject.projects.size() == genProduct.data.size()); diff --git a/src/plugins/generator/keiluv/keiluvproject.h b/src/plugins/generator/keiluv/keiluvproject.h index 98b2815ed..da86f71fd 100644 --- a/src/plugins/generator/keiluv/keiluvproject.h +++ b/src/plugins/generator/keiluv/keiluvproject.h @@ -40,15 +40,13 @@ namespace qbs { -class KeiluvVersionInfo; - class KeiluvProject final : public gen::xml::Project { public: explicit KeiluvProject( const qbs::GeneratableProject &genProject, const qbs::GeneratableProductData &genProduct, - const KeiluvVersionInfo &versionInfo); + const gen::VersionInfo &versionInfo); private: std::vector<std::unique_ptr<gen::xml::PropertyGroupFactory>> m_factories; }; diff --git a/src/plugins/generator/keiluv/keiluvversioninfo.cpp b/src/plugins/generator/keiluv/keiluvversioninfo.cpp deleted file mode 100644 index 973d0a420..000000000 --- a/src/plugins/generator/keiluv/keiluvversioninfo.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qbs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "keiluvconstants.h" -#include "keiluvversioninfo.h" - -#include <QtCore/qdebug.h> - -namespace qbs { - -KeiluvVersionInfo::KeiluvVersionInfo( - const Version &version, - const std::set<gen::utils::Architecture> &archs) - : gen::VersionInfo(version, archs) -{ -} - -std::set<KeiluvVersionInfo> KeiluvVersionInfo::knownVersions() -{ - static const std::set<KeiluvVersionInfo> known = { - {Version(KeiluvConstants::v5::kUVisionVersion), - {gen::utils::Architecture::Mcs51, - gen::utils::Architecture::Arm}}, - }; - return known; -} - -int KeiluvVersionInfo::marketingVersion() const -{ - const auto mv = gen::VersionInfo::marketingVersion(); - for (const KeiluvVersionInfo &known : knownVersions()) { - if (known.version().majorVersion() == mv) - return mv; - } - qWarning() << QStringLiteral("Unrecognized KEIL UV version: ") - << version().toString(); - return 0; -} - -} // namespace qbs diff --git a/src/plugins/generator/keiluv/keiluvversioninfo.h b/src/plugins/generator/keiluv/keiluvversioninfo.h index a64513492..cc379c3d7 100644 --- a/src/plugins/generator/keiluv/keiluvversioninfo.h +++ b/src/plugins/generator/keiluv/keiluvversioninfo.h @@ -40,22 +40,21 @@ #ifndef QBS_KEILUVVERSIONINFO_H #define QBS_KEILUVVERSIONINFO_H +#include "keiluvconstants.h" + #include <generators/generatorutils.h> #include <generators/generatorversioninfo.h> namespace qbs { +namespace KeiluvVersionInfo { -class KeiluvVersionInfo final : public gen::VersionInfo -{ -public: - KeiluvVersionInfo(const Version &version, - const std::set<gen::utils::Architecture> &archs); - - int marketingVersion() const final; - - static std::set<KeiluvVersionInfo> knownVersions(); +constexpr gen::VersionInfo knownVersions[] = { + {Version(KeiluvConstants::v5::kUVisionVersion), + {gen::utils::Architecture::Mcs51, + gen::utils::Architecture::Arm}}, }; +} // namespace KeiluvVersionInfo } // namespace qbs #endif // QBS_KEILUVVERSIONINFO_H diff --git a/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp b/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp index 634bb2381..12fbe2da5 100644 --- a/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp +++ b/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp @@ -43,6 +43,8 @@ #include <QtCore/qxmlstream.h> +#include <memory> + namespace qbs { static const QString kMSBuildSchemaURI = @@ -87,7 +89,7 @@ MSBuildProjectWriter::MSBuildProjectWriter(std::ostream *device) : d(new MSBuildProjectWriterPrivate) { d->device = device; - d->writer.reset(new QXmlStreamWriter(&d->buffer)); + d->writer = std::make_unique<QXmlStreamWriter>(&d->buffer); d->writer->setAutoFormatting(true); } diff --git a/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp b/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp index e980249d6..625489ac6 100644 --- a/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp +++ b/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp @@ -64,9 +64,7 @@ VisualStudioSolutionWriter::VisualStudioSolutionWriter(std::ostream *device) d->device = device; } -VisualStudioSolutionWriter::~VisualStudioSolutionWriter() -{ -} +VisualStudioSolutionWriter::~VisualStudioSolutionWriter() = default; std::string VisualStudioSolutionWriter::projectBaseDirectory() const { diff --git a/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp index c51f0e517..81078ecb9 100644 --- a/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp +++ b/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp @@ -45,9 +45,7 @@ IMSBuildGroup::IMSBuildGroup(MSBuildProject *parent) { } -IMSBuildGroup::~IMSBuildGroup() -{ -} +IMSBuildGroup::~IMSBuildGroup() = default; QString IMSBuildGroup::condition() const { diff --git a/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp index 4c70405c2..f563f7b07 100644 --- a/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp +++ b/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp @@ -32,8 +32,6 @@ namespace qbs { -IMSBuildNode::~IMSBuildNode() -{ -} +IMSBuildNode::~IMSBuildNode() = default; } // namespace qbs diff --git a/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h b/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h index fe75c23f9..84239d648 100644 --- a/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h +++ b/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h @@ -46,7 +46,7 @@ class MSBuildPropertyGroup; class IMSBuildNodeVisitor { public: - virtual ~IMSBuildNodeVisitor() {} + virtual ~IMSBuildNodeVisitor() = default; virtual void visitStart(const MSBuildImport *import) = 0; virtual void visitEnd(const MSBuildImport *import) = 0; diff --git a/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp index 6e54f1e43..be18f1a5b 100644 --- a/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp +++ b/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp @@ -46,9 +46,7 @@ IMSBuildProperty::IMSBuildProperty(QObject *parent) { } -IMSBuildProperty::~IMSBuildProperty() -{ -} +IMSBuildProperty::~IMSBuildProperty() = default; QString IMSBuildProperty::condition() const { diff --git a/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp index 26c08cacb..4cbb01d04 100644 --- a/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp +++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp @@ -29,6 +29,8 @@ ****************************************************************************/ #include "msbuildfileitem.h" + +#include <memory> #include "../msbuilditemmetadata.h" namespace qbs { @@ -43,12 +45,10 @@ MSBuildFileItem::MSBuildFileItem(const QString &name, IMSBuildItemGroup *parent) : MSBuildItem(name, parent) , d(new MSBuildFileItemPrivate) { - d->filter.reset(new MSBuildItemMetadata(QStringLiteral("Filter"), QVariant())); + d->filter = std::make_unique<MSBuildItemMetadata>(QStringLiteral("Filter"), QVariant()); } -MSBuildFileItem::~MSBuildFileItem() -{ -} +MSBuildFileItem::~MSBuildFileItem() = default; QString MSBuildFileItem::filePath() const { diff --git a/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp index f7c506651..0b9c2c86a 100644 --- a/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp +++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp @@ -68,9 +68,7 @@ MSBuildFilter::MSBuildFilter(const QString &name, setExtensions(extensions); } -MSBuildFilter::~MSBuildFilter() -{ -} +MSBuildFilter::~MSBuildFilter() = default; QUuid MSBuildFilter::identifier() const { diff --git a/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp index a0c693aff..000af4496 100644 --- a/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp +++ b/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp @@ -55,9 +55,7 @@ MSBuildImport::MSBuildImport(MSBuildImportGroup *parent) { } -MSBuildImport::~MSBuildImport() -{ -} +MSBuildImport::~MSBuildImport() = default; QString MSBuildImport::project() const { diff --git a/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp index 73e1922db..d84d81783 100644 --- a/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp +++ b/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp @@ -47,9 +47,7 @@ MSBuildImportGroup::MSBuildImportGroup(MSBuildProject *parent) { } -MSBuildImportGroup::~MSBuildImportGroup() -{ -} +MSBuildImportGroup::~MSBuildImportGroup() = default; QString MSBuildImportGroup::label() const { diff --git a/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp index b11b62295..ed181a453 100644 --- a/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp +++ b/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp @@ -51,9 +51,7 @@ MSBuildItem::MSBuildItem(const QString &name, IMSBuildItemGroup *parent) setName(name); } -MSBuildItem::~MSBuildItem() -{ -} +MSBuildItem::~MSBuildItem() = default; QString MSBuildItem::name() const { diff --git a/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp index 5228e850e..1479577c5 100644 --- a/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp +++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp @@ -40,9 +40,7 @@ MSBuildItemDefinitionGroup::MSBuildItemDefinitionGroup(MSBuildProject *parent) { } -MSBuildItemDefinitionGroup::~MSBuildItemDefinitionGroup() -{ -} +MSBuildItemDefinitionGroup::~MSBuildItemDefinitionGroup() = default; void MSBuildItemDefinitionGroup::accept(IMSBuildNodeVisitor *visitor) const { diff --git a/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp index c4e80ecc7..48f919709 100644 --- a/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp +++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp @@ -49,9 +49,7 @@ MSBuildItemGroup::MSBuildItemGroup(MSBuildProject *parent) { } -MSBuildItemGroup::~MSBuildItemGroup() -{ -} +MSBuildItemGroup::~MSBuildItemGroup() = default; QString MSBuildItemGroup::label() const { diff --git a/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp index c872622b9..11b5b81ea 100644 --- a/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp +++ b/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp @@ -52,9 +52,7 @@ MSBuildProject::MSBuildProject(QObject *parent) { } -MSBuildProject::~MSBuildProject() -{ -} +MSBuildProject::~MSBuildProject() = default; QString MSBuildProject::defaultTargets() const { diff --git a/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp index 4f9c72939..5acb73dad 100644 --- a/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp +++ b/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp @@ -48,9 +48,7 @@ MSBuildPropertyGroup::MSBuildPropertyGroup(MSBuildProject *parent) { } -MSBuildPropertyGroup::~MSBuildPropertyGroup() -{ -} +MSBuildPropertyGroup::~MSBuildPropertyGroup() = default; QString MSBuildPropertyGroup::label() const { diff --git a/src/plugins/generator/visualstudio/msbuildtargetproject.cpp b/src/plugins/generator/visualstudio/msbuildtargetproject.cpp index 154f8dccc..bcd654061 100644 --- a/src/plugins/generator/visualstudio/msbuildtargetproject.cpp +++ b/src/plugins/generator/visualstudio/msbuildtargetproject.cpp @@ -83,9 +83,7 @@ MSBuildTargetProject::MSBuildTargetProject(const GeneratableProject &project, propertySheetsImportGroup(); } -MSBuildTargetProject::~MSBuildTargetProject() -{ -} +MSBuildTargetProject::~MSBuildTargetProject() = default; const Internal::VisualStudioVersionInfo &MSBuildTargetProject::versionInfo() const { diff --git a/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp b/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp index f3a6a0cbd..4623b5d4d 100644 --- a/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp +++ b/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp @@ -46,9 +46,7 @@ IVisualStudioSolutionProject::IVisualStudioSolutionProject(QObject *parent) { } -IVisualStudioSolutionProject::~IVisualStudioSolutionProject() -{ -} +IVisualStudioSolutionProject::~IVisualStudioSolutionProject() = default; QUuid IVisualStudioSolutionProject::guid() const { diff --git a/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp index c09ef1f4f..89b266647 100644 --- a/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp +++ b/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp @@ -57,9 +57,7 @@ VisualStudioSolution::VisualStudioSolution(const Internal::VisualStudioVersionIn { } -VisualStudioSolution::~VisualStudioSolution() -{ -} +VisualStudioSolution::~VisualStudioSolution() = default; Internal::VisualStudioVersionInfo VisualStudioSolution::versionInfo() const { diff --git a/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp index d66f47cf7..ab5db088d 100644 --- a/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp +++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp @@ -48,9 +48,7 @@ VisualStudioSolutionFileProject::VisualStudioSolutionFileProject(const QString & setFilePath(filePath); } -VisualStudioSolutionFileProject::~VisualStudioSolutionFileProject() -{ -} +VisualStudioSolutionFileProject::~VisualStudioSolutionFileProject() = default; QString VisualStudioSolutionFileProject::name() const { diff --git a/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp index 1e4f5fd01..5cbb0cd61 100644 --- a/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp +++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp @@ -51,9 +51,7 @@ VisualStudioSolutionGlobalSection::VisualStudioSolutionGlobalSection(const QStri setName(name); } -VisualStudioSolutionGlobalSection::~VisualStudioSolutionGlobalSection() -{ -} +VisualStudioSolutionGlobalSection::~VisualStudioSolutionGlobalSection() = default; QString VisualStudioSolutionGlobalSection::name() const { @@ -82,7 +80,7 @@ std::vector<std::pair<QString, QString> > VisualStudioSolutionGlobalSection::pro void VisualStudioSolutionGlobalSection::appendProperty(const QString &key, const QString &value) { - d->properties.push_back({ key, value }); + d->properties.emplace_back(key, value); } } // namespace qbs diff --git a/src/plugins/generator/visualstudio/visualstudiogenerator.cpp b/src/plugins/generator/visualstudio/visualstudiogenerator.cpp index ace55b6e6..2ce54e73e 100644 --- a/src/plugins/generator/visualstudio/visualstudiogenerator.cpp +++ b/src/plugins/generator/visualstudio/visualstudiogenerator.cpp @@ -158,9 +158,7 @@ VisualStudioGenerator::VisualStudioGenerator(const VisualStudioVersionInfo &vers Q_ASSERT(d->versionInfo.usesSolutions()); } -VisualStudioGenerator::~VisualStudioGenerator() -{ -} +VisualStudioGenerator::~VisualStudioGenerator() = default; QString VisualStudioGenerator::generatorName() const { diff --git a/src/plugins/plugins.pri b/src/plugins/plugins.pri index 43d7dcfac..b09619ca6 100644 --- a/src/plugins/plugins.pri +++ b/src/plugins/plugins.pri @@ -11,7 +11,7 @@ TEMPLATE = lib CONFIG += c++14 CONFIG(static, static|shared): CONFIG += create_prl -unix: CONFIG += plugin +CONFIG += plugin !isEmpty(QBS_PLUGINS_INSTALL_DIR): \ installPrefix = $${QBS_PLUGINS_INSTALL_DIR} diff --git a/src/plugins/scanner/cpp/Lexer.cpp b/src/plugins/scanner/cpp/Lexer.cpp index 4e06f93b4..5bf5b2367 100644 --- a/src/plugins/scanner/cpp/Lexer.cpp +++ b/src/plugins/scanner/cpp/Lexer.cpp @@ -70,8 +70,7 @@ Lexer::Lexer(const char *firstChar, const char *lastChar) setSource(firstChar, lastChar); } -Lexer::~Lexer() -{ } +Lexer::~Lexer() = default; void Lexer::setSource(const char *firstChar, const char *lastChar) { @@ -225,7 +224,7 @@ void Lexer::scan_helper(Token *tok) goto _Lagain; case '"': case '\'': { - const char quote = ch; + const unsigned char quote = ch; tok->f.kind = quote == '"' ? T_STRING_LITERAL @@ -403,7 +402,7 @@ void Lexer::scan_helper(Token *tok) bool doxy = false; if (_yychar == '*' || _yychar == '!') { - const char ch = _yychar; + const unsigned char ch = _yychar; yyinp(); @@ -609,7 +608,7 @@ void Lexer::scan_helper(Token *tok) ch = _yychar; yyinp(); - const char quote = ch; + const unsigned char quote = ch; tok->f.kind = quote == '"' ? T_WIDE_STRING_LITERAL @@ -668,4 +667,4 @@ void Lexer::scan_helper(Token *tok) } // switch } -} +} // namespace CPlusPlus diff --git a/src/plugins/scanner/cpp/Token.cpp b/src/plugins/scanner/cpp/Token.cpp index f8b017fdb..603918f63 100644 --- a/src/plugins/scanner/cpp/Token.cpp +++ b/src/plugins/scanner/cpp/Token.cpp @@ -118,9 +118,7 @@ Token::Token() : { } -Token::~Token() -{ -} +Token::~Token() = default; void Token::reset() { diff --git a/src/plugins/scanner/cpp/cppscanner.cpp b/src/plugins/scanner/cpp/cppscanner.cpp index 1cebc52eb..4b7f0eb03 100644 --- a/src/plugins/scanner/cpp/cppscanner.cpp +++ b/src/plugins/scanner/cpp/cppscanner.cpp @@ -66,7 +66,7 @@ using namespace CPlusPlus; struct ScanResult { char *fileName; - unsigned int size; + int size; int flags; }; @@ -163,7 +163,7 @@ static void scanCppFile(void *opaq, CPlusPlus::Lexer &yylex, bool scanForFileTag yylex.setScanAngleStringLiteralTokens(false); if (!tk.newline() && (tk.is(T_STRING_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))) { - scanResult.size = tk.length() - 2; + scanResult.size = int(tk.length() - 2); if (tk.is(T_STRING_LITERAL)) scanResult.flags = SC_LOCAL_INCLUDE_FLAG; else diff --git a/src/shared/json/json.cpp b/src/shared/json/json.cpp index 3a838a177..949e2745f 100644 --- a/src/shared/json/json.cpp +++ b/src/shared/json/json.cpp @@ -46,8 +46,8 @@ #include <utility> #include <vector> -#include <limits.h> -#include <string.h> +#include <climits> +#include <cstring> #include "json.h" @@ -4127,7 +4127,7 @@ bool Parser::parseObject() DEBUG << "numEntries" << parsedObject.offsets.size(); int table = objectOffset; // finalize the object - if (parsedObject.offsets.size()) { + if (!parsedObject.offsets.empty()) { int tableSize = static_cast<int>(parsedObject.offsets.size()) * sizeof(uint32_t); table = reserveSpace(tableSize); memcpy(data + table, &*parsedObject.offsets.begin(), tableSize); @@ -4218,7 +4218,7 @@ bool Parser::parseArray() DEBUG << "size =" << values.size(); int table = arrayOffset; // finalize the object - if (values.size()) { + if (!values.empty()) { int tableSize = static_cast<int>(values.size() * sizeof(Value)); table = reserveSpace(tableSize); memcpy(data + table, values.data(), tableSize); |