aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/corelib/tools')
-rw-r--r--src/lib/corelib/tools/applecodesignutils.cpp8
-rw-r--r--src/lib/corelib/tools/architectures.cpp2
-rw-r--r--src/lib/corelib/tools/buildoptions.cpp4
-rw-r--r--src/lib/corelib/tools/clangclinfo.cpp6
-rw-r--r--src/lib/corelib/tools/codelocation.cpp43
-rw-r--r--src/lib/corelib/tools/codelocation.h74
-rw-r--r--src/lib/corelib/tools/deprecationwarningmode.cpp98
-rw-r--r--src/lib/corelib/tools/deprecationwarningmode.h59
-rw-r--r--src/lib/corelib/tools/error.cpp28
-rw-r--r--src/lib/corelib/tools/error.h1
-rw-r--r--src/lib/corelib/tools/executablefinder.cpp6
-rw-r--r--src/lib/corelib/tools/fileinfo.h8
-rw-r--r--src/lib/corelib/tools/installoptions.cpp2
-rw-r--r--src/lib/corelib/tools/launchersocket.cpp9
-rw-r--r--src/lib/corelib/tools/msvcinfo.cpp11
-rw-r--r--src/lib/corelib/tools/mutexdata.h104
-rw-r--r--src/lib/corelib/tools/persistence.cpp10
-rw-r--r--src/lib/corelib/tools/persistence.h18
-rw-r--r--src/lib/corelib/tools/pimpl.h61
-rw-r--r--src/lib/corelib/tools/profile.cpp2
-rw-r--r--src/lib/corelib/tools/profiling.cpp8
-rw-r--r--src/lib/corelib/tools/profiling.h2
-rw-r--r--src/lib/corelib/tools/progressobserver.h11
-rw-r--r--src/lib/corelib/tools/propagate_const.h418
-rw-r--r--src/lib/corelib/tools/qbs_export.h4
-rw-r--r--src/lib/corelib/tools/qbsassert.h5
-rw-r--r--src/lib/corelib/tools/qbspluginmanager.cpp2
-rw-r--r--src/lib/corelib/tools/qbsprocess.cpp2
-rw-r--r--src/lib/corelib/tools/qttools.h75
-rw-r--r--src/lib/corelib/tools/scripttools.cpp260
-rw-r--r--src/lib/corelib/tools/scripttools.h163
-rw-r--r--src/lib/corelib/tools/settings.cpp21
-rw-r--r--src/lib/corelib/tools/settings.h2
-rw-r--r--src/lib/corelib/tools/settingscreator.cpp16
-rw-r--r--src/lib/corelib/tools/settingsmodel.cpp16
-rw-r--r--src/lib/corelib/tools/settingsrepresentation.cpp22
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.cpp122
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.h11
-rw-r--r--src/lib/corelib/tools/shellutils.cpp2
-rw-r--r--src/lib/corelib/tools/stlutils.h16
-rw-r--r--src/lib/corelib/tools/stringconstants.h2
-rw-r--r--src/lib/corelib/tools/tools.pri147
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 &currentNamePart, 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
-}