From cf8f23e8e0f0bf497941740f03d565f274c0f593 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 13 Apr 2023 13:37:43 +0200 Subject: [PATCH 01/12] SquishTests: Fix wrong usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amends 476f67cce57. Change-Id: I584a059b52515bf625a973fff43485f5b52e6061 Reviewed-by: Robert Löhning --- tests/system/suite_general/tst_default_settings/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/suite_general/tst_default_settings/test.py b/tests/system/suite_general/tst_default_settings/test.py index 10a31534535..866720b27b8 100644 --- a/tests/system/suite_general/tst_default_settings/test.py +++ b/tests/system/suite_general/tst_default_settings/test.py @@ -35,7 +35,7 @@ def __checkKits__(): if llvmForBuild is not None: internalClangExe = os.path.join(llvmForBuild, "bin", "clang") if platform.system() in ("Microsoft", "Windows"): - internalClangExe.append(".exe") + internalClangExe += ".exe" if os.path.exists(internalClangExe): expectedCompilers.append(internalClangExe) foundCompilers = [] From 9beec994529b6ff80aff1dc7714ecfdf52d3e30b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 13 Apr 2023 14:02:51 +0200 Subject: [PATCH 02/12] SquishTests: Expect another build fail on Win MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id4051f4f82c1219209fd59e72f1add76ec338a87 Reviewed-by: Robert Löhning --- tests/system/suite_debugger/tst_build_new_project/test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/suite_debugger/tst_build_new_project/test.py b/tests/system/suite_debugger/tst_build_new_project/test.py index ca0d6f70879..b29678ffcf6 100644 --- a/tests/system/suite_debugger/tst_build_new_project/test.py +++ b/tests/system/suite_debugger/tst_build_new_project/test.py @@ -18,6 +18,7 @@ def main(): expectBuildToFail = [] if platform.system() in ('Microsoft', 'Windows'): expectConfigureToFail = [ Targets.DESKTOP_5_4_1_GCC ] # gcc 4.9 does not know C++17 + expectBuildToFail = [ Targets.DESKTOP_5_10_1_DEFAULT ] # fails to handle constexpr correctly for kit, config in availableConfigs: selectBuildConfig(kit, config) From 2d01003c4e37041efc63bd536d1cd06ce4928bf7 Mon Sep 17 00:00:00 2001 From: Zoltan Gera Date: Wed, 12 Apr 2023 18:11:34 +0300 Subject: [PATCH 03/12] Android: Automotive debugging capability Android Automotive images use special system users to run Android apps and activities. To maintain compatibility with all Android flavors not only the process ID but also the user ID of the process should be detected in order to be able to start the debugger with the correct user credentials. Failing to do so caused the debugging server to terminate upon not being able to connect to the app to be debugged. This also disabled the native debugging in Qt Creator. Task-number: QTCREATORBUG-28851 Change-Id: Ib4cd0ba7f252096cb7b8b14f959c8f0c743d8bf2 Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/android/androidrunnerworker.cpp | 188 ++++++++++++-------- src/plugins/android/androidrunnerworker.h | 9 +- 2 files changed, 124 insertions(+), 73 deletions(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index e702d487b01..7567cc06183 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -51,6 +51,7 @@ namespace Android { namespace Internal { static const QString pidPollingScript = QStringLiteral("while [ -d /proc/%1 ]; do sleep 1; done"); +static const QRegularExpression userIdPattern("u(\\d+)_a"); static int APP_START_TIMEOUT = 45000; static bool isTimedOut(const chrono::high_resolution_clock::time_point &start, @@ -77,8 +78,8 @@ static qint64 extractPID(const QString &output, const QString &packageName) return pid; } -static void findProcessPID(QFutureInterface &fi, QStringList selector, - const QString &packageName, bool preNougat) +static void findProcessPIDAndUser(QFutureInterface &fi, QStringList selector, + const QString &packageName, bool preNougat) { if (packageName.isEmpty()) return; @@ -108,8 +109,32 @@ static void findProcessPID(QFutureInterface &fi, QStringList selector, } while ((processPID == -1 || processPID == 0) && !isTimedOut(start) && !fi.isCanceled()); qCDebug(androidRunWorkerLog) << "PID found:" << processPID << ", PreNougat:" << preNougat; + + qint64 processUser = 0; + if (processPID > 0 && !fi.isCanceled()) { + args = {selector}; + args.append({"shell", "ps", "-o", "user", "-p"}); + args.append(QString::number(processPID)); + QtcProcess proc; + proc.setCommand({adbPath, args}); + proc.runBlocking(); + const QString out = proc.allOutput(); + if (!out.isEmpty()) { + QRegularExpressionMatch match; + qsizetype matchPos = out.indexOf(userIdPattern, 0, &match); + if (matchPos >= 0 && match.hasCaptured(1) && match.capturedLength(1) > 0) { + bool ok = false; + processUser = match.captured(1).toInt(&ok); + if (!ok) + processUser = 0; + } + } + } + + qCDebug(androidRunWorkerLog) << "USER found:" << processUser; + if (!fi.isCanceled()) - fi.reportResult(processPID); + fi.reportResult(PidUserPair(processPID, processUser)); } static void deleter(QProcess *p) @@ -325,13 +350,16 @@ bool AndroidRunnerWorker::uploadDebugServer(const QString &debugServerFileName) return false; } + QStringList adbArgs = {"shell", "run-as", m_packageName}; + if (m_processUser > 0) + adbArgs << "--user" << QString::number(m_processUser); // Copy gdbserver from temp location to app directory - if (!runAdb({"shell", "run-as", m_packageName, "cp" , tempDebugServerPath, debugServerFileName})) { + if (!runAdb(adbArgs + QStringList({"cp" , tempDebugServerPath, debugServerFileName}))) { qCDebug(androidRunWorkerLog) << "Debug server copy from temp directory failed"; return false; } - const bool ok = runAdb({"shell", "run-as", m_packageName, "chmod", "777", debugServerFileName}); + const bool ok = runAdb(adbArgs + QStringList({"chmod", "777", debugServerFileName})); QTC_ASSERT(ok, qCDebug(androidRunWorkerLog) << "Debug server chmod 777 failed."); return true; } @@ -346,7 +374,11 @@ bool AndroidRunnerWorker::deviceFileExists(const QString &filePath) bool AndroidRunnerWorker::packageFileExists(const QString &filePath) { QString output; - const bool success = runAdb({"shell", "run-as", m_packageName, "ls", filePath, "2>/dev/null"}, &output); + QStringList adbArgs = {"shell", "run-as", m_packageName}; + if (m_processUser > 0) + adbArgs << "--user" << QString::number(m_processUser); + const bool success = runAdb(adbArgs + QStringList({"ls", filePath, "2>/dev/null"}), + &output); return success && !output.trimmed().isEmpty(); } @@ -513,62 +545,8 @@ void AndroidRunnerWorker::asyncStartHelper() QStringList args({"shell", "am", "start"}); args << "-n" << m_intentName; - if (m_useCppDebugger) { + if (m_useCppDebugger) args << "-D"; - // run-as pwd fails on API 22 so route the pwd through shell. - QString packageDir; - if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"}, - &packageDir)) { - emit remoteProcessFinished(Tr::tr("Failed to find application directory.")); - return; - } - - // Add executable flag to package dir. Gdb can't connect to running server on device on - // e.g. on Android 8 with NDK 10e - runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()}); - - if (!m_debugServerPath.exists()) { - QString msg = Tr::tr("Cannot find C++ debug server in NDK installation."); - if (m_useLldb) - msg += "\n" + Tr::tr("The lldb-server binary has not been found."); - emit remoteProcessFinished(msg); - return; - } - - QString debugServerFile; - if (m_useLldb) { - debugServerFile = "./lldb-server"; - runAdb({"shell", "run-as", m_packageName, "killall", "lldb-server"}); - if (!uploadDebugServer(debugServerFile)) { - emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server.")); - return; - } - } else { - if (packageFileExists("./lib/gdbserver")) { - debugServerFile = "./lib/gdbserver"; - qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile; - runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"}); - } else if (packageFileExists("./lib/libgdbserver.so")) { - debugServerFile = "./lib/libgdbserver.so"; - qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile; - runAdb({"shell", "run-as", m_packageName, "killall", "libgdbserver.so"}); - } else { - // Armv8. symlink lib is not available. - debugServerFile = "./gdbserver"; - // Kill the previous instances of gdbserver. Do this before copying the gdbserver. - runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"}); - if (!uploadDebugServer("./gdbserver")) { - emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server.")); - return; - } - } - } - QString debuggerServerErr; - if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) { - emit remoteProcessFinished(debuggerServerErr); - return; - } - } if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) { // currently forward to same port on device and host @@ -624,17 +602,79 @@ void AndroidRunnerWorker::asyncStartHelper() } } +void AndroidRunnerWorker::startNativeDebugging() +{ + // run-as pwd fails on API 22 so route the pwd through shell. + QString packageDir; + QStringList adbArgs = {"shell", "run-as", m_packageName}; + if (m_processUser > 0) + adbArgs << "--user" << QString::number(m_processUser); + if (!runAdb(adbArgs + QStringList({"/system/bin/sh", "-c", "pwd"}), + &packageDir)) { + emit remoteProcessFinished(Tr::tr("Failed to find application directory.")); + return; + } + // Add executable flag to package dir. Gdb can't connect to running server on device on + // e.g. on Android 8 with NDK 10e + runAdb(adbArgs + QStringList({"chmod", "a+x", packageDir.trimmed()})); + if (!m_debugServerPath.exists()) { + QString msg = Tr::tr("Cannot find C++ debug server in NDK installation."); + if (m_useLldb) + msg += "\n" + Tr::tr("The lldb-server binary has not been found."); + emit remoteProcessFinished(msg); + return; + } + + QString debugServerFile; + if (m_useLldb) { + debugServerFile = "./lldb-server"; + runAdb(adbArgs + QStringList({"killall", "lldb-server"})); + if (!uploadDebugServer(debugServerFile)) { + emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server.")); + return; + } + } else { + if (packageFileExists("./lib/gdbserver")) { + debugServerFile = "./lib/gdbserver"; + qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile; + runAdb(adbArgs + QStringList({"killall", "gdbserver"})); + } else if (packageFileExists("./lib/libgdbserver.so")) { + debugServerFile = "./lib/libgdbserver.so"; + qCDebug(androidRunWorkerLog) << "Found GDB server " + debugServerFile; + runAdb(adbArgs + QStringList({"killall", "libgdbserver.so"})); + } else { + // Armv8. symlink lib is not available. + debugServerFile = "./gdbserver"; + // Kill the previous instances of gdbserver. Do this before copying the gdbserver. + runAdb(adbArgs + QStringList({"killall", "gdbserver"})); + if (!uploadDebugServer("./gdbserver")) { + emit remoteProcessFinished(Tr::tr("Cannot copy C++ debug server.")); + return; + } + } + } + QString debuggerServerErr; + if (!startDebuggerServer(packageDir, debugServerFile, &debuggerServerErr)) { + emit remoteProcessFinished(debuggerServerErr); + return; + } +} + bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir, const QString &debugServerFile, QString *errorStr) { + QStringList adbArgs = {"shell", "run-as", m_packageName}; + if (m_processUser > 0) + adbArgs << "--user" << QString::number(m_processUser); if (m_useLldb) { QString lldbServerErr; QStringList lldbServerArgs = selector(); - lldbServerArgs << "shell" << "run-as" << m_packageName << debugServerFile - << "platform" - // << "--server" // Can lead to zombie servers - << "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString()); + lldbServerArgs += adbArgs; + lldbServerArgs << debugServerFile + << "platform" + // << "--server" // Can lead to zombie servers + << "--listen" << QString("*:%1").arg(m_localDebugServerPort.toString()); m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(lldbServerArgs, &lldbServerErr)); if (!m_debugServerProcess) { @@ -648,12 +688,13 @@ bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir, } else { QString gdbServerSocket = packageDir + "/debug-socket"; - runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket}); + runAdb(adbArgs + QStringList({"rm", gdbServerSocket})); QString gdbProcessErr; QStringList gdbServerErr = selector(); - gdbServerErr << "shell" << "run-as" << m_packageName << debugServerFile - << "--multi" << "+" + gdbServerSocket; + gdbServerErr += adbArgs; + gdbServerErr << debugServerFile + << "--multi" << "+" + gdbServerSocket; m_debugServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerErr, &gdbProcessErr)); if (!m_debugServerProcess) { @@ -683,7 +724,7 @@ void AndroidRunnerWorker::asyncStart() { asyncStartHelper(); - m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, selector(), + m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPIDAndUser, selector(), m_packageName, m_isPreNougat), bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1)); } @@ -793,13 +834,16 @@ void AndroidRunnerWorker::removeForwardPort(const QString &port) } } -void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) +void AndroidRunnerWorker::onProcessIdChanged(PidUserPair pidUser) { + qint64 pid = pidUser.first; + qint64 user = pidUser.second; // Don't write to m_psProc from a different thread QTC_ASSERT(QThread::currentThread() == thread(), return); qCDebug(androidRunWorkerLog) << "Process ID changed from:" << m_processPID << "to:" << pid; m_processPID = pid; + m_processUser = user; if (pid == -1) { emit remoteProcessFinished(QLatin1String("\n\n") + Tr::tr("\"%1\" died.") .arg(m_packageName)); @@ -813,6 +857,8 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) for (const QString &entry: std::as_const(m_afterFinishAdbCommands)) runAdb(entry.split(' ', Qt::SkipEmptyParts)); } else { + if (m_useCppDebugger) + startNativeDebugging(); // In debugging cases this will be funneled to the engine to actually start // and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below. emit remoteProcessStarted(m_localDebugServerPort, m_qmlServer, m_processPID); @@ -824,7 +870,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) m_psIsAlive->setObjectName("IsAliveProcess"); m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels); connect(m_psIsAlive.get(), &QProcess::finished, - this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, -1)); + this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, PidUserPair(-1, -1))); } } diff --git a/src/plugins/android/androidrunnerworker.h b/src/plugins/android/androidrunnerworker.h index e8c340d1a37..7e41d2e9c73 100644 --- a/src/plugins/android/androidrunnerworker.h +++ b/src/plugins/android/androidrunnerworker.h @@ -10,6 +10,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QProcess; @@ -26,6 +27,8 @@ namespace Internal { const int MIN_SOCKET_HANDSHAKE_PORT = 20001; +using PidUserPair = std::pair; + class AndroidRunnerWorker : public QObject { Q_OBJECT @@ -61,6 +64,7 @@ signals: private: void asyncStartHelper(); + void startNativeDebugging(); bool startDebuggerServer(const QString &packageDir, const QString &debugServerFile, QString *errorStr = nullptr); bool deviceFileExists(const QString &filePath); bool packageFileExists(const QString& filePath); @@ -72,7 +76,7 @@ private: Waiting, Settled }; - void onProcessIdChanged(qint64 pid); + void onProcessIdChanged(PidUserPair pidUser); using Deleter = void (*)(QProcess *); // Create the processes and timer in the worker thread, for correct thread affinity @@ -83,11 +87,12 @@ private: QStringList m_afterFinishAdbCommands; QStringList m_amStartExtraArgs; qint64 m_processPID = -1; + qint64 m_processUser = -1; std::unique_ptr m_adbLogcatProcess; std::unique_ptr m_psIsAlive; QByteArray m_stdoutBuffer; QByteArray m_stderrBuffer; - QFuture m_pidFinder; + QFuture m_pidFinder; bool m_useCppDebugger = false; bool m_useLldb = false; // FIXME: Un-implemented currently. QmlDebug::QmlDebugServicesPreset m_qmlDebugServices; From 26bcec16419d3749a5d623c6edb3b99a09ac7aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 14 Apr 2023 16:23:13 +0200 Subject: [PATCH 04/12] SquishTests: Don't require Qt Quick Controls It's not available for any version we use anymore. Change-Id: I11556c42b4ed7924d3ede04749b0b26251d8f0da Reviewed-by: Reviewed-by: Christian Stenger --- tests/system/README | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/system/README b/tests/system/README index 45fd2e498be..43d65ec70ad 100644 --- a/tests/system/README +++ b/tests/system/README @@ -12,7 +12,6 @@ of the Qt installation from the online installer. It's easiest to use installations of the official opensource Qt packages. Just install the Qt version for the respective toolchain with the components (if available): - (Desktop) , e.g. Desktop gcc 64-bit -- Qt Quick Controls (if available) - Qt Script (Qt5 only) The exact versions and toolchains are: From 81b294d1b1ff572aec309edd9e02f7da615315b3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 14 Apr 2023 11:15:53 +0200 Subject: [PATCH 05/12] Update qbs submodule to HEAD of 2.0 branch Change-Id: Idc7a0d5d0f2c50b2e6606eb92ae49756db49ddf0 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 289aac0aa1c..978448ddfe8 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 289aac0aa1cccb2ef66a17f572aeb59236c6bd29 +Subproject commit 978448ddfe8aac9c4cc895f6c93429e0f9f689bc From bdfa412b14174e7e81b899ae8323fc78ddd7916e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 14 Apr 2023 13:09:35 +0200 Subject: [PATCH 06/12] Examples: Automatically enable showing categories for Qt >= 6.5.1 Supposedly that is the version that will have a sensible amount of examples sorted into categories to not look weird. It is still possible to force showing the categories with QTC_USE_EXAMPLE_CATEGORIES. Fixes: QTCREATORBUG-28546 Change-Id: Ia1e6afa97d9b1b86763c29209fcf6f674d0844f5 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/qtsupport/exampleslistmodel.cpp | 38 +++++++++++++++------ src/plugins/qtsupport/exampleslistmodel.h | 8 ++++- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index c567f992e41..d3cf3535dd9 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -44,6 +44,7 @@ static bool debugExamples() } static const char kSelectedExampleSetKey[] = "WelcomePage/SelectedExampleSet"; +Q_GLOBAL_STATIC_WITH_ARGS(QVersionNumber, minQtVersionForCategories, (6, 5, 1)); void ExampleSetModel::writeCurrentIdToSettings(int currentIndex) const { @@ -117,7 +118,7 @@ void ExampleSetModel::recreateModel(const QtVersions &qtVersions) beginResetModel(); clear(); - QSet extraManifestDirs; + QHash extraManifestDirs; for (int i = 0; i < m_extraExampleSets.size(); ++i) { const ExtraExampleSet &set = m_extraExampleSets.at(i); auto newItem = new QStandardItem(); @@ -127,14 +128,19 @@ void ExampleSetModel::recreateModel(const QtVersions &qtVersions) newItem->setData(i, Qt::UserRole + 3); appendRow(newItem); - extraManifestDirs.insert(set.manifestPath); + extraManifestDirs.insert(FilePath::fromUserInput(set.manifestPath), i); } for (QtVersion *version : qtVersions) { - // sanitize away qt versions that have already been added through extra sets - if (extraManifestDirs.contains(version->docsPath().toString())) { + // Sanitize away qt versions that have already been added through extra sets. + // This way we do not have entries for Qt/Android, Qt/Desktop, Qt/MinGW etc pp, + // but only the one "QtX X.Y.Z" entry that is registered as an example set by the installer. + if (extraManifestDirs.contains(version->docsPath())) { + m_extraExampleSets[extraManifestDirs.value(version->docsPath())].qtVersion + = version->qtVersion(); if (debugExamples()) { - qWarning() << "Not showing Qt version because manifest path is already added through InstalledExamples settings:" + qWarning() << "Not showing Qt version because manifest path is already added " + "through InstalledExamples settings:" << version->displayName(); } continue; @@ -330,10 +336,11 @@ static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second) } static QList>> getCategories( - const QList &items) + const QList &items, bool sortIntoCategories) { static const QString otherDisplayName = Tr::tr("Other", "Category for all other examples"); - const bool useCategories = qtcEnvironmentVariableIsSet("QTC_USE_EXAMPLE_CATEGORIES"); + const bool useCategories = sortIntoCategories + || qtcEnvironmentVariableIsSet("QTC_USE_EXAMPLE_CATEGORIES"); QList other; QMap> categoryMap; if (useCategories) { @@ -374,10 +381,11 @@ void ExamplesViewController::updateExamples() { QString examplesInstallPath; QString demosInstallPath; + QVersionNumber qtVersion; const QStringList sources = m_exampleSetModel->exampleSources(&examplesInstallPath, - &demosInstallPath); - + &demosInstallPath, + &qtVersion); m_view->clear(); QList items; @@ -414,7 +422,9 @@ void ExamplesViewController::updateExamples() } } - const QList>> sections = getCategories(items); + const bool sortIntoCategories = qtVersion >= *minQtVersionForCategories; + const QList>> sections + = getCategories(items, sortIntoCategories); for (int i = 0; i < sections.size(); ++i) { m_view->addSection({sections.at(i).first, i}, static_container_cast(sections.at(i).second)); @@ -482,7 +492,9 @@ QtVersion *ExampleSetModel::findHighestQtVersion(const QtVersions &versions) con return newVersion; } -QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, QString *demosInstallPath) +QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, + QString *demosInstallPath, + QVersionNumber *qtVersion) { QStringList sources; @@ -500,6 +512,8 @@ QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, QStrin manifestScanPath = exampleSet.manifestPath; examplesPath = exampleSet.examplesPath; demosPath = exampleSet.examplesPath; + if (qtVersion) + *qtVersion = exampleSet.qtVersion; } else if (currentType == ExampleSetModel::QtExampleSet) { const int qtId = getQtId(m_selectedExampleSetIndex); const QtVersions versions = QtVersionManager::versions(); @@ -508,6 +522,8 @@ QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, QStrin manifestScanPath = version->docsPath().toString(); examplesPath = version->examplesPath().toString(); demosPath = version->demosPath().toString(); + if (qtVersion) + *qtVersion = version->qtVersion(); break; } } diff --git a/src/plugins/qtsupport/exampleslistmodel.h b/src/plugins/qtsupport/exampleslistmodel.h index 0047bf45e3e..c444f9bc1e7 100644 --- a/src/plugins/qtsupport/exampleslistmodel.h +++ b/src/plugins/qtsupport/exampleslistmodel.h @@ -28,6 +28,10 @@ public: QString displayName; QString manifestPath; QString examplesPath; + // qtVersion is set by recreateModel for extra sets that correspond to actual Qt versions. + // This is needed for the decision to show categories or not based on the Qt version + // (which is not ideal). + QVersionNumber qtVersion; }; static QVector pluginRegisteredExampleSets(); @@ -35,7 +39,9 @@ public: int selectedExampleSet() const { return m_selectedExampleSetIndex; } void selectExampleSet(int index); - QStringList exampleSources(QString *examplesInstallPath, QString *demosInstallPath); + QStringList exampleSources(QString *examplesInstallPath, + QString *demosInstallPath, + QVersionNumber *qtVersion); bool selectedQtSupports(const Utils::Id &target) const; signals: From 8304f3c576d20949235ab9bcdfa23b513ceb1827 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 17 Apr 2023 13:12:31 +0200 Subject: [PATCH 07/12] ClangTools: Give the tool main windows unique object names Somewhat surprisingly, the object name is relevant: If we use the same one, then clang-tidy and clazy have the same issues view. Change-Id: I5ce32301780e5ae63c82fdb2ce3b1bca63ef85d5 Reviewed-by: David Schulz --- src/plugins/clangtools/clangtool.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index afe60be7dc8..109f23875c4 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -519,8 +519,8 @@ ClangTool::ClangTool(const QString &name, Utils::Id id) mainLayout->addWidget(m_infoBarWidget); mainLayout->addWidget(m_diagnosticView); auto mainWidget = new QWidget; - mainWidget->setObjectName("ClangTidyClazyIssuesView"); - mainWidget->setWindowTitle(Tr::tr("Clang-Tidy and Clazy")); + mainWidget->setObjectName(id.toString() + "IssuesView"); + mainWidget->setWindowTitle(name); mainWidget->setLayout(mainLayout); m_perspective.addWindow(mainWidget, Perspective::SplitVertical, nullptr); From 45faec05e555fec99c6cf75b3fc8844b37084919 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 31 Mar 2023 19:53:45 +0200 Subject: [PATCH 08/12] CMakePM: expand macros for all configure cacheVariables Fixes: QTCREATORBUG-28982 Change-Id: Iabbf39b815ed7477a9d272a320308f320a31adbc Reviewed-by: hjk --- .../cmakeprojectmanager/cmakeproject.cpp | 4 +- .../cmakeprojectimporter.cpp | 29 ++++--------- .../cmakeprojectmanager/presetsmacros.cpp | 42 +++++++++++++++++++ .../cmakeprojectmanager/presetsmacros.h | 8 ++++ 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index b0fab0894ae..ecf3228d318 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -98,7 +98,9 @@ Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakeP auto resolveInherits = [](auto &presetsHash, auto &presetsList) { Utils::sort(presetsList, [](const auto &left, const auto &right) { - if (!left.inherits || left.inherits.value().contains(right.name)) + const bool sameInheritance = left.inherits && right.inherits + && left.inherits.value() == right.inherits.value(); + if (!left.inherits || left.inherits.value().contains(right.name) || sameInheritance) return false; return true; }); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index a89ae82e1ff..dc752f0a9f9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -209,23 +209,11 @@ static CMakeConfig configurationFromPresetProbe( ? configurePreset.cacheVariables.value() : CMakeConfig(); - auto expandCacheValue = - [configurePreset, env, sourceDirectory, cache](const QString &key) -> QString { - QString result = cache.stringValueOf(key.toUtf8()); - CMakePresets::Macros::expand(configurePreset, env, sourceDirectory, result); - - // all usages involve file paths, so make sure they are cleaned up - const FilePaths paths = transform(result.split(";"), &FilePath::fromUserInput); - result = transform(paths, &FilePath::path).join(";"); - - return result; - }; - - const QString cmakeMakeProgram = expandCacheValue("CMAKE_MAKE_PROGRAM"); - const QString toolchainFile = expandCacheValue("CMAKE_TOOLCHAIN_FILE"); - const QString prefixPath = expandCacheValue("CMAKE_PREFIX_PATH"); - const QString findRootPath = expandCacheValue("CMAKE_FIND_ROOT_PATH"); - const QString qtHostPath = expandCacheValue("QT_HOST_PATH"); + const QString cmakeMakeProgram = cache.stringValueOf("CMAKE_MAKE_PROGRAM"); + const QString toolchainFile = cache.stringValueOf("CMAKE_TOOLCHAIN_FILE"); + const QString prefixPath = cache.stringValueOf("CMAKE_PREFIX_PATH"); + const QString findRootPath = cache.stringValueOf("CMAKE_FIND_ROOT_PATH"); + const QString qtHostPath = cache.stringValueOf("QT_HOST_PATH"); if (!cmakeMakeProgram.isEmpty()) { args.emplace_back( @@ -662,6 +650,8 @@ QList CMakeProjectImporter::examineDirectory(const FilePath &importPath, projectDirectory(), data->buildDirectory); + CMakePresets::Macros::updateCacheVariables(configurePreset, env, projectDirectory()); + const CMakeConfig cache = configurePreset.cacheVariables ? configurePreset.cacheVariables.value() : CMakeConfig(); @@ -710,10 +700,7 @@ QList CMakeProjectImporter::examineDirectory(const FilePath &importPath, data->cmakePresetDefaultConfigHash = CMakeConfigurationKitAspect::computeDefaultConfigHash(config, data->cmakeBinary); - QString cmakeBuildType = QString::fromUtf8(cache.valueOf("CMAKE_BUILD_TYPE")); - CMakePresets::Macros::expand(configurePreset, env, projectDirectory(), cmakeBuildType); - - QByteArrayList buildConfigurationTypes = {cmakeBuildType.toUtf8()}; + QByteArrayList buildConfigurationTypes = {cache.valueOf("CMAKE_BUILD_TYPE")}; if (buildConfigurationTypes.front().isEmpty()) { buildConfigurationTypes.clear(); QByteArray buildConfigurationTypesString = cache.valueOf("CMAKE_CONFIGURATION_TYPES"); diff --git a/src/plugins/cmakeprojectmanager/presetsmacros.cpp b/src/plugins/cmakeprojectmanager/presetsmacros.cpp index c1007b202f4..af5524216fb 100644 --- a/src/plugins/cmakeprojectmanager/presetsmacros.cpp +++ b/src/plugins/cmakeprojectmanager/presetsmacros.cpp @@ -4,6 +4,7 @@ #include "presetsmacros.h" #include "presetsparser.h" +#include #include #include #include @@ -304,6 +305,47 @@ void updateInstallDir(PresetsDetails::ConfigurePreset &configurePreset, } +void updateCacheVariables(PresetsDetails::ConfigurePreset &configurePreset, + const Utils::Environment &env, + const Utils::FilePath &sourceDirectory) +{ + using namespace Utils; + + if (!configurePreset.cacheVariables) + return; + + CMakeConfig cache = configurePreset.cacheVariables.value(); + + static const QSet pathKeys{"CMAKE_C_COMPILER", + "CMAKE_CXX_COMPILER", + "CMAKE_PREFIX_PATH", + "CMAKE_FIND_ROOT_PATH", + "CMAKE_MAKE_PROGRAM", + "CMAKE_TOOLCHAIN_FILE", + "QT_HOST_PATH", + "QT_QMAKE_EXECUTABLE", + "CMAKE_SYSROOT"}; + + auto expandCacheValue = + [configurePreset, env, sourceDirectory, cache](const QByteArray &key) { + QString result = cache.stringValueOf(key); + CMakePresets::Macros::expand(configurePreset, env, sourceDirectory, result); + + if (pathKeys.contains(key)) { + const FilePaths paths = transform(result.split(";"), &FilePath::fromUserInput); + result = transform(paths, &FilePath::path).join(";"); + } + + return result.toUtf8(); + }; + + for (auto &item : cache) + item.value = expandCacheValue(item.key); + + configurePreset.cacheVariables = cache; +} + + template void expandConditionValues(const PresetType &preset, const Utils::Environment &env, diff --git a/src/plugins/cmakeprojectmanager/presetsmacros.h b/src/plugins/cmakeprojectmanager/presetsmacros.h index 7d71514739a..49e47a71b1c 100644 --- a/src/plugins/cmakeprojectmanager/presetsmacros.h +++ b/src/plugins/cmakeprojectmanager/presetsmacros.h @@ -60,6 +60,14 @@ void updateToolchainFile(PresetsDetails::ConfigurePreset &configurePreset, void updateInstallDir(PresetsDetails::ConfigurePreset &configurePreset, const Utils::Environment &env, const Utils::FilePath &sourceDirectory); + +/** + * Updates the cacheVariables parameter of the configurePreset with the expanded prameter values. + * Including macro expansion and relative paths resolving. + */ +void updateCacheVariables(PresetsDetails::ConfigurePreset &configurePreset, + const Utils::Environment &env, + const Utils::FilePath &sourceDirectory); /** * Expands the condition values and then evaluates the condition object of the preset and returns * the boolean result. From bbe61a965d23ff627f476f3fda8613373c9a52b8 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 31 Mar 2023 21:14:38 +0200 Subject: [PATCH 09/12] CMakePM: sanitize preset initial configuration values The task-number below has a sample where CMAKE_C|XX_COMPILER was set to "cl.exe" and the CMAKE_PREFIX_PATH was set to "C:/Qt//6.5.0/ msvc2019_64". These values would cause "red" values in the CMake configuration, which is not that nice. This patchset will make sure that everything is nicely configured. Task-number: QTCREATORBUG-28982 Change-Id: I21289d1936ef075ce02364fc675709c52c76c3ed Reviewed-by: Alessandro Portale Reviewed-by: --- .../cmakebuildconfiguration.cpp | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index fb3a098e54f..9113c40700e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1255,6 +1255,12 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume const QString presetItemArg = presetItem.toArgument(); const QString presetItemArgNoType = presetItemArg.left(presetItemArg.indexOf(":")); + static QSet defaultKitMacroValues{"CMAKE_C_COMPILER", + "CMAKE_CXX_COMPILER", + "QT_QMAKE_EXECUTABLE", + "QT_HOST_PATH", + "CMAKE_PROJECT_INCLUDE_BEFORE"}; + auto it = std::find_if(initialArguments.begin(), initialArguments.end(), [presetItemArgNoType](const QString &arg) { @@ -1265,6 +1271,11 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume QString &arg = *it; CMakeConfigItem argItem = CMakeConfigItem::fromString(arg.mid(2)); // skip -D + // These values have Qt Creator macro names pointing to the Kit values + // which are preset expanded values used when the Kit was created + if (defaultKitMacroValues.contains(argItem.key) && argItem.value.startsWith("%{")) + continue; + // For multi value path variables append the non Qt path if (argItem.key == "CMAKE_PREFIX_PATH" || argItem.key == "CMAKE_FIND_ROOT_PATH") { QStringList presetValueList = presetItem.expandedValue(k).split(";"); @@ -1275,7 +1286,7 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume QStringList argItemPaths = argItemExpandedValue.split(";"); for (const QString &argPath : argItemPaths) { const FilePath argFilePath = FilePath::fromString(argPath); - const FilePath presetFilePath = FilePath::fromString(presetPath); + const FilePath presetFilePath = FilePath::fromUserInput(presetPath); if (argFilePath == presetFilePath) return true; @@ -1290,12 +1301,10 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume } arg = argItem.toArgument(); - } else if (argItem.key == "CMAKE_C_COMPILER" || argItem.key == "CMAKE_CXX_COMPILER" - || argItem.key == "QT_QMAKE_EXECUTABLE" || argItem.key == "QT_HOST_PATH" - || argItem.key == "CMAKE_PROJECT_INCLUDE_BEFORE" - || argItem.key == "CMAKE_TOOLCHAIN_FILE") { + } else if (argItem.key == "CMAKE_TOOLCHAIN_FILE") { const FilePath argFilePath = FilePath::fromString(argItem.expandedValue(k)); - const FilePath presetFilePath = FilePath::fromUtf8(presetItem.value); + const FilePath presetFilePath = FilePath::fromUserInput( + QString::fromUtf8(presetItem.value)); if (argFilePath != presetFilePath) arg = presetItem.toArgument(); From bb551f4b6065662a9c10835f6363a44a87f878fd Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 17 Apr 2023 06:36:31 +0200 Subject: [PATCH 10/12] Android: Fix compile with Qt6.2 Just removed redundant check. Amends 2d01003c4e37041efc63bd536d1cd06ce4928bf7. Change-Id: Ie7ce3836804199bcb561b8c34a70814856a4033a Reviewed-by: Alessandro Portale Reviewed-by: Zoltan Gera --- src/plugins/android/androidrunnerworker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 7567cc06183..2676fa6305c 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -122,7 +122,7 @@ static void findProcessPIDAndUser(QFutureInterface &fi, QStringList if (!out.isEmpty()) { QRegularExpressionMatch match; qsizetype matchPos = out.indexOf(userIdPattern, 0, &match); - if (matchPos >= 0 && match.hasCaptured(1) && match.capturedLength(1) > 0) { + if (matchPos >= 0 && match.capturedLength(1) > 0) { bool ok = false; processUser = match.captured(1).toInt(&ok); if (!ok) From 0c37fc356ede86e0e697ce3af5fb320cd7275019 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Mon, 17 Apr 2023 15:08:00 +0200 Subject: [PATCH 11/12] ClangFormat: Fix wrong indentation numbers with separator Fixes: QTCREATORBUG-29033 Change-Id: I70ba12828d3805cb8087a797d14e0ee24611418f Reviewed-by: Christian Kandeler --- src/plugins/clangformat/clangformatutils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index d1d6bee684b..ca6fea8f18e 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -177,6 +177,7 @@ clang::format::FormatStyle qtcStyle() style.Standard = FormatStyle::LS_Cpp11; style.TabWidth = 4; style.UseTab = FormatStyle::UT_Never; + style.Standard = FormatStyle::LS_Auto; return style; } From f2c6af064b73c25ca11816d054e7d1318068b391 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 18 Apr 2023 09:57:47 +0200 Subject: [PATCH 12/12] Update qbs submodule to HEAD of 2.0 branch Fixes build with Qt 6.5 Change-Id: I9aaae5ade6b9165e54c248d246d20dd0665967bf Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: Christian Kandeler --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 978448ddfe8..e002680feb4 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 978448ddfe8aac9c4cc895f6c93429e0f9f689bc +Subproject commit e002680feb415ee7d26e3a31d70afeef0d50dea2