diff options
Diffstat (limited to 'src/lib/corelib/tools')
42 files changed, 1561 insertions, 320 deletions
diff --git a/src/lib/corelib/tools/applecodesignutils.cpp b/src/lib/corelib/tools/applecodesignutils.cpp index feae266bf..de74e9206 100644 --- a/src/lib/corelib/tools/applecodesignutils.cpp +++ b/src/lib/corelib/tools/applecodesignutils.cpp @@ -95,12 +95,12 @@ QVariantMap certificateInfo(const QByteArray &data) map.insert(QString::fromUtf8(attr), cert.subjectInfo(attr).front()); return map; }; - + const auto sha1 = QString::fromLatin1(cert.digest(QCryptographicHash::Sha1).toHex().toUpper()); return { - {QStringLiteral("SHA1"), cert.digest(QCryptographicHash::Sha1).toHex().toUpper()}, + {QStringLiteral("SHA1"), sha1}, {QStringLiteral("subjectInfo"), subjectInfo(cert)}, - {QStringLiteral("validBefore"), cert.effectiveDate()}, - {QStringLiteral("validAfter"), cert.expiryDate()} + {QStringLiteral("validAfter"), cert.effectiveDate()}, + {QStringLiteral("validBefore"), cert.expiryDate()} }; } diff --git a/src/lib/corelib/tools/architectures.cpp b/src/lib/corelib/tools/architectures.cpp index cf9fec27b..f139509e4 100644 --- a/src/lib/corelib/tools/architectures.cpp +++ b/src/lib/corelib/tools/architectures.cpp @@ -55,7 +55,7 @@ QString canonicalTargetArchitecture(const QString &architecture, const QString &system, const QString &abi) { - const QString arch = canonicalArchitecture(architecture); + QString arch = canonicalArchitecture(architecture); const bool isApple = (vendor == QStringLiteral("apple") || system == QStringLiteral("darwin") || system == QStringLiteral("macosx") diff --git a/src/lib/corelib/tools/buildoptions.cpp b/src/lib/corelib/tools/buildoptions.cpp index e4e9ba17f..cc3ef7557 100644 --- a/src/lib/corelib/tools/buildoptions.cpp +++ b/src/lib/corelib/tools/buildoptions.cpp @@ -413,8 +413,8 @@ template<> JobLimits fromJson(const QJsonValue &limitsData) { JobLimits limits; const QJsonArray &limitsArray = limitsData.toArray(); - for (const QJsonValue &v : limitsArray) { - const QJsonObject limitData = v.toObject(); + for (const auto &value : limitsArray) { + const QJsonObject limitData = value.toObject(); QString pool; int limit = 0; setValueFromJson(pool, limitData, "pool"); diff --git a/src/lib/corelib/tools/clangclinfo.cpp b/src/lib/corelib/tools/clangclinfo.cpp index a9a1cb449..fd907ebf1 100644 --- a/src/lib/corelib/tools/clangclinfo.cpp +++ b/src/lib/corelib/tools/clangclinfo.cpp @@ -47,7 +47,7 @@ static std::vector<MSVCInstallInfo> compatibleMsvcs(Logger &logger) return true; bool ok = false; const int major = versions.at(0).toInt(&ok); - return !(ok && major >= 15); // support MSVC2017 and above + return !ok || major < 15; // support MSVC2017 and above }; Internal::removeIf(msvcs, filter); for (const auto &msvc: msvcs) { @@ -61,7 +61,7 @@ static std::vector<MSVCInstallInfo> compatibleMsvcs(Logger &logger) static QString findCompatibleVcsarsallBat(const std::vector<MSVCInstallInfo> &msvcs) { for (const auto &msvc: msvcs) { - const auto vcvarsallPath = msvc.findVcvarsallBat(); + auto vcvarsallPath = msvc.findVcvarsallBat(); if (!vcvarsallPath.isEmpty()) return vcvarsallPath; } @@ -121,7 +121,7 @@ std::vector<ClangClInfo> ClangClInfo::installedCompilers( if (registry.contains(key)) { const auto compilerPath = QDir::fromNativeSeparators(registry.value(key).toString()) + QStringLiteral("/bin/") + compilerName; - if (QFileInfo::exists(compilerPath)) + if (QFileInfo::exists(compilerPath) && !contains(compilerPaths, compilerPath)) compilerPaths.push_back(compilerPath); } diff --git a/src/lib/corelib/tools/codelocation.cpp b/src/lib/corelib/tools/codelocation.cpp index ebfd5edc6..f04041e14 100644 --- a/src/lib/corelib/tools/codelocation.cpp +++ b/src/lib/corelib/tools/codelocation.cpp @@ -87,8 +87,9 @@ CodeLocation::CodeLocation(const QString &aFilePath, int aLine, int aColumn, boo } CodeLocation::CodeLocation(const CodeLocation &other) = default; - +CodeLocation::CodeLocation(CodeLocation &&other) noexcept = default; CodeLocation &CodeLocation::operator=(const CodeLocation &other) = default; +CodeLocation &CodeLocation::operator=(CodeLocation &&other) noexcept = default; CodeLocation::~CodeLocation() = default; @@ -181,4 +182,44 @@ bool operator<(const CodeLocation &cl1, const CodeLocation &cl2) return cl1.toString() < cl2.toString(); } +void CodePosition::load(Internal::PersistentPool &pool) { pool.load(m_line, m_column); } +void CodePosition::store(Internal::PersistentPool &pool) const { pool.store(m_line, m_column); } + +bool operator==(const CodePosition &pos1, const CodePosition &pos2) +{ + return pos1.line() == pos2.line() && pos1.column() == pos2.column(); +} +bool operator!=(const CodePosition &pos1, const CodePosition &pos2) { return !(pos1 == pos2); } + +bool operator<(const CodePosition &pos1, const CodePosition &pos2) +{ + const int lineDiff = pos1.line() - pos2.line(); + if (lineDiff < 0) + return true; + if (lineDiff > 0) + return false; + return pos1.column() < pos2.column(); +} +bool operator>(const CodePosition &pos1, const CodePosition &pos2) { return pos2 < pos1; } +bool operator<=(const CodePosition &pos1, const CodePosition &pos2) { return !(pos1 > pos2); } +bool operator>=(const CodePosition &pos1, const CodePosition &pos2) { return !(pos1 < pos2); } + +CodeRange::CodeRange(const CodePosition &start, const CodePosition &end) + : m_start(start), m_end(end) {} + +void CodeRange::load(Internal::PersistentPool &pool) { pool.load(m_start, m_end); } +void CodeRange::store(Internal::PersistentPool &pool) const { pool.store(m_start, m_end); } + +bool CodeRange::contains(const CodePosition &pos) const +{ + return start() <= pos && end() > pos; +} + +bool operator==(const CodeRange &r1, const CodeRange &r2) +{ + return r1.start() == r2.start() && r1.end() == r2.end(); +} +bool operator!=(const CodeRange &r1, const CodeRange &r2) { return !(r1 == r2); } +bool operator<(const CodeRange &r1, const CodeRange &r2) { return r1.start() < r2.start(); } + } // namespace qbs diff --git a/src/lib/corelib/tools/codelocation.h b/src/lib/corelib/tools/codelocation.h index 158b90766..afcd2e075 100644 --- a/src/lib/corelib/tools/codelocation.h +++ b/src/lib/corelib/tools/codelocation.h @@ -62,7 +62,9 @@ public: explicit CodeLocation(const QString &aFilePath, int aLine = -1, int aColumn = -1, bool checkPath = true); CodeLocation(const CodeLocation &other); + CodeLocation(CodeLocation &&other) noexcept; CodeLocation &operator=(const CodeLocation &other); + CodeLocation &operator=(CodeLocation &&other) noexcept; ~CodeLocation(); QString filePath() const; @@ -84,11 +86,79 @@ private: QBS_EXPORT bool operator==(const CodeLocation &cl1, const CodeLocation &cl2); QBS_EXPORT bool operator!=(const CodeLocation &cl1, const CodeLocation &cl2); QBS_EXPORT bool operator<(const CodeLocation &cl1, const CodeLocation &cl2); - inline auto qHash(const CodeLocation &cl) { return qHash(cl.toString()); } - QDebug operator<<(QDebug debug, const CodeLocation &location); +class QBS_EXPORT CodePosition +{ +public: + CodePosition(int line, int column) : m_line(line), m_column(column) {} + + CodePosition() = default; + CodePosition(const CodePosition &other) = default; + CodePosition(CodePosition &&other) = default; + CodePosition &operator=(const CodePosition &other) = default; + CodePosition &operator=(CodePosition &&other) = default; + + int line() const { return m_line; } + void setLine(int newLine) { m_line = newLine; } + + int column() const { return m_column; } + void setColumn(int newColumn) { m_column = newColumn; } + + void load(Internal::PersistentPool &pool); + void store(Internal::PersistentPool &pool) const; + +private: + int m_line = 0; + int m_column = 0; +}; + +QBS_EXPORT bool operator==(const CodePosition &pos1, const CodePosition &pos2); +QBS_EXPORT bool operator!=(const CodePosition &pos1, const CodePosition &pos2); +QBS_EXPORT bool operator<(const CodePosition &pos1, const CodePosition &pos2); +QBS_EXPORT bool operator>(const CodePosition &pos1, const CodePosition &pos2); +QBS_EXPORT bool operator<=(const CodePosition &pos1, const CodePosition &pos2); +QBS_EXPORT bool operator>=(const CodePosition &pos1, const CodePosition &pos2); +inline auto qHash(const CodePosition &pos) +{ + return QT_PREPEND_NAMESPACE(qHash)(pos.line()) ^ QT_PREPEND_NAMESPACE(qHash)(pos.column()); +} + +class QBS_EXPORT CodeRange +{ +public: + CodeRange(const CodePosition &start, const CodePosition &end); + + CodeRange() = default; + CodeRange(const CodeRange &other) = default; + CodeRange(CodeRange &&other) = default; + CodeRange &operator=(const CodeRange &other) = default; + CodeRange &operator=(CodeRange &&other) = default; + + const CodePosition &start() const & { return m_start; } + const CodePosition &end() const & { return m_end; } + CodePosition start() && { return std::move(m_start); } + CodePosition end() && { return std::move(m_end); } + + bool contains(const CodePosition &pos) const; + + void load(Internal::PersistentPool &pool); + void store(Internal::PersistentPool &pool) const; + +private: + CodePosition m_start; + CodePosition m_end; +}; + +QBS_EXPORT bool operator==(const CodeRange &r1, const CodeRange &r2); +QBS_EXPORT bool operator!=(const CodeRange &r1, const CodeRange &r2); +QBS_EXPORT bool operator<(const CodeRange &r1, const CodeRange &r2); +inline auto qHash(const CodeRange &range) { return qHash(range.start()) ^ qHash(range.end()); } + +using CodeLinksInFile = QHash<CodeRange, QList<CodeLocation>>; +using CodeLinks = QHash<QString, CodeLinksInFile>; + } // namespace qbs #endif // QBS_SOURCELOCATION_H diff --git a/src/lib/corelib/tools/deprecationwarningmode.cpp b/src/lib/corelib/tools/deprecationwarningmode.cpp new file mode 100644 index 000000000..e140e3e49 --- /dev/null +++ b/src/lib/corelib/tools/deprecationwarningmode.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** 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 "deprecationwarningmode.h" + +/*! + * \enum DeprecationWarningMode + * This enum type specifies how \QBS should behave on encountering deprecated items or properties. + * \value DeprecationWarningMode::Error Project resolving will stop with an error message. + * \value DeprecationWarningMode::On A warning will be printed. + * \value DeprecationWarningMode::BeforeRemoval A warning will be printed if and only if this is + * the last \QBS version before the removal version. This is the default behavior. + * \note If the removal version's minor version number is zero, the behavior is + * the same as for ErrorHandlingMode::On. + * \value DeprecationWarningMode::Off No warnings will be emitted for deprecated constructs. + */ + +namespace qbs { + +DeprecationWarningMode defaultDeprecationWarningMode() +{ + return DeprecationWarningMode::BeforeRemoval; +} + +QString deprecationWarningModeName(DeprecationWarningMode mode) +{ + switch (mode) { + case DeprecationWarningMode::Error: + return QStringLiteral("error"); + case DeprecationWarningMode::On: + return QStringLiteral("on"); + case DeprecationWarningMode::BeforeRemoval: + return QStringLiteral("before-removal"); + case DeprecationWarningMode::Off: + return QStringLiteral("off"); + default: + break; + } + return {}; +} + +DeprecationWarningMode deprecationWarningModeFromName(const QString &name) +{ + DeprecationWarningMode mode = defaultDeprecationWarningMode(); + for (int i = 0; i <= int(DeprecationWarningMode::Sentinel); ++i) { + if (deprecationWarningModeName(static_cast<DeprecationWarningMode>(i)) == name) { + mode = static_cast<DeprecationWarningMode>(i); + break; + } + } + return mode; +} + +QStringList allDeprecationWarningModeStrings() +{ + QStringList result; + for (int i = 0; i <= int(DeprecationWarningMode::Sentinel); ++i) + result << deprecationWarningModeName(static_cast<DeprecationWarningMode>(i)); + return result; +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/deprecationwarningmode.h b/src/lib/corelib/tools/deprecationwarningmode.h new file mode 100644 index 000000000..bb2a14155 --- /dev/null +++ b/src/lib/corelib/tools/deprecationwarningmode.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** 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$ +** +****************************************************************************/ + +#ifndef QBS_DEPRECATIONWARNINGMODE_H +#define QBS_DEPRECATIONWARNINGMODE_H + +#include "qbs_export.h" + +#include <QtCore/qstringlist.h> + +namespace qbs { + +enum class DeprecationWarningMode { Error, On, BeforeRemoval, Off, Sentinel = Off }; + +QBS_EXPORT DeprecationWarningMode defaultDeprecationWarningMode(); +QBS_EXPORT QString deprecationWarningModeName(DeprecationWarningMode mode); +QBS_EXPORT DeprecationWarningMode deprecationWarningModeFromName(const QString &name); +QBS_EXPORT QStringList allDeprecationWarningModeStrings(); + +} // namespace qbs + +#endif // QBS_DEPRECATIONWARNINGMODE_H + diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp index 2ff36d1d1..f1b90b71e 100644 --- a/src/lib/corelib/tools/error.cpp +++ b/src/lib/corelib/tools/error.cpp @@ -40,7 +40,6 @@ #include "error.h" #include "persistence.h" -#include "qttools.h" #include "stringconstants.h" #include "setupprojectparameters.h" #include "logging/logger.h" @@ -209,15 +208,21 @@ ErrorInfo::ErrorInfo(const QString &description, const QStringList &backtrace) { append(description); for (const QString &traceLine : backtrace) { - static const std::regex regexp("^(.+) at (.+):(\\-?[0-9]+)$"); + if (traceLine.contains(QStringLiteral("<eval>"))) + continue; + static const std::regex regexpWithFunc("^(.+) at [^(]*\\((.+):(\\-?[0-9]+)\\)$"); + static const std::regex regexpWithoutFunc("^(.+) at (.+):(\\-?[0-9]+)$"); std::smatch match; const std::string tl = traceLine.toStdString(); - if (std::regex_match(tl, match, regexp)) { - const QString message = QString::fromStdString(match[1]), - file = QString::fromStdString(match[2]), - line = QString::fromStdString(match[3]); + bool hasMatch = std::regex_match(tl, match, regexpWithFunc); + if (!hasMatch) + hasMatch = std::regex_match(tl, match, regexpWithoutFunc); + if (hasMatch) { + const QString message = QString::fromStdString(match[1]).trimmed(); + const QString file = QString::fromStdString(match[2]); + const QString line = QString::fromStdString(match[3]); const CodeLocation location(file, line.toInt()); - appendBacktrace(message, location); + appendBacktrace(message, CodeLocation(file, line.toInt())); } } } @@ -271,7 +276,7 @@ void ErrorInfo::clear() QString ErrorInfo::toString() const { QStringList lines; - for (const ErrorItem &e : qAsConst(d->items)) { + for (const ErrorItem &e : std::as_const(d->items)) { if (e.isBacktraceItem()) { QString line; if (!e.description().isEmpty()) @@ -312,6 +317,13 @@ bool ErrorInfo::hasLocation() const return ei.codeLocation().isValid(); }); } +bool ErrorInfo::isCancelException() const +{ + return Internal::any_of(d->items, [](const ErrorItem &ei) { + return ei.description() == QLatin1String("interrupted"); + }); +} + void ErrorInfo::load(Internal::PersistentPool &pool) { pool.load(*d); diff --git a/src/lib/corelib/tools/error.h b/src/lib/corelib/tools/error.h index 4c6370b1e..ba600a558 100644 --- a/src/lib/corelib/tools/error.h +++ b/src/lib/corelib/tools/error.h @@ -113,6 +113,7 @@ public: QJsonObject toJson() const; bool isInternalError() const; bool hasLocation() const; + bool isCancelException() const; void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool) const; diff --git a/src/lib/corelib/tools/executablefinder.cpp b/src/lib/corelib/tools/executablefinder.cpp index 5bf531551..b5d9c0151 100644 --- a/src/lib/corelib/tools/executablefinder.cpp +++ b/src/lib/corelib/tools/executablefinder.cpp @@ -99,7 +99,7 @@ QString ExecutableFinder::findBySuffix(const QString &filePath) const bool ExecutableFinder::candidateCheck(const QString &directory, const QString &program, QString &fullProgramPath) const { - for (const QString &suffix : qAsConst(m_executableSuffixes)) { + for (const QString &suffix : std::as_const(m_executableSuffixes)) { QString candidate = directory + program + suffix; qCDebug(lcExec) << "candidate:" << candidate; QFileInfo fi(candidate); @@ -120,10 +120,10 @@ QString ExecutableFinder::findInPath(const QString &filePath, const QString &wor fullProgramPath = filePath; qCDebug(lcExec) << "looking for executable in PATH" << fullProgramPath; QStringList pathEnv = m_environment.value(StringConstants::pathEnvVar()) - .split(HostOsInfo::pathListSeparator(), QBS_SKIP_EMPTY_PARTS); + .split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); if (HostOsInfo::isWindowsHost()) pathEnv.prepend(StringConstants::dot()); - for (QString directory : qAsConst(pathEnv)) { + for (QString directory : std::as_const(pathEnv)) { if (directory == StringConstants::dot()) directory = workingDirPath; if (!directory.isEmpty()) { diff --git a/src/lib/corelib/tools/fileinfo.h b/src/lib/corelib/tools/fileinfo.h index f0a09a16b..3ad585f74 100644 --- a/src/lib/corelib/tools/fileinfo.h +++ b/src/lib/corelib/tools/fileinfo.h @@ -99,10 +99,10 @@ private: bool removeFileRecursion(const QFileInfo &f, QString *errorMessage); -// FIXME: Used by tests. -bool QBS_EXPORT removeDirectoryWithContents(const QString &path, QString *errorMessage); -bool QBS_EXPORT copyFileRecursion(const QString &sourcePath, const QString &targetPath, - bool preserveSymLinks, bool copyDirectoryContents, QString *errorMessage); +bool QBS_AUTOTEST_EXPORT removeDirectoryWithContents(const QString &path, QString *errorMessage); +bool QBS_AUTOTEST_EXPORT copyFileRecursion( + const QString &sourcePath, const QString &targetPath, bool preserveSymLinks, + bool copyDirectoryContents, QString *errorMessage); } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/tools/installoptions.cpp b/src/lib/corelib/tools/installoptions.cpp index 5e112e6de..563f04a7b 100644 --- a/src/lib/corelib/tools/installoptions.cpp +++ b/src/lib/corelib/tools/installoptions.cpp @@ -68,7 +68,7 @@ public: QString effectiveInstallRoot(const InstallOptions &options, const TopLevelProject *project) { - const QString installRoot = options.installRoot(); + QString installRoot = options.installRoot(); if (!installRoot.isEmpty()) return installRoot; diff --git a/src/lib/corelib/tools/launchersocket.cpp b/src/lib/corelib/tools/launchersocket.cpp index 1489af1e9..7d4788ee3 100644 --- a/src/lib/corelib/tools/launchersocket.cpp +++ b/src/lib/corelib/tools/launchersocket.cpp @@ -82,12 +82,7 @@ void LauncherSocket::setSocket(QLocalSocket *socket) QBS_ASSERT(!m_socket, return); m_socket.store(socket); m_packetParser.setDevice(m_socket); - connect(m_socket, -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error), -#else - &QLocalSocket::errorOccurred, -#endif + connect(m_socket, &QLocalSocket::errorOccurred, this, &LauncherSocket::handleSocketError); connect(m_socket, &QLocalSocket::readyRead, this, &LauncherSocket::handleSocketDataAvailable); @@ -144,7 +139,7 @@ void LauncherSocket::handleRequests() const auto socket = m_socket.load(); QBS_ASSERT(socket, return); std::lock_guard<std::mutex> locker(m_requestsMutex); - for (const QByteArray &request : qAsConst(m_requests)) + for (const QByteArray &request : std::as_const(m_requests)) socket->write(request); m_requests.clear(); } diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp index 418a76ba1..77b83023a 100644 --- a/src/lib/corelib/tools/msvcinfo.cpp +++ b/src/lib/corelib/tools/msvcinfo.cpp @@ -176,6 +176,7 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath, << qEnvironmentVariable("COMSPEC") << QStringLiteral("/c") << languageSwitch + << QStringLiteral("/Zs") << QStringLiteral("NUL"), compilerEnv, true, commands)).split(QLatin1Char('\n')); @@ -309,7 +310,7 @@ 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 + QString cmd = value + QStringLiteral("/Microsoft Visual Studio/Installer/vswhere.exe"); if (QFileInfo(cmd).exists()) return cmd; @@ -356,8 +357,8 @@ static std::vector<MSVCInstallInfo> retrieveInstancesFromVSWhere( return result; } const auto jsonArray = jsonOutput.array(); - for (const QJsonValue &v : jsonArray) { - const QJsonObject o = v.toObject(); + for (const auto &value : jsonArray) { + const QJsonObject o = value.toObject(); MSVCInstallInfo info; info.version = o.value(QStringLiteral("installationVersion")).toString(); if (productType == ProductType::BuildTools) { @@ -509,7 +510,7 @@ void MSVC::init() QString MSVC::architectureFromClPath(const QString &clPath) { const auto parentDir = QFileInfo(clPath).absolutePath(); - const auto parentDirName = QFileInfo(parentDir).fileName().toLower(); + auto parentDirName = QFileInfo(parentDir).fileName().toLower(); // can be the case when cl.exe is present within the Windows SDK installation... but can it? if (parentDirName == QLatin1String("bin")) return QStringLiteral("x86"); @@ -722,7 +723,7 @@ QString MSVCInstallInfo::findVcvarsallBat() const std::vector<MSVCInstallInfo> MSVCInstallInfo::installedMSVCs(Logger &logger) { - const auto installInfos = installedMSVCsFromVsWhere(logger); + auto installInfos = installedMSVCsFromVsWhere(logger); if (installInfos.empty()) return installedMSVCsFromRegistry(); return installInfos; diff --git a/src/lib/corelib/tools/mutexdata.h b/src/lib/corelib/tools/mutexdata.h new file mode 100644 index 000000000..160f6dd26 --- /dev/null +++ b/src/lib/corelib/tools/mutexdata.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2023 Ivan Komissarov (abbapoh@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$ +** +****************************************************************************/ + +#pragma once + +#include <shared_mutex> + +namespace qbs { +namespace Internal { + +// adapted version of https://github.com/dragazo/rustex/blob/master/rustex.h + +// a data with a mutually exclusive access +template<typename DataType, typename MutexType = std::shared_mutex> +class MutexData +{ +public: + template<typename T, template<typename> typename LockType> + class ReferenceGuard + { + friend class MutexData; + template<typename U> + ReferenceGuard(U &&data) noexcept + : m_ptr(std::addressof(data.m_data)) + , m_lock(data.m_mutex) + {} + public: + ReferenceGuard(const ReferenceGuard &) = delete; + ReferenceGuard(ReferenceGuard &&) = default; + ReferenceGuard &operator=(const ReferenceGuard &) = delete; + ReferenceGuard &operator=(ReferenceGuard &&) = default; + + T &get() const noexcept { return *m_ptr; } + T &data() const noexcept { return *m_ptr; } + operator T &() const noexcept { return *m_ptr; } + + private: + T *m_ptr; + LockType<MutexType> m_lock; + }; + + using UniqueMutableGuard = ReferenceGuard<DataType, std::unique_lock>; + using UniqueConstGuard = ReferenceGuard<const DataType, std::unique_lock>; + using SharedGuard = ReferenceGuard<const DataType, std::shared_lock>; + + template< + typename ...Args, + std::enable_if_t<std::is_constructible_v<DataType, Args...>, int> = 0 + > + explicit MutexData(Args &&...args) : m_data(std::forward<Args>(args)...) {} + + [[nodiscard]] UniqueMutableGuard lock() noexcept { return UniqueMutableGuard{*this}; } + [[nodiscard]] UniqueConstGuard lock() const noexcept { return UniqueConstGuard{*this}; } + + template< + typename U = MutexType, + std::enable_if_t<std::is_same_v<U, std::shared_mutex>, int> = 0 + > + [[nodiscard]] SharedGuard lock_shared() const noexcept + { return SharedGuard{*this}; } + +private: + DataType m_data; + mutable MutexType m_mutex; +}; + +} // namespace qbs +} // namespace Internal diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp index 95211e894..0e545377a 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-130"; +static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-133"; NoBuildGraphError::NoBuildGraphError(const QString &filePath) : ErrorInfo(Tr::tr("Build graph not found for configuration '%1'. Expected location was '%2'.") @@ -140,6 +140,11 @@ void PersistentPool::finalizeWriteStream() void PersistentPool::storeVariant(const QVariant &variant) { + if (variant.isNull()) { + m_stream << quint32(QMetaType::User); + m_stream << variant; + return; + } const auto type = static_cast<quint32>(variant.userType()); m_stream << type; switch (type) { @@ -231,8 +236,5 @@ void PersistentPool::doStoreValue(const QProcessEnvironment &env) store(env.value(key)); } -const PersistentPool::PersistentObjectId PersistentPool::ValueNotFoundId; -const PersistentPool::PersistentObjectId PersistentPool::EmptyValueId; - } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/tools/persistence.h b/src/lib/corelib/tools/persistence.h index b7aa543a4..86365c993 100644 --- a/src/lib/corelib/tools/persistence.h +++ b/src/lib/corelib/tools/persistence.h @@ -145,8 +145,9 @@ private: template<typename T> QHash<T, PersistentObjectId> &idMap(); template<typename T> PersistentObjectId &lastStoredId(); - static const PersistentObjectId ValueNotFoundId = -1; - static const PersistentObjectId EmptyValueId = -2; + static const inline PersistentObjectId ValueNotFoundId = -1; + static const inline PersistentObjectId EmptyValueId = -2; + static const inline PersistentObjectId NullValueId = -3; std::unique_ptr<QIODevice> m_file; QDataStream m_stream; @@ -271,8 +272,13 @@ template<typename T> inline T PersistentPool::idLoadValue() { int id; m_stream >> id; - if (id == EmptyValueId) + if (id == NullValueId) return T(); + if (id == EmptyValueId) { + if constexpr (std::is_same_v<T, QString>) + return QString(0, QChar()); + return T(); + } QBS_CHECK(id >= 0); if (id >= static_cast<int>(idStorage<T>().size())) { T value; @@ -287,6 +293,12 @@ template<typename T> inline T PersistentPool::idLoadValue() template<typename T> void PersistentPool::idStoreValue(const T &value) { + if constexpr (std::is_same_v<T, QString>) { + if (value.isNull()) { + m_stream << NullValueId; + return; + } + } if (value.isEmpty()) { m_stream << EmptyValueId; return; diff --git a/src/lib/corelib/tools/pimpl.h b/src/lib/corelib/tools/pimpl.h new file mode 100644 index 000000000..ab672aabe --- /dev/null +++ b/src/lib/corelib/tools/pimpl.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2023 Ivan Komissarov (abbapoh@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$ +** +****************************************************************************/ + +#ifndef PIMPL_H +#define PIMPL_H + +#include <tools/propagate_const.h> +#include <memory> + +namespace qbs { +namespace Internal { + +template<typename T> +using Pimpl = KDToolBox::propagate_const<std::unique_ptr<T>>; + +template<typename T, typename... Args> +Pimpl<T> makePimpl(Args&&... args) +{ + return Pimpl<T>(std::make_unique<T>(std::forward<Args>(args)...)); +} + +} // namespace Internal +} // namespace qbs + +#endif // PIMPL_H diff --git a/src/lib/corelib/tools/profile.cpp b/src/lib/corelib/tools/profile.cpp index 2eac25091..0fe0ba19d 100644 --- a/src/lib/corelib/tools/profile.cpp +++ b/src/lib/corelib/tools/profile.cpp @@ -213,7 +213,7 @@ QVariant Profile::possiblyInheritedValue(const QString &key, const QVariant &def QStringList profileChain) const { extendAndCheckProfileChain(profileChain); - const QVariant v = localValue(key); + QVariant v = localValue(key); if (v.isValid()) return v; const QString baseProfileName = baseProfile(); diff --git a/src/lib/corelib/tools/profiling.cpp b/src/lib/corelib/tools/profiling.cpp index db64a73c6..b93d3fa17 100644 --- a/src/lib/corelib/tools/profiling.cpp +++ b/src/lib/corelib/tools/profiling.cpp @@ -72,7 +72,7 @@ void TimedActivityLogger::finishActivity() { if (!d) return; - const QString timeString = elapsedTimeString(d->timer.elapsed()); + const QString timeString = elapsedTimeString(d->timer.nsecsElapsed()); d->logger.qbsLog(LoggerInfo, true) << Tr::tr("Activity '%2' took %3.").arg(d->activity, timeString); d.reset(); @@ -98,13 +98,13 @@ void AccumulatingTimer::stop() { if (!m_timer.isValid()) return; - *m_elapsedTime += m_timer.elapsed(); + *m_elapsedTime += m_timer.nsecsElapsed(); m_timer.invalidate(); } -QString elapsedTimeString(qint64 elapsedTimeInMs) +QString elapsedTimeString(qint64 elapsedTimeInNs) { - qint64 ms = elapsedTimeInMs; + qint64 ms = elapsedTimeInNs / (1000ll * 1000ll); qint64 s = ms/1000; ms -= s*1000; qint64 m = s/60; diff --git a/src/lib/corelib/tools/profiling.h b/src/lib/corelib/tools/profiling.h index c6fc9ede7..3220c2a82 100644 --- a/src/lib/corelib/tools/profiling.h +++ b/src/lib/corelib/tools/profiling.h @@ -52,7 +52,7 @@ namespace qbs { namespace Internal { class Logger; -QString elapsedTimeString(qint64 elapsedTimeInMs); +QString elapsedTimeString(qint64 elapsedTimeInNs); class TimedActivityLogger { diff --git a/src/lib/corelib/tools/progressobserver.h b/src/lib/corelib/tools/progressobserver.h index fc49d9eed..73a61de37 100644 --- a/src/lib/corelib/tools/progressobserver.h +++ b/src/lib/corelib/tools/progressobserver.h @@ -41,12 +41,15 @@ #include <QtCore/qglobal.h> +#include <vector> + QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { namespace Internal { +class ScriptEngine; class ProgressObserver { @@ -64,6 +67,14 @@ public: // Call this to ensure that the progress bar always goes to 100%. void setFinished(); + + void addScriptEngine(ScriptEngine *engine) { m_scriptEngines.push_back(engine); } + +protected: + const std::vector<ScriptEngine *> &scriptEngines() const { return m_scriptEngines; } + +private: + std::vector<ScriptEngine *> m_scriptEngines; }; } // namespace Internal diff --git a/src/lib/corelib/tools/propagate_const.h b/src/lib/corelib/tools/propagate_const.h new file mode 100644 index 000000000..65e35fc8c --- /dev/null +++ b/src/lib/corelib/tools/propagate_const.h @@ -0,0 +1,418 @@ +/**************************************************************************** +** MIT License +** +** Copyright (C) 2022-2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Author: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +** +** This file is part of KDToolBox (https://github.com/KDAB/KDToolBox). +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, ** and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice (including the next paragraph) +** shall be included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF ** CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +****************************************************************************/ + +#ifndef KDTOOLBOX_PROPAGATE_CONST +#define KDTOOLBOX_PROPAGATE_CONST + +#include <functional> +#include <type_traits> +#include <utility> + +// Our SFINAE is too noisy and clang-format gets confused. +// clang-format off + +namespace KDToolBox +{ + +template <typename T> +class propagate_const; + +namespace detail { +// Type traits to detect propagate_const specializations +template <typename T> +struct is_propagate_const : std::false_type +{ +}; + +template <typename T> +struct is_propagate_const<propagate_const<T>> : std::true_type +{ +}; + +// Using SFINAE in a base class to constrain the conversion operators. +// Otherwise, if we make them function templates and apply SFINAE directly on +// them, we would not be able to do certain conversions (cf. +// [over.ics.user/3]). +template <typename T> +using propagate_const_element_type = std::remove_reference_t<decltype(*std::declval<T &>())>; + +// Const conversion. +// NON-STANDARD: checks that `const T` is convertible, not `T`. +// See https://wg21.link/lwg3812 +template <typename T, + bool = std::disjunction_v< + std::is_pointer<T>, + std::is_convertible<const T, const propagate_const_element_type<T> *> + > + > +struct propagate_const_const_conversion_operator_base +{ +}; + +template <typename T> +struct propagate_const_const_conversion_operator_base<T, true> +{ + constexpr operator const propagate_const_element_type<T> *() const; +}; + +// Non-const conversion +template <typename T, + bool = std::disjunction_v< + std::is_pointer<T>, + std::is_convertible<T, propagate_const_element_type<T> *> + > + > +struct propagate_const_non_const_conversion_operator_base +{ +}; + +template <typename T> +struct propagate_const_non_const_conversion_operator_base<T, true> +{ + constexpr operator propagate_const_element_type<T> *(); +}; + +template <typename T> +struct propagate_const_base + : propagate_const_const_conversion_operator_base<T>, + propagate_const_non_const_conversion_operator_base<T> +{}; + +} // namespace detail + +/* + TODO: This code could benefit from a C++20 overhaul: + * concepts + * three-way comparisons + * explicit(bool) + + However we can't depend on C++20 yet... +*/ + +template <typename T> +class propagate_const : public detail::propagate_const_base<T> +{ +public: + using element_type = detail::propagate_const_element_type<T>; + + // Special member functions + propagate_const() = default; + propagate_const(propagate_const &&) = default; + propagate_const &operator=(propagate_const &&) = default; + propagate_const(const propagate_const &) = delete; + propagate_const &operator=(const propagate_const &) = delete; + ~propagate_const() = default; + + // Constructor from values + + template < + typename U, + std::enable_if_t< // This constructor is enabled if: + std::conjunction_v< + std::is_constructible<T, U>, // 1) we can build a T from a U, + std::negation<detail::is_propagate_const<std::decay_t<U>>>, // 2) we are not making a + // converting constructor, + std::is_convertible<U, T> // 3) and the conversion from U to T is implicit; + >, + bool> = true> + /* implicit */ // then, this constructor is implicit too. + propagate_const(U &&other) + : m_t(std::forward<U>(other)) + { + } + + template < + typename U, + std::enable_if_t< // This constructor is enabled if: + std::conjunction_v< + std::is_constructible<T, U>, // 1) we can build a T from a U, + std::negation<detail::is_propagate_const<std::decay_t<U>>>, // 2) we are not making a + // converting constructor, + std::negation<std::is_convertible<U, T>> // 3) and the conversion from U to T is + // explicit; + >, + bool> = true> + explicit // then, this constructor is explicit. + propagate_const(U &&other) + : m_t(std::forward<U>(other)) + { + } + + // Constructors from other propagate_const (converting constructors) + template <typename U, + std::enable_if_t< // This constructor is enabled if: + std::conjunction_v<std::is_constructible<T, U>, // 1) we can do the conversion, + std::is_convertible<U, T> // 2) and the conversion is implicit; + >, + bool> = true> + /* implicit */ // then, this constructor is implicit. + constexpr propagate_const(propagate_const<U> &&other) + : m_t(std::move(get_underlying(other))) + { + } + + template <typename U, + std::enable_if_t< // This constructor is enabled if: + std::conjunction_v<std::is_constructible<T, U>, // 1) we can do the conversion, + std::negation<std::is_convertible<U, T>> // 2) and the + // conversion is + // explicit; + >, + bool> = true> + explicit // then, this constructor is explicit. + constexpr propagate_const(propagate_const<U> &&other) + : m_t(std::move(get_underlying(other))) + { + } + + // Converting assignment + template <typename U, + std::enable_if_t< // This assignment operator is enabled if + std::is_convertible_v<U, T>, // the conversion from U to T is implicit + bool> = true> + constexpr propagate_const &operator=(propagate_const<U> &&other) + { + m_t = std::move(get_underlying(other)); + return *this; + } + + template <typename U, + std::enable_if_t< // This assignment operator is enabled if: + std::conjunction_v< + std::is_convertible<U, T>, // 1) the conversion from U to T is implicit, + std::negation<detail::is_propagate_const<std::decay_t<U>>> // 2) and U is not a + // propagate_const + >, + bool> = true> + constexpr propagate_const &operator=(U &&other) + { + m_t = std::forward<U>(other); + return *this; + } + + // Swap + constexpr void swap(propagate_const &other) noexcept(std::is_nothrow_swappable_v<T>) + { + using std::swap; + swap(m_t, other.m_t); + } + + // Const observers + constexpr explicit operator bool() const { return static_cast<bool>(m_t); } + + constexpr const element_type *get() const { return get_impl(m_t); } + + constexpr const element_type &operator*() const { return *get(); } + + constexpr const element_type *operator->() const { return get(); } + + // Non-const observers + constexpr element_type *get() { return get_impl(m_t); } + + constexpr element_type &operator*() { return *get(); } + + constexpr element_type *operator->() { return get(); } + + // Non-member utilities: extract the contained object + template <typename U> + friend constexpr auto &get_underlying(propagate_const<U> &p); + + template <typename U> + friend constexpr const auto &get_underlying(const propagate_const<U> &p); + +private: + // Implementation of get() that works with raw pointers and smart + // pointers. Similar to std::to_address, but to_address is C++20, + // and propagate_const spec does not match it. + template <typename U> + static constexpr element_type *get_impl(U *u) + { + return u; + } + + template <typename U> + static constexpr element_type *get_impl(U &u) + { + return u.get(); + } + + template <typename U> + static constexpr const element_type *get_impl(const U *u) + { + return u; + } + + template <typename U> + static constexpr const element_type *get_impl(const U &u) + { + return u.get(); + } + + T m_t; +}; + +// Swap +template <typename T, + std::enable_if_t<std::is_swappable_v<T>, bool> = true> +constexpr void swap(propagate_const<T> &lhs, propagate_const<T> &rhs) + noexcept(noexcept(lhs.swap(rhs))) +{ + lhs.swap(rhs); +} + +// Implementation of get_underlying +template <typename T> +constexpr auto &get_underlying(propagate_const<T> &p) +{ + return p.m_t; +} + +template <typename T> +constexpr const auto &get_underlying(const propagate_const<T> &p) +{ + return p.m_t; +} + +// Implementation of the conversion operators +template <typename T> +constexpr detail::propagate_const_const_conversion_operator_base<T, true> + ::operator const detail::propagate_const_element_type<T> *() const +{ + return static_cast<const propagate_const<T> *>(this)->get(); +} + +template <typename T> +constexpr detail::propagate_const_non_const_conversion_operator_base<T, true> + ::operator detail::propagate_const_element_type<T> *() +{ + return static_cast<propagate_const<T> *>(this)->get(); +} + +// Comparisons. As per spec, they're free function templates. + +// Comparisons against nullptr. +template <typename T> +constexpr bool operator==(const propagate_const<T> &p, std::nullptr_t) +{ + return get_underlying(p) == nullptr; +} + +template <typename T> +constexpr bool operator!=(const propagate_const<T> &p, std::nullptr_t) +{ + return get_underlying(p) != nullptr; +} + +template <typename T> +constexpr bool operator==(std::nullptr_t, const propagate_const<T> &p) +{ + return nullptr == get_underlying(p); +} + +template <typename T> +constexpr bool operator!=(std::nullptr_t, const propagate_const<T> &p) +{ + return nullptr == get_underlying(p); +} + +// Comparisons between propagate_const +#define DEFINE_PROPAGATE_CONST_COMPARISON_OP(op) \ +template <typename T, typename U> \ + constexpr bool operator op (const propagate_const<T> &lhs, const propagate_const<U> &rhs) \ +{ \ + return get_underlying(lhs) op get_underlying(rhs); \ +} \ + + DEFINE_PROPAGATE_CONST_COMPARISON_OP(==) + DEFINE_PROPAGATE_CONST_COMPARISON_OP(!=) + DEFINE_PROPAGATE_CONST_COMPARISON_OP(<) + DEFINE_PROPAGATE_CONST_COMPARISON_OP(<=) + DEFINE_PROPAGATE_CONST_COMPARISON_OP(>) + DEFINE_PROPAGATE_CONST_COMPARISON_OP(>=) + +#undef DEFINE_PROPAGATE_CONST_COMPARISON_OP + +// Comparisons against other (smart) pointers +#define DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(op) \ + template <typename T, typename U> \ + constexpr bool operator op (const propagate_const<T> &lhs, const U &rhs) \ +{ \ + return get_underlying(lhs) op rhs; \ +} \ + template <typename T, typename U> \ + constexpr bool operator op (const T &lhs, const propagate_const<U> &rhs) \ +{ \ + return lhs op get_underlying(rhs); \ +} \ + + DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(==) + DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(!=) + DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(<) + DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(<=) + DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(>) + DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP(>=) + +#undef DEFINE_PROPAGATE_CONST_MIXED_COMPARISON_OP + +} // namespace KDToolBox + +// std::hash specialization +namespace std +{ +template <typename T> +struct hash<KDToolBox::propagate_const<T>> +{ + constexpr size_t operator()(const KDToolBox::propagate_const<T> &t) const + noexcept(noexcept(hash<T>{}(get_underlying(t)))) + { + return hash<T>{}(get_underlying(t)); + } +}; + +#define DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(COMP) \ +template <typename T> \ + struct COMP<KDToolBox::propagate_const<T>> \ +{ \ + constexpr bool operator()(const KDToolBox::propagate_const<T> &lhs, \ + const KDToolBox::propagate_const<T> &rhs) \ + { \ + return COMP<T>{}(get_underlying(lhs), get_underlying(rhs)); \ + } \ +}; \ + + DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(equal_to) + DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(not_equal_to) + DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(less) + DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(greater) + DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(less_equal) + DEFINE_COMP_OBJECT_SPECIALIZATION_FOR_PROPAGATE_CONST(greater_equal) + +#undef DEFINE_COMP_OBJECT_SPECIALIZATION + +} // namespace std + +#endif // KDTOOLBOX_PROPAGATE_CONST diff --git a/src/lib/corelib/tools/qbs_export.h b/src/lib/corelib/tools/qbs_export.h index 164aa4184..2cfe1cd82 100644 --- a/src/lib/corelib/tools/qbs_export.h +++ b/src/lib/corelib/tools/qbs_export.h @@ -53,14 +53,14 @@ #else # ifdef QBS_LIBRARY # define QBS_EXPORT QBS_DECL_EXPORT -# ifdef QBS_ENABLE_UNIT_TESTS +# ifdef QBS_WITH_TESTS # define QBS_AUTOTEST_EXPORT QBS_DECL_EXPORT # else # define QBS_AUTOTEST_EXPORT # endif # else # define QBS_EXPORT QBS_DECL_IMPORT -# ifdef QBS_ENABLE_UNIT_TESTS +# ifdef QBS_WITH_TESTS # define QBS_AUTOTEST_EXPORT QBS_DECL_IMPORT # else # define QBS_AUTOTEST_EXPORT diff --git a/src/lib/corelib/tools/qbsassert.h b/src/lib/corelib/tools/qbsassert.h index e8dfcacf8..65352fdb3 100644 --- a/src/lib/corelib/tools/qbsassert.h +++ b/src/lib/corelib/tools/qbsassert.h @@ -59,6 +59,11 @@ QBS_EXPORT void writeAssertLocation(const char *condition, const char *file, int // The do {} while (0) is here to enforce the use of a semicolon after QBS_ASSERT. // action can also be continue or break. Copied from qtcassert.h in Qt Creator. +#define QBS_GUARD(cond) \ + (Q_LIKELY(cond) \ + ? true \ + : (::qbs::Internal::writeAssertLocation(#cond, __FILE__, __LINE__), false)) + #define QBS_CHECK(cond)\ do {\ if (Q_LIKELY(cond)) {} else {\ diff --git a/src/lib/corelib/tools/qbspluginmanager.cpp b/src/lib/corelib/tools/qbspluginmanager.cpp index d4e92e22a..0816d9d25 100644 --- a/src/lib/corelib/tools/qbspluginmanager.cpp +++ b/src/lib/corelib/tools/qbspluginmanager.cpp @@ -79,7 +79,7 @@ QbsPluginManager::~QbsPluginManager() { unloadStaticPlugins(); - for (QLibrary * const lib : qAsConst(d->libs)) { + for (QLibrary * const lib : std::as_const(d->libs)) { auto unload = reinterpret_cast<QbsPluginUnloadFunction>(lib->resolve("QbsPluginUnload")); if (unload) unload(); diff --git a/src/lib/corelib/tools/qbsprocess.cpp b/src/lib/corelib/tools/qbsprocess.cpp index de2590e8a..3fdc05afe 100644 --- a/src/lib/corelib/tools/qbsprocess.cpp +++ b/src/lib/corelib/tools/qbsprocess.cpp @@ -120,7 +120,7 @@ void QbsProcess::sendPacket(const LauncherPacket &packet) QByteArray QbsProcess::readAndClear(QByteArray &data) { - const QByteArray tmp = data; + QByteArray tmp = data; data.clear(); return tmp; } diff --git a/src/lib/corelib/tools/qttools.h b/src/lib/corelib/tools/qttools.h index bc1210d53..029948be4 100644 --- a/src/lib/corelib/tools/qttools.h +++ b/src/lib/corelib/tools/qttools.h @@ -55,19 +55,7 @@ QT_BEGIN_NAMESPACE class QProcessEnvironment; QT_END_NAMESPACE -#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) -#define QBS_SKIP_EMPTY_PARTS QString::SkipEmptyParts -#else -#define QBS_SKIP_EMPTY_PARTS Qt::SkipEmptyParts -#endif - namespace std { -#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) -template<> struct hash<QString> { - std::size_t operator()(const QString &s) const { return qHash(s); } -}; -#endif - template<typename T1, typename T2> struct hash<std::pair<T1, T2>> { size_t operator()(const pair<T1, T2> &x) const @@ -161,12 +149,6 @@ inline qbs::QHashValueType qHash(const QVariantHash &v) return std::hash<QVariantHash>()(v) % std::numeric_limits<uint>::max(); } -#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 { @@ -174,32 +156,20 @@ namespace qbs { template <class T> QSet<T> toSet(const QList<T> &list) { -#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) - return list.toSet(); -#else return QSet<T>(list.begin(), list.end()); -#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 } template<typename K, typename V> QHash<K, V> &unite(QHash<K, V> &h, const QHash<K, V> &other) { -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - return h.unite(other); -#else h.insert(other); return h; -#endif } inline void setupDefaultCodec(QTextStream &stream) @@ -229,6 +199,51 @@ inline bool qVariantConvert(QVariant &variant, int typeId) #endif } +inline QMetaType::Type qVariantType(const QVariant &v) +{ + return static_cast<QMetaType::Type>( +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + v.metaType().id() +#else + v.type() +#endif + ); +} + +template<typename T> +inline QVariant typedNullVariant() +{ + const auto metaType = QMetaType::fromType<T>(); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + return QVariant(metaType, nullptr); +#else + return QVariant(static_cast<QVariant::Type>(metaType.id())); +#endif +} + +inline bool qVariantsEqual(const QVariant &v1, const QVariant &v2) +{ + return v1.isNull() == v2.isNull() && v1 == v2; +} + +inline bool qVariantMapsEqual(const QVariantMap &m1, const QVariantMap &m2) +{ + if (m1.size() != m2.size()) + return false; + if (m1.isSharedWith(m2)) + return true; + + auto it1 = m1.cbegin(); + auto it2 = m2.cbegin(); + while (it1 != m1.cend()) { + if (it1.key() != it2.key() || !qVariantsEqual(it1.value(), it2.value())) + return false; + ++it2; + ++it1; + } + return true; +} + } // namespace qbs #endif // QBSQTTOOLS_H diff --git a/src/lib/corelib/tools/scripttools.cpp b/src/lib/corelib/tools/scripttools.cpp index ed88520fc..e89e4a0ad 100644 --- a/src/lib/corelib/tools/scripttools.cpp +++ b/src/lib/corelib/tools/scripttools.cpp @@ -39,9 +39,14 @@ #include "scripttools.h" -#include <QtCore/qdatastream.h> +#include <language/scriptengine.h> +#include <tools/error.h> -#include <QtScript/qscriptengine.h> +#include <QtCore/qdatastream.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsondocument.h> +#include <QtCore/qjsonobject.h> namespace qbs { namespace Internal { @@ -65,16 +70,259 @@ QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name) return getConfigProperty(cfg.value(name.front()).toMap(), name.mid(1)); } -TemporaryGlobalObjectSetter::TemporaryGlobalObjectSetter(const QScriptValue &object) +TemporaryGlobalObjectSetter::TemporaryGlobalObjectSetter( + ScriptEngine *engine, const JSValue &object) + : m_engine(engine), m_oldGlobalObject(engine->globalObject()) { - QScriptEngine *engine = object.engine(); - m_oldGlobalObject = engine->globalObject(); engine->setGlobalObject(object); } TemporaryGlobalObjectSetter::~TemporaryGlobalObjectSetter() { - m_oldGlobalObject.engine()->setGlobalObject(m_oldGlobalObject); + m_engine->setGlobalObject(m_oldGlobalObject); +} + +JsException::JsException(JsException &&other) noexcept + : m_ctx(other.m_ctx), m_exception(other.m_exception), + m_fallbackLocation(std::move(other.m_fallbackLocation)) +{ + other.m_exception = JS_NULL; +} + +JsException::~JsException() { JS_FreeValue(m_ctx, m_exception); } + +QString JsException::message() const +{ + if (JS_IsError(m_ctx, m_exception)) + return getJsStringProperty(m_ctx, m_exception, QStringLiteral("message")); + const QVariant v = getJsVariant(m_ctx, m_exception); + switch (static_cast<QMetaType::Type>(v.userType())) { + case QMetaType::QVariantMap: + return QString::fromUtf8(QJsonDocument(QJsonObject::fromVariantMap(v.toMap())) + .toJson(QJsonDocument::Indented)); + case QMetaType::QStringList: + return QString::fromUtf8(QJsonDocument(QJsonArray::fromStringList(v.toStringList())) + .toJson(QJsonDocument::Indented)); + case QMetaType::QVariantList: + return QString::fromUtf8(QJsonDocument(QJsonArray::fromVariantList(v.toList())) + .toJson(QJsonDocument::Indented)); + default: + return v.toString(); + } +} + +const QStringList JsException::stackTrace() const +{ + return getJsStringProperty(m_ctx, m_exception, QLatin1String("stack")) + .split(QLatin1Char('\n'), Qt::SkipEmptyParts); +} + +ErrorInfo JsException::toErrorInfo() const +{ + const QString msg = message(); + ErrorInfo e(msg, stackTrace()); + if (e.hasLocation() || !m_fallbackLocation.isValid()) + return e; + return {msg, m_fallbackLocation}; +} + +void defineJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, JSValue val) +{ + JS_DefinePropertyValueStr(ctx, obj, prop.toUtf8().constData(), val, 0); +} + +JSValue getJsProperty(JSContext *ctx, JSValue obj, const QString &prop) +{ + return JS_GetPropertyStr(ctx, obj, prop.toUtf8().constData()); +} + +void setJsProperty(JSContext *ctx, JSValue obj, const QString &prop, JSValue val) +{ + if (JS_SetPropertyStr(ctx, obj, prop.toUtf8().constData(), val) <= 0) + qDebug() << "Oje!"; +} + +void setJsProperty(JSContext *ctx, JSValue obj, const QString &prop, const QString &val) +{ + setJsProperty(ctx, obj, prop, makeJsString(ctx, val)); +} + +void handleJsProperties(JSContext *ctx, JSValue obj, + const std::function<void (const JSAtom &, + const JSPropertyDescriptor &)> &handler) +{ + struct PropsHolder { + PropsHolder(JSContext *ctx) : ctx(ctx) {} + ~PropsHolder() { + for (uint32_t i = 0; i < count; ++i) + JS_FreeAtom(ctx, props[i].atom); + js_free(ctx, props); + } + JSContext * const ctx; + JSPropertyEnum *props = nullptr; + uint32_t count = 0; + } propsHolder(ctx); + JS_GetOwnPropertyNames(ctx, &propsHolder.props, &propsHolder.count, obj, JS_GPN_STRING_MASK); + for (uint32_t i = 0; i < propsHolder.count; ++i) { + JSPropertyDescriptor desc{0, JS_UNDEFINED, JS_UNDEFINED, JS_UNDEFINED}; + JS_GetOwnProperty(ctx, &desc, obj, propsHolder.props[i].atom); + const ScopedJsValueList valueHolder(ctx, {desc.value, desc.getter, desc.setter}); + handler(propsHolder.props[i].atom, desc); + } +} + +QString getJsString(JSContext *ctx, JSValueConst val) +{ + size_t strLen; + const char * const str = JS_ToCStringLen(ctx, &strLen, val); + QString s = QString::fromUtf8(str, strLen); + JS_FreeCString(ctx, str); + return s; +} + +QString getJsStringProperty(JSContext *ctx, JSValue obj, const QString &prop) +{ + const ScopedJsValue sv(ctx, getJsProperty(ctx, obj, prop)); + return getJsString(ctx, sv); +} + +int getJsIntProperty(JSContext *ctx, JSValue obj, const QString &prop) +{ + return JS_VALUE_GET_INT(getJsProperty(ctx, obj, prop)); +} + +bool getJsBoolProperty(JSContext *ctx, JSValue obj, const QString &prop) +{ + return JS_VALUE_GET_BOOL(getJsProperty(ctx, obj, prop)); +} + +JSValue makeJsArrayBuffer(JSContext *ctx, const QByteArray &s) +{ + return ScriptEngine::engineForContext(ctx)->asJsValue(s); +} + +JSValue makeJsString(JSContext *ctx, const QString &s) +{ + return ScriptEngine::engineForContext(ctx)->asJsValue(s); +} + +JSValue makeJsStringList(JSContext *ctx, const QStringList &l) +{ + return ScriptEngine::engineForContext(ctx)->asJsValue(l); +} + +JSValue throwError(JSContext *ctx, const QString &message) +{ + return JS_Throw(ctx, makeJsString(ctx, message)); +} + +QStringList getJsStringList(JSContext *ctx, JSValue val) +{ + if (JS_IsString(val)) + return {getJsString(ctx, val)}; + if (!JS_IsArray(ctx, val)) + return {}; + const int size = getJsIntProperty(ctx, val, QLatin1String("length")); + QStringList l; + for (int i = 0; i < size; ++i) { + const ScopedJsValue elem(ctx, JS_GetPropertyUint32(ctx, val, i)); + l << getJsString(ctx, elem); + } + return l; +} + +JSValue makeJsVariant(JSContext *ctx, const QVariant &v, quintptr id) +{ + return ScriptEngine::engineForContext(ctx)->asJsValue(v, id); +} + +JSValue makeJsVariantList(JSContext *ctx, const QVariantList &l, quintptr id) +{ + return ScriptEngine::engineForContext(ctx)->asJsValue(l, id); +} + +JSValue makeJsVariantMap(JSContext *ctx, const QVariantMap &m, quintptr id) +{ + return ScriptEngine::engineForContext(ctx)->asJsValue(m, id); +} + +static QVariant getJsVariantImpl(JSContext *ctx, JSValue val, QList<JSValue> path) +{ + if (JS_IsString(val)) + return getJsString(ctx, val); + if (JS_IsBool(val)) + return bool(JS_VALUE_GET_BOOL(val)); + if (JS_IsArrayBuffer(val)) { + size_t size = 0; + const auto data = JS_GetArrayBuffer(ctx, &size, val); + if (!data || !size) + return QByteArray(); + return QByteArray(reinterpret_cast<const char *>(data), size); + } + if (JS_IsArray(ctx, val)) { + if (path.contains(val)) + return {}; + path << val; + QVariantList l; + const int size = getJsIntProperty(ctx, val, QLatin1String("length")); + for (int i = 0; i < size; ++i) { + const ScopedJsValue sv(ctx, JS_GetPropertyUint32(ctx, val, i)); + l << getJsVariantImpl(ctx, sv, path); + } + return l; + } + if (JS_IsDate(val)) { + ScopedJsValue toString(ctx, getJsProperty(ctx, val, QLatin1String("toISOString"))); + if (!JS_IsFunction(ctx, toString)) + return {}; + ScopedJsValue dateString(ctx, JS_Call(ctx, toString, val, 0, nullptr)); + if (!JS_IsString(dateString)) + return {}; + return QDateTime::fromString(getJsString(ctx, dateString), Qt::ISODateWithMs); + } + if (JS_IsObject(val)) { + if (path.contains(val)) + return {}; + path << val; + QVariantMap map; + handleJsProperties(ctx, val, [ctx, &map, path](const JSAtom &prop, const JSPropertyDescriptor &desc) { + map.insert(getJsString(ctx, prop), getJsVariantImpl(ctx, desc.value, path)); + }); + return map; + } + const auto tag = JS_VALUE_GET_TAG(val); + if (tag == JS_TAG_INT) + return JS_VALUE_GET_INT(val); + else if (JS_TAG_IS_FLOAT64(tag)) + return JS_VALUE_GET_FLOAT64(val); + return {}; +} + +QVariant getJsVariant(JSContext *ctx, JSValue val) +{ + return getJsVariantImpl(ctx, val, {}); +} + +QStringList getJsStringListProperty(JSContext *ctx, JSValue obj, const QString &prop) +{ + JSValue array = getJsProperty(ctx, obj, prop); + QStringList list = getJsStringList(ctx, array); + JS_FreeValue(ctx, array); + return list; +} + +QVariant getJsVariantProperty(JSContext *ctx, JSValue obj, const QString &prop) +{ + const JSValue vv = getJsProperty(ctx, obj, prop); + QVariant v = getJsVariant(ctx, vv); + JS_FreeValue(ctx, vv); + return v; +} + +QString getJsString(JSContext *ctx, JSAtom atom) +{ + const ScopedJsValue atomString(ctx, JS_AtomToString(ctx, atom)); + return getJsString(ctx, atomString); } } // namespace Internal diff --git a/src/lib/corelib/tools/scripttools.h b/src/lib/corelib/tools/scripttools.h index 4a258b98f..ac7ed9928 100644 --- a/src/lib/corelib/tools/scripttools.h +++ b/src/lib/corelib/tools/scripttools.h @@ -40,57 +40,172 @@ #ifndef QBS_SCRIPTTOOLS_H #define QBS_SCRIPTTOOLS_H -#include <tools/qbs_export.h> +#include "codelocation.h" +#include "porting.h" +#include "qbs_export.h" +#include <quickjs.h> + +#include <QtCore/qhash.h> #include <QtCore/qstringlist.h> #include <QtCore/qvariant.h> -#include <QtScript/qscriptengine.h> -#include <QtScript/qscriptprogram.h> -#include <QtScript/qscriptvalue.h> +#include <utility> +#include <vector> namespace qbs { +class ErrorInfo; namespace Internal { +class ScriptEngine; -template <typename C> -QScriptValue toScriptValue(QScriptEngine *scriptEngine, const C &container) -{ - QScriptValue v = scriptEngine->newArray(container.size()); - int i = 0; - for (const typename C::value_type &item : container) - v.setProperty(i++, scriptEngine->toScriptValue(item)); - return v; -} +using JSValueList = std::vector<JSValue>; -void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value); -QVariant QBS_AUTOTEST_EXPORT getConfigProperty(const QVariantMap &cfg, const QStringList &name); +void defineJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, JSValue val); +JSValue getJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop); +void setJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, JSValue val); +void setJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, const QString &val); +QString getJsStringProperty(JSContext *ctx, JSValueConst obj, const QString &prop); +QStringList getJsStringListProperty(JSContext *ctx, JSValueConst obj, const QString &prop); +int getJsIntProperty(JSContext *ctx, JSValueConst obj, const QString &prop); +bool getJsBoolProperty(JSContext *ctx, JSValueConst obj, const QString &prop); +QVariant getJsVariantProperty(JSContext *ctx, JSValueConst obj, const QString &prop); +QString getJsString(JSContext *ctx, JSValueConst val); +QString getJsString(JSContext *ctx, JSAtom atom); +QBS_AUTOTEST_EXPORT QVariant getJsVariant(JSContext *ctx, JSValueConst val); +JSValue makeJsArrayBuffer(JSContext *ctx, const QByteArray &s); +JSValue makeJsString(JSContext *ctx, const QString &s); +JSValue makeJsStringList(JSContext *ctx, const QStringList &l); +JSValue makeJsVariant(JSContext *ctx, const QVariant &v, quintptr id = 0); +JSValue makeJsVariantList(JSContext *ctx, const QVariantList &l, quintptr id = 0); +JSValue makeJsVariantMap(JSContext *ctx, const QVariantMap &m, quintptr id = 0); +QStringList getJsStringList(JSContext *ctx, JSValueConst val); +JSValue throwError(JSContext *ctx, const QString &message); +using PropertyHandler = std::function<void(const JSAtom &, const JSPropertyDescriptor &)>; +void handleJsProperties(JSContext *ctx, JSValueConst obj, const PropertyHandler &handler); +inline quintptr jsObjectId(const JSValue &val) { return quintptr(JS_VALUE_GET_OBJ(val)); } template <class T> -void attachPointerTo(QScriptValue &scriptValue, T *ptr) +void attachPointerTo(JSValue &scriptValue, T *ptr) { - QVariant v; - v.setValue<quintptr>(reinterpret_cast<quintptr>(ptr)); - scriptValue.setData(scriptValue.engine()->newVariant(v)); + JS_SetOpaque(scriptValue, const_cast<std::remove_const_t<T> *>(ptr)); } template <class T> -T *attachedPointer(const QScriptValue &scriptValue) +T *attachedPointer(const JSValue &scriptValue, JSClassID id) { - const auto ptr = scriptValue.data().toVariant().value<quintptr>(); - return reinterpret_cast<T *>(ptr); + return reinterpret_cast<T *>(JS_GetOpaque(scriptValue, id)); } class TemporaryGlobalObjectSetter { public: - TemporaryGlobalObjectSetter(const QScriptValue &object); + TemporaryGlobalObjectSetter(ScriptEngine *engine, const JSValue &object); ~TemporaryGlobalObjectSetter(); private: - QScriptValue m_oldGlobalObject; + ScriptEngine * const m_engine; + const JSValue m_oldGlobalObject; +}; + +class ScopedJsValue +{ +public: + ScopedJsValue(JSContext *ctx, JSValue v) : m_context(ctx), m_value(v) {} + void setValue(JSValue v) { JS_FreeValue(m_context, m_value); m_value = v; } + ~ScopedJsValue() { JS_FreeValue(m_context, m_value); } + operator JSValue() const { return m_value; } + JSValue release() { const JSValue v = m_value; m_value = JS_UNDEFINED; return v; } + void reset(JSValue v) { JS_FreeValue(m_context, m_value); m_value = v; } + + ScopedJsValue(const ScopedJsValue &) = delete; + ScopedJsValue &operator=(const ScopedJsValue &) = delete; + + ScopedJsValue(ScopedJsValue && other) : m_context(other.m_context), m_value(other.m_value) + { + other.m_value = JS_UNDEFINED; + } + +private: + JSContext * const m_context; + JSValue m_value; }; +class ScopedJsValueList +{ +public: + ScopedJsValueList(JSContext *ctx, const JSValueList &l) : m_context(ctx), m_list(l) {} + ~ScopedJsValueList() { for (const JSValue v : m_list) JS_FreeValue(m_context, v); } + operator JSValueList() const { return m_list; } + + ScopedJsValueList(const ScopedJsValueList &) = delete; + ScopedJsValueList &operator=(const ScopedJsValueList &) = delete; + + ScopedJsValueList(ScopedJsValueList && other) noexcept + : m_context(other.m_context), m_list(std::move(other.m_list)) + { + other.m_list.clear(); + } + +private: + JSContext * const m_context; + JSValueList m_list; +}; + +class ScopedJsAtom +{ +public: + ScopedJsAtom(JSContext *ctx, JSAtom a) : m_context(ctx), m_atom(a) {} + ScopedJsAtom(JSContext *ctx, const QByteArray &s) + : ScopedJsAtom(ctx, JS_NewAtom(ctx, s.constData())) {} + ScopedJsAtom(JSContext *ctx, const QString &s) : ScopedJsAtom(ctx, s.toUtf8()) {} + ~ScopedJsAtom() { JS_FreeAtom(m_context, m_atom); } + operator JSAtom() const { return m_atom; } + + ScopedJsAtom(const ScopedJsAtom &) = delete; + ScopedJsAtom&operator=(const ScopedJsAtom &) = delete; + + ScopedJsAtom(ScopedJsAtom &&other) : m_context(other.m_context), m_atom(other.m_atom) + { + other.m_atom = 0; + } + +private: + JSContext * const m_context; + JSAtom m_atom; +}; + +class QBS_AUTOTEST_EXPORT JsException +{ +public: + JsException(JSContext *ctx, JSValue ex, const CodeLocation &fallbackLocation) + : m_ctx(ctx), m_exception(ex), m_fallbackLocation(fallbackLocation) {} + JsException(JsException && other) noexcept; + ~JsException(); + JsException(const JsException &) = delete; + JsException &operator=(const JsException &) = delete; + + operator bool() const { return !JS_IsNull(m_exception); } + QString message() const; + const QStringList stackTrace() const; + ErrorInfo toErrorInfo() const; +private: + JSContext *m_ctx; + JSValue m_exception; + CodeLocation m_fallbackLocation; +}; + +void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value); +QVariant QBS_AUTOTEST_EXPORT getConfigProperty(const QVariantMap &cfg, const QStringList &name); + } // namespace Internal } // namespace qbs +// Only to be used for objects! +#ifndef JS_NAN_BOXING +inline bool operator==(JSValue v1, JSValue v2) { return v1.u.ptr == v2.u.ptr; } +inline bool operator!=(JSValue v1, JSValue v2) { return !(v1 == v2); } +inline bool operator<(JSValue v1, JSValue v2) { return v1.u.ptr < v2.u.ptr; } +inline qbs::QHashValueType qHash(const JSValue &v) { return QT_PREPEND_NAMESPACE(qHash)(v.u.ptr); } +#endif + #endif // QBS_SCRIPTTOOLS_H diff --git a/src/lib/corelib/tools/settings.cpp b/src/lib/corelib/tools/settings.cpp index 8b22c45e5..4a3d9d727 100644 --- a/src/lib/corelib/tools/settings.cpp +++ b/src/lib/corelib/tools/settings.cpp @@ -135,13 +135,22 @@ QStringList Settings::allKeys(Scopes scopes) const return keys; } -QStringList Settings::directChildren(const QString &parentGroup, Scope scope) const +QStringList Settings::directChildren(const QString &parentGroup, Scopes scopes) const { - QSettings * const settings = settingsForScope(scope); - settings->beginGroup(internalRepresentation(parentGroup)); - QStringList children = settings->childGroups(); - children << settings->childKeys(); - settings->endGroup(); + auto helper = [this, &parentGroup](const Scope scope) { + QSettings * const settings = settingsForScope(scope); + settings->beginGroup(internalRepresentation(parentGroup)); + QStringList children = settings->childGroups(); + children << settings->childKeys(); + settings->endGroup(); + return children; + }; + + QStringList children; + if (scopes & UserScope) + children += helper(UserScope); + if (scopes & SystemScope) + children += helper(SystemScope); fixupKeys(children); return children; } diff --git a/src/lib/corelib/tools/settings.h b/src/lib/corelib/tools/settings.h index 4ea148af0..7c9c52c9e 100644 --- a/src/lib/corelib/tools/settings.h +++ b/src/lib/corelib/tools/settings.h @@ -70,7 +70,7 @@ public: QVariant value(const QString &key, Scopes scopes, const QVariant &defaultValue = QVariant()) const; QStringList allKeys(Scopes scopes) const; - QStringList directChildren(const QString &parentGroup, Scope scope) const; // Keys and groups. + QStringList directChildren(const QString &parentGroup, Scopes scopes) const; // Keys and groups. QStringList allKeysWithPrefix(const QString &group, Scopes scopes) const; void setValue(const QString &key, const QVariant &value); void remove(const QString &key); diff --git a/src/lib/corelib/tools/settingscreator.cpp b/src/lib/corelib/tools/settingscreator.cpp index f94ae6f10..2cef0e5ce 100644 --- a/src/lib/corelib/tools/settingscreator.cpp +++ b/src/lib/corelib/tools/settingscreator.cpp @@ -53,14 +53,26 @@ namespace qbs { namespace Internal { +namespace { +QString getBaseDir(QString baseDir) { + if (!baseDir.isEmpty()) + return baseDir; + + const char key[] = "QBS_SETTINGS_DIR"; + if (qEnvironmentVariableIsSet(key)) + return QLatin1String(qgetenv(key)); + + return {}; +} +} // namespace + static QSettings::Format format() { return HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat; } - SettingsCreator::SettingsCreator(QString baseDir) - : m_settingsBaseDir(std::move(baseDir)) + : m_settingsBaseDir(getBaseDir(std::move(baseDir))) , m_qbsVersion(Version::fromString(QLatin1String(QBS_VERSION))) { } diff --git a/src/lib/corelib/tools/settingsmodel.cpp b/src/lib/corelib/tools/settingsmodel.cpp index 31aa0f5f1..4fa0e14da 100644 --- a/src/lib/corelib/tools/settingsmodel.cpp +++ b/src/lib/corelib/tools/settingsmodel.cpp @@ -78,7 +78,7 @@ QString Node::uniqueChildName() const bool unique; do { unique = true; - for (const Node *childNode : qAsConst(children)) { + for (const Node *childNode : std::as_const(children)) { if (childNode->name == newName) { unique = false; newName += QLatin1Char('_'); @@ -281,10 +281,10 @@ bool SettingsModel::setData(const QModelIndex &index, const QVariant &value, int const QString valueString = value.toString(); QString *toChange = nullptr; if (index.column() == keyColumn() && !valueString.isEmpty() - && !node->parent->hasDirectChildWithName(valueString) - && !(node->parent->parent == &d->rootNode - && node->parent->name == Internal::StringConstants::profilesSettingsKey() - && valueString == Profile::fallbackName())) { + && !node->parent->hasDirectChildWithName(valueString) + && (node->parent->parent != &d->rootNode + || node->parent->name != Internal::StringConstants::profilesSettingsKey() + || valueString != Profile::fallbackName())) { toChange = &node->name; } else if (index.column() == valueColumn() && valueString != node->value) { toChange = &node->value; @@ -329,7 +329,7 @@ void SettingsModel::SettingsModelPrivate::readSettings() addNodeFromSettings(&rootNode, topLevelKey); for (QVariantMap::ConstIterator it = additionalProperties.constBegin(); it != additionalProperties.constEnd(); ++it) { - const QStringList nameAsList = it.key().split(QLatin1Char('.'), QBS_SKIP_EMPTY_PARTS); + const QStringList nameAsList = it.key().split(QLatin1Char('.'), Qt::SkipEmptyParts); addNode(&rootNode, nameAsList.front(), nameAsList.mid(1), it.value()); } dirty = false; @@ -361,7 +361,7 @@ void SettingsModel::SettingsModelPrivate::addNode(qbs::Internal::Node *parentNod const QString ¤tNamePart, const QStringList &restOfName, const QVariant &value) { Node *currentNode = nullptr; - for (Node * const n : qAsConst(parentNode->children)) { + for (Node * const n : std::as_const(parentNode->children)) { if (n->name == currentNamePart) { currentNode = n; break; @@ -385,7 +385,7 @@ void SettingsModel::SettingsModelPrivate::doSave(const Node *node, const QString } const QString newPrefix = prefix + node->name + QLatin1Char('.'); - for (const Node * const child : qAsConst(node->children)) + for (const Node * const child : std::as_const(node->children)) doSave(child, newPrefix); } diff --git a/src/lib/corelib/tools/settingsrepresentation.cpp b/src/lib/corelib/tools/settingsrepresentation.cpp index 7790f1aa1..6dfd81beb 100644 --- a/src/lib/corelib/tools/settingsrepresentation.cpp +++ b/src/lib/corelib/tools/settingsrepresentation.cpp @@ -41,8 +41,8 @@ #include "jsliterals.h" -#include <QtScript/qscriptengine.h> -#include <QtScript/qscriptvalue.h> +#include <language/scriptengine.h> +#include <logging/logger.h> namespace qbs { @@ -54,11 +54,19 @@ QString settingsValueToRepresentation(const QVariant &value) static QVariant variantFromString(const QString &str, bool &ok) { // ### use Qt5's JSON reader at some point. - QScriptEngine engine; - QScriptValue sv = engine.evaluate(QLatin1String("(function(){return ") - + str + QLatin1String(";})()")); - ok = !sv.isError(); - return sv.toVariant(); + class DummyLogSink : public ILogSink { + void doPrintMessage(LoggerLevel, const QString &, const QString &) override { } + } logSink; + Internal::Logger logger(&logSink); + + const auto engine = Internal::ScriptEngine::create(logger, {}); + Internal::ScopedJsValue sv( + engine->context(), + engine->evaluate(Internal::JsValueOwner::Caller, + QLatin1String("(function(){return ") + str + + QLatin1String(";})()"))); + ok = !engine->checkAndClearException({}); + return Internal::getJsVariant(engine->context(), sv); } QVariant representationToSettingsValue(const QString &representation) diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp index a06ffc4bd..e9212c165 100644 --- a/src/lib/corelib/tools/setupprojectparameters.cpp +++ b/src/lib/corelib/tools/setupprojectparameters.cpp @@ -38,6 +38,8 @@ ****************************************************************************/ #include "setupprojectparameters.h" +#include "buildoptions.h" + #include <logging/logger.h> #include <logging/translator.h> #include <tools/buildgraphlocker.h> @@ -45,8 +47,10 @@ #include <tools/jsonhelper.h> #include <tools/profile.h> #include <tools/qbsassert.h> +#include <tools/qttools.h> #include <tools/scripttools.h> #include <tools/settings.h> +#include <tools/stringconstants.h> #include <QtCore/qdir.h> #include <QtCore/qfileinfo.h> @@ -89,21 +93,24 @@ public: mutable QVariantMap buildConfigurationTree; mutable QVariantMap overriddenValuesTree; mutable QVariantMap finalBuildConfigTree; + int maxJobCount = 0; bool overrideBuildGraphData; bool dryRun; bool logElapsedTime; bool forceProbeExecution; bool waitLockBuildGraph; - bool fallbackProviderEnabled = true; SetupProjectParameters::RestoreBehavior restoreBehavior; ErrorHandlingMode propertyCheckingMode; ErrorHandlingMode productErrorMode; + DeprecationWarningMode deprecationWarningMode = defaultDeprecationWarningMode(); QProcessEnvironment environment; }; } // namespace Internal -SetupProjectParameters::SetupProjectParameters() : d(new Internal::SetupProjectParametersPrivate) +using namespace Internal; + +SetupProjectParameters::SetupProjectParameters() : d(new SetupProjectParametersPrivate) { } @@ -125,6 +132,11 @@ template<> ErrorHandlingMode fromJson(const QJsonValue &v) return ErrorHandlingMode::Strict; } +template<> DeprecationWarningMode fromJson(const QJsonValue &v) +{ + return deprecationWarningModeFromName(v.toString()); +} + template<> SetupProjectParameters::RestoreBehavior fromJson(const QJsonValue &v) { const QString value = v.toString(); @@ -145,15 +157,18 @@ SetupProjectParameters SetupProjectParameters::fromJson(const QJsonObject &data) setValueFromJson(params.d->projectFilePath, data, "project-file-path"); setValueFromJson(params.d->buildRoot, data, "build-root"); setValueFromJson(params.d->settingsBaseDir, data, "settings-directory"); + setValueFromJson(params.d->maxJobCount, data, "max-job-count"); + if (params.maxJobCount() <= 0) + params.setMaxJobCount(BuildOptions::defaultMaxJobCount()); setValueFromJson(params.d->overriddenValues, data, "overridden-properties"); setValueFromJson(params.d->dryRun, data, "dry-run"); setValueFromJson(params.d->logElapsedTime, data, "log-time"); setValueFromJson(params.d->forceProbeExecution, data, "force-probe-execution"); setValueFromJson(params.d->waitLockBuildGraph, data, "wait-lock-build-graph"); - setValueFromJson(params.d->fallbackProviderEnabled, data, "fallback-provider-enabled"); setValueFromJson(params.d->environment, data, "environment"); setValueFromJson(params.d->restoreBehavior, data, "restore-behavior"); setValueFromJson(params.d->propertyCheckingMode, data, "error-handling-mode"); + setValueFromJson(params.d->deprecationWarningMode, data, "deprecation-warning-mode"); params.d->productErrorMode = params.d->propertyCheckingMode; return params; } @@ -219,6 +234,44 @@ void SetupProjectParameters::setProjectFilePath(const QString &projectFilePath) d->projectFilePath = canonicalProjectFilePath; } +void SetupProjectParameters::finalizeProjectFilePath() +{ + QString filePath = projectFilePath(); + if (filePath.isEmpty()) + filePath = QDir::currentPath(); + const QFileInfo projectFileInfo(filePath); + if (!projectFileInfo.exists()) + throw ErrorInfo(Tr::tr("Project file '%1' cannot be found.").arg(filePath)); + if (projectFileInfo.isRelative()) + filePath = projectFileInfo.absoluteFilePath(); + if (projectFileInfo.isFile()) { + setProjectFilePath(filePath); + return; + } + if (!projectFileInfo.isDir()) + throw ErrorInfo(Tr::tr("Project file '%1' has invalid type.").arg(filePath)); + + const QStringList &actualFileNames + = QDir(filePath).entryList(StringConstants::qbsFileWildcards(), QDir::Files); + if (actualFileNames.empty()) { + QString error; + if (projectFilePath().isEmpty()) + error = Tr::tr("No project file given and none found in current directory.\n"); + else + error = Tr::tr("No project file found in directory '%1'.").arg(filePath); + throw ErrorInfo(error); + } + if (actualFileNames.size() > 1) { + throw ErrorInfo(Tr::tr("More than one project file found in directory '%1'.") + .arg(filePath)); + } + filePath.append(QLatin1Char('/')).append(actualFileNames.front()); + + filePath = QDir::current().filePath(filePath); + filePath = QDir::cleanPath(filePath); + setProjectFilePath(filePath); +} + /*! * \brief Returns the base path of where to put the build artifacts and store the build graph. */ @@ -243,7 +296,7 @@ void SetupProjectParameters::setBuildRoot(const QString &buildRoot) // Calling mkpath() may be necessary to get the canonical build root, but if we do it, // it must be reverted immediately afterwards as not to create directories needlessly, // e.g in the case of a dry run build. - Internal::DirectoryManager dirManager(buildRoot, Internal::Logger()); + DirectoryManager dirManager(buildRoot, Logger()); // We don't do error checking here, as this is not a convenient place to report an error. // If creation of the build directory is not possible, we will get sensible error messages @@ -325,6 +378,27 @@ void SetupProjectParameters::setSettingsDirectory(const QString &settingsBaseDir } /*! + * \brief Returns the maximum number of threads to employ when resolving the project. + * If the value is not valid (i.e. <= 0), a sensible one will be derived from the number of + * available processor cores. + * The default is 0. + * \sa BuildOptions::defaultMaxJobCount + */ +int SetupProjectParameters::maxJobCount() const +{ + return d->maxJobCount; +} + +/*! + * \brief Controls how many threads to employ when resolving the project. + * A value <= 0 leaves the decision to qbs. + */ +void SetupProjectParameters::setMaxJobCount(int jobCount) +{ + d->maxJobCount = jobCount; +} + +/*! * Returns the overridden values of the build configuration. */ QVariantMap SetupProjectParameters::overriddenValues() const @@ -354,7 +428,7 @@ static void provideValuesTree(const QVariantMap &values, QVariantMap *valueTree) const QStringList nameElements = (idx == -1) ? QStringList() << name : QStringList() << name.left(idx) << name.mid(idx + 1); - Internal::setConfigProperty(*valueTree, nameElements, it.value()); + setConfigProperty(*valueTree, nameElements, it.value()); } } @@ -395,7 +469,7 @@ static QVariantMap expandedBuildConfigurationInternal(const Profile &profile, if (err.hasError()) throw err; if (profileKeys.empty()) - throw ErrorInfo(Internal::Tr::tr("Unknown or empty profile '%1'.").arg(profile.name())); + throw ErrorInfo(Tr::tr("Unknown or empty profile '%1'.").arg(profile.name())); for (const QString &profileKey : profileKeys) { buildConfig.insert(profileKey, profile.value(profileKey, QVariant(), &err)); if (err.hasError()) @@ -405,7 +479,7 @@ static QVariantMap expandedBuildConfigurationInternal(const Profile &profile, // (2) Build configuration name. if (configurationName.isEmpty()) - throw ErrorInfo(Internal::Tr::tr("No build configuration name set.")); + throw ErrorInfo(Tr::tr("No build configuration name set.")); buildConfig.insert(QStringLiteral("qbs.configurationName"), configurationName); return buildConfig; } @@ -442,7 +516,7 @@ ErrorInfo SetupProjectParameters::expandBuildConfiguration() QVariantMap expandedConfig = expandedBuildConfiguration(profile, configurationName(), &err); if (err.hasError()) return err; - if (d->buildConfiguration != expandedConfig) { + if (!qVariantMapsEqual(d->buildConfiguration, expandedConfig)) { d->buildConfigurationTree.clear(); d->buildConfiguration = expandedConfig; } @@ -547,22 +621,6 @@ void SetupProjectParameters::setWaitLockBuildGraph(bool wait) } /*! - * \brief Returns true if qbs should fall back to pkg-config if a dependency is not found. - */ -bool SetupProjectParameters::fallbackProviderEnabled() const -{ - return d->fallbackProviderEnabled; -} - -/*! - * Controls whether to fall back to pkg-config if a dependency is not found. - */ -void SetupProjectParameters::setFallbackProviderEnabled(bool enable) -{ - d->fallbackProviderEnabled = enable; -} - -/*! * \brief Gets the environment used while resolving the project. */ QProcessEnvironment SetupProjectParameters::environment() const @@ -688,4 +746,20 @@ void SetupProjectParameters::setProductErrorMode(ErrorHandlingMode mode) d->productErrorMode = mode; } +/*! + * \brief Indicates how deprecated constructs are handled. + */ +DeprecationWarningMode SetupProjectParameters::deprecationWarningMode() const +{ + return d->deprecationWarningMode; +} + +/*! + * \brief Specifies the behavior on encountering deprecated constructs. + */ +void SetupProjectParameters::setDeprecationWarningMode(DeprecationWarningMode mode) +{ + d->deprecationWarningMode = mode; +} + } // namespace qbs diff --git a/src/lib/corelib/tools/setupprojectparameters.h b/src/lib/corelib/tools/setupprojectparameters.h index 2617a34cd..5cd9700a9 100644 --- a/src/lib/corelib/tools/setupprojectparameters.h +++ b/src/lib/corelib/tools/setupprojectparameters.h @@ -41,6 +41,7 @@ #include "qbs_export.h" +#include <tools/deprecationwarningmode.h> #include <tools/error.h> #include <QtCore/qshareddata.h> @@ -81,6 +82,7 @@ public: QString projectFilePath() const; void setProjectFilePath(const QString &projectFilePath); + void finalizeProjectFilePath(); QString buildRoot() const; void setBuildRoot(const QString &buildRoot); @@ -97,6 +99,9 @@ public: QString settingsDirectory() const; void setSettingsDirectory(const QString &settingsBaseDir); + int maxJobCount() const; + void setMaxJobCount(int jobCount); + QVariantMap overriddenValues() const; void setOverriddenValues(const QVariantMap &values); QVariantMap overriddenValuesTree() const; @@ -127,9 +132,6 @@ public: bool waitLockBuildGraph() const; void setWaitLockBuildGraph(bool wait); - bool fallbackProviderEnabled() const; - void setFallbackProviderEnabled(bool enable); - QProcessEnvironment environment() const; void setEnvironment(const QProcessEnvironment &env); QProcessEnvironment adjustedEnvironment() const; @@ -144,6 +146,9 @@ public: ErrorHandlingMode productErrorMode() const; void setProductErrorMode(ErrorHandlingMode mode); + DeprecationWarningMode deprecationWarningMode() const; + void setDeprecationWarningMode(DeprecationWarningMode mode); + private: QSharedDataPointer<Internal::SetupProjectParametersPrivate> d; }; diff --git a/src/lib/corelib/tools/shellutils.cpp b/src/lib/corelib/tools/shellutils.cpp index d032aecac..5fff254f6 100644 --- a/src/lib/corelib/tools/shellutils.cpp +++ b/src/lib/corelib/tools/shellutils.cpp @@ -57,7 +57,7 @@ QString shellInterpreter(const QString &filePath) { const QString shebang = ts.readLine(); if (shebang.startsWith(QLatin1String("#!"))) { return (shebang.mid(2).split(QRegularExpression(QStringLiteral("\\s")), - QBS_SKIP_EMPTY_PARTS) << QString()).front(); + Qt::SkipEmptyParts) << QString()).front(); } } diff --git a/src/lib/corelib/tools/stlutils.h b/src/lib/corelib/tools/stlutils.h index 70e3f2b6d..306f37157 100644 --- a/src/lib/corelib/tools/stlutils.h +++ b/src/lib/corelib/tools/stlutils.h @@ -46,14 +46,24 @@ namespace qbs { namespace Internal { -template <class C> -C sorted(const C &container) +template <typename C> +auto sorted(C &&container) { - C result = container; + using R = std::remove_cv_t<std::remove_reference_t<C>>; + R result(std::forward<C>(container)); std::sort(std::begin(result), std::end(result)); return result; } +template <typename C, typename Pred> +auto sorted(C &&container, Pred &&pred) +{ + using R = std::remove_cv_t<std::remove_reference_t<C>>; + R result(std::forward<C>(container)); + std::sort(std::begin(result), std::end(result), std::forward<Pred>(pred)); + return result; +} + template <typename To, typename From, typename Op> To transformed(const From &from, Op op) { diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h index f40bfa4a7..799a140d9 100644 --- a/src/lib/corelib/tools/stringconstants.h +++ b/src/lib/corelib/tools/stringconstants.h @@ -110,6 +110,7 @@ public: QBS_STRING_CONSTANT(installDirProperty, "installDir") QBS_STRING_CONSTANT(installSourceBaseProperty, "installSourceBase") QBS_STRING_CONSTANT(isEnabledKey, "is-enabled") + QBS_STRING_CONSTANT(isEagerProperty, "isEager") QBS_STRING_CONSTANT(jobCountProperty, "jobCount") QBS_STRING_CONSTANT(jobPoolProperty, "jobPool") QBS_STRING_CONSTANT(lengthProperty, "length") @@ -168,6 +169,7 @@ public: QBS_STRING_CONSTANT(importScopeNamePropertyInternal, "_qbs_importScopeName") QBS_STRING_CONSTANT(modulePropertyInternal, "__module") + QBS_STRING_CONSTANT(dataPropertyInternal, "_qbs_data") QBS_STRING_CONSTANT(qbsSourceDirPropertyInternal, "_qbs_sourceDir") static const char *qbsProcEnvVarInternal() { return "_qbs_procenv"; } diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri deleted file mode 100644 index 1fdacc016..000000000 --- a/src/lib/corelib/tools/tools.pri +++ /dev/null @@ -1,147 +0,0 @@ -include(../../../install_prefix.pri) - -INCLUDEPATH += $$PWD/../.. # for plugins - -QBS_SYSTEM_SETTINGS_DIR = $$(QBS_SYSTEM_SETTINGS_DIR) -!isEmpty(QBS_SYSTEM_SETTINGS_DIR) { - DEFINES += 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 \ - $$PWD/error.h \ - $$PWD/executablefinder.h \ - $$PWD/fileinfo.h \ - $$PWD/filesaver.h \ - $$PWD/filetime.h \ - $$PWD/generateoptions.h \ - $$PWD/id.h \ - $$PWD/iosutils.h \ - $$PWD/joblimits.h \ - $$PWD/jsliterals.h \ - $$PWD/jsonhelper.h \ - $$PWD/launcherinterface.h \ - $$PWD/launcherpackets.h \ - $$PWD/launchersocket.h \ - $$PWD/msvcinfo.h \ - $$PWD/persistence.h \ - $$PWD/porting.h \ - $$PWD/scannerpluginmanager.h \ - $$PWD/scripttools.h \ - $$PWD/set.h \ - $$PWD/settings.h \ - $$PWD/settingsmodel.h \ - $$PWD/settingsrepresentation.h \ - $$PWD/pathutils.h \ - $$PWD/preferences.h \ - $$PWD/profile.h \ - $$PWD/profiling.h \ - $$PWD/processresult.h \ - $$PWD/processresult_p.h \ - $$PWD/processutils.h \ - $$PWD/progressobserver.h \ - $$PWD/projectgeneratormanager.h \ - $$PWD/qbspluginmanager.h \ - $$PWD/qbsprocess.h \ - $$PWD/shellutils.h \ - $$PWD/stlutils.h \ - $$PWD/stringutils.h \ - $$PWD/toolchains.h \ - $$PWD/hostosinfo.h \ - $$PWD/buildoptions.h \ - $$PWD/installoptions.h \ - $$PWD/cleanoptions.h \ - $$PWD/setupprojectparameters.h \ - $$PWD/weakpointer.h \ - $$PWD/qbs_export.h \ - $$PWD/qbsassert.h \ - $$PWD/qttools.h \ - $$PWD/settingscreator.h \ - $$PWD/stringconstants.h \ - $$PWD/version.h \ - $$PWD/visualstudioversioninfo.h \ - $$PWD/vsenvironmentdetector.h - -SOURCES += \ - $$PWD/architectures.cpp \ - $$PWD/buildgraphlocker.cpp \ - $$PWD/clangclinfo.cpp \ - $$PWD/codelocation.cpp \ - $$PWD/commandechomode.cpp \ - $$PWD/error.cpp \ - $$PWD/executablefinder.cpp \ - $$PWD/fileinfo.cpp \ - $$PWD/filesaver.cpp \ - $$PWD/filetime.cpp \ - $$PWD/generateoptions.cpp \ - $$PWD/id.cpp \ - $$PWD/joblimits.cpp \ - $$PWD/jsliterals.cpp \ - $$PWD/launcherinterface.cpp \ - $$PWD/launcherpackets.cpp \ - $$PWD/launchersocket.cpp \ - $$PWD/msvcinfo.cpp \ - $$PWD/persistence.cpp \ - $$PWD/scannerpluginmanager.cpp \ - $$PWD/scripttools.cpp \ - $$PWD/settings.cpp \ - $$PWD/settingsmodel.cpp \ - $$PWD/settingsrepresentation.cpp \ - $$PWD/preferences.cpp \ - $$PWD/processresult.cpp \ - $$PWD/processutils.cpp \ - $$PWD/profile.cpp \ - $$PWD/profiling.cpp \ - $$PWD/progressobserver.cpp \ - $$PWD/projectgeneratormanager.cpp \ - $$PWD/qbspluginmanager.cpp \ - $$PWD/qbsprocess.cpp \ - $$PWD/shellutils.cpp \ - $$PWD/buildoptions.cpp \ - $$PWD/installoptions.cpp \ - $$PWD/cleanoptions.cpp \ - $$PWD/setupprojectparameters.cpp \ - $$PWD/qbsassert.cpp \ - $$PWD/qttools.cpp \ - $$PWD/settingscreator.cpp \ - $$PWD/toolchains.cpp \ - $$PWD/version.cpp \ - $$PWD/visualstudioversioninfo.cpp \ - $$PWD/vsenvironmentdetector.cpp - -osx { - HEADERS += $$PWD/applecodesignutils.h - SOURCES += $$PWD/applecodesignutils.cpp - LIBS += -framework Security -} - -!qbs_no_dev_install { - tools_headers.files = \ - $$PWD/architectures.h \ - $$PWD/buildoptions.h \ - $$PWD/cleanoptions.h \ - $$PWD/codelocation.h \ - $$PWD/commandechomode.h \ - $$PWD/error.h \ - $$PWD/generateoptions.h \ - $$PWD/installoptions.h \ - $$PWD/joblimits.h \ - $$PWD/preferences.h \ - $$PWD/processresult.h \ - $$PWD/profile.h \ - $$PWD/projectgeneratormanager.h \ - $$PWD/qbs_export.h \ - $$PWD/settings.h \ - $$PWD/settingsmodel.h \ - $$PWD/settingsrepresentation.h \ - $$PWD/setupprojectparameters.h \ - $$PWD/toolchains.h \ - $$PWD/version.h - tools_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/tools - INSTALLS += tools_headers -} |