CMakePM: Presets: Add ability to register a Debugger via "vendor" field

This adds "Debugger" as a dependency for the CMake Project Manager.

The "vendor" field of a configurePreset can look like:

```
      "vendor": {
        "qt.io/QtCreator/1.0": {
          "debugger": "C:/Qt/Tools/mingw1120_64/bin/gdb.exe"
          }
        }
      }
```

or with all the DebugItem details as:

```
      "vendor": {
        "qt.io/QtCreator/1.0": {
          "debugger": {
            "DisplayName": "GNU gdb 11.2.0 for MinGW 11.2.0 64-bit",
            "Abis": ["x86-windows-msys-pe-64bit"],
            "Binary": "C:/Qt/Tools/mingw1120_64/bin/gdb.exe",
            "EngineType": 1,
            "Version": "11.2.0"
          }
        }
      }
```

Fixes: QTCREATORBUG-30836
Change-Id: Ia89ff29ce5fad713ee8617477ec798bd86f2f811
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Cristian Adam
2024-05-29 16:37:14 +02:00
parent 73e8dfba44
commit 968051eb72
6 changed files with 90 additions and 31 deletions

View File

@@ -48,7 +48,6 @@ add_subdirectory(autotoolsprojectmanager)
add_subdirectory(bazaar)
add_subdirectory(beautifier)
add_subdirectory(clearcase)
add_subdirectory(cmakeprojectmanager)
add_subdirectory(cvs)
add_subdirectory(designer)
add_subdirectory(docker)
@@ -80,6 +79,7 @@ if (WITH_QMLDESIGNER)
endif()
add_subdirectory(python)
add_subdirectory(clangformat)
add_subdirectory(cmakeprojectmanager)
# Level 7:
add_subdirectory(android)

View File

@@ -1,7 +1,7 @@
add_qtc_plugin(CMakeProjectManager
PLUGIN_CLASS CMakeProjectPlugin
DEPENDS QmlJS
PLUGIN_DEPENDS Core CppEditor ProjectExplorer TextEditor QtSupport
PLUGIN_DEPENDS Core CppEditor Debugger ProjectExplorer TextEditor QtSupport
SYSTEM_INCLUDES 3dparty/cmake
SOURCES
builddirparameters.cpp builddirparameters.h

View File

@@ -12,6 +12,9 @@
#include "presetsmacros.h"
#include <coreplugin/messagemanager.h>
#include <debugger/debuggeritem.h>
#include <debugger/debuggeritemmanager.h>
#include <debugger/debuggerkitaspect.h>
#include <projectexplorer/buildinfo.h>
#include <projectexplorer/kitaspects.h>
@@ -30,7 +33,9 @@
#include <QApplication>
#include <QLoggingCategory>
#include <QUuid>
using namespace Debugger;
using namespace ProjectExplorer;
using namespace QtSupport;
using namespace Utils;
@@ -60,6 +65,7 @@ struct DirectoryData
FilePath sysroot;
QtProjectImporter::QtVersionData qt;
QVector<ToolchainDescription> toolchains;
QVariant debugger;
};
static FilePaths scanDirectory(const FilePath &path, const QString &prefix)
@@ -205,6 +211,48 @@ FilePaths CMakeProjectImporter::presetCandidates()
return candidates;
}
static QVariant findOrRegisterDebugger(
Environment &env, const std::optional<QVariantMap> &vendor, const QString &presetName)
{
const QString debuggerKey("debugger");
if (!vendor || !vendor.value().contains(debuggerKey))
return {};
const QVariant debuggerVariant = vendor.value().value(debuggerKey);
FilePath debuggerPath = FilePath::fromUserInput(debuggerVariant.toString());
if (!debuggerPath.isEmpty()) {
if (debuggerPath.isRelativePath())
debuggerPath = env.searchInPath(debuggerPath.fileName());
const QString mainName = Tr::tr("CMake Preset (%1) %2 Debugger");
DebuggerItem debugger;
debugger.setCommand(debuggerPath);
debugger.setUnexpandedDisplayName(
mainName.arg(presetName).arg(debuggerPath.completeBaseName()));
debugger.setAutoDetected(false);
QString errorMessage;
debugger.reinitializeFromFile(&errorMessage, &env);
if (!errorMessage.isEmpty())
qCWarning(cmInputLog()) << "Error reinitializing debugger" << debuggerPath.toString()
<< "Error:" << errorMessage;
return DebuggerItemManager::registerDebugger(debugger);
} else {
auto debuggerMap = debuggerVariant.toMap();
if (debuggerMap.isEmpty())
return {};
// Manually create an Id, otrhewise the Kit will not have a debugger set
if (!debuggerMap.contains("Id"))
debuggerMap.insert("Id", QUuid::createUuid().toString());
auto store = storeFromMap(debuggerMap);
DebuggerItem debugger(store);
return DebuggerItemManager::registerDebugger(debugger);
}
}
Target *CMakeProjectImporter::preferredTarget(const QList<Target *> &possibleTargets)
{
for (Kit *kit : m_project->oldPresetKits()) {
@@ -835,6 +883,8 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
data->hasQmlDebugging = CMakeBuildConfiguration::hasQmlDebugging(config);
data->debugger = findOrRegisterDebugger(env, configurePreset.vendor, configurePreset.name);
QByteArrayList buildConfigurationTypes = {cache.valueOf("CMAKE_BUILD_TYPE")};
if (buildConfigurationTypes.front().isEmpty()) {
buildConfigurationTypes.clear();
@@ -1055,6 +1105,9 @@ Kit *CMakeProjectImporter::createKit(void *directoryData) const
if (!data->cmakePreset.isEmpty())
ensureBuildDirectory(*data, k);
if (data->debugger.isValid())
DebuggerKitAspect::setDebugger(k, data->debugger);
qCInfo(cmInputLog) << "Temporary Kit created.";
});
}

View File

@@ -8,6 +8,7 @@ QtcPlugin {
Depends { name: "Core" }
Depends { name: "CppEditor" }
Depends { name: "Debugger" }
Depends { name: "QmlJS" }
Depends { name: "ProjectExplorer" }
Depends { name: "TextEditor" }

View File

@@ -148,6 +148,30 @@ std::optional<PresetsDetails::Condition> parseCondition(const QJsonValue &jsonVa
return condition;
}
bool parseVendor(const QJsonValue &jsonValue, std::optional<QVariantMap> &vendorSettings)
{
// The whole section is optional
if (jsonValue.isUndefined())
return true;
if (!jsonValue.isObject())
return false;
const QJsonObject object = jsonValue.toObject();
const QJsonValue qtIo = object.value("qt.io/QtCreator/1.0");
if (qtIo.isUndefined())
return true;
if (!qtIo.isObject())
return false;
const QJsonObject qtIoObject = qtIo.toObject();
vendorSettings = QVariantMap();
for (const QString &settingKey : qtIoObject.keys()) {
const QJsonValue settingValue = qtIoObject.value(settingKey);
vendorSettings->insert(settingKey, settingValue.toVariant());
}
return true;
}
bool parseConfigurePresets(const QJsonValue &jsonValue,
QList<PresetsDetails::ConfigurePreset> &configurePresets,
const Utils::FilePath &fileDir)
@@ -188,6 +212,9 @@ bool parseConfigurePresets(const QJsonValue &jsonValue,
if (object.contains("condition"))
preset.condition = parseCondition(object.value("condition"));
if (object.contains("vendor"))
parseVendor(object.value("vendor"), preset.vendor);
if (object.contains("displayName"))
preset.displayName = object.value("displayName").toString();
if (object.contains("description"))
@@ -378,6 +405,9 @@ bool parseBuildPresets(const QJsonValue &jsonValue,
if (object.contains("condition"))
preset.condition = parseCondition(object.value("condition"));
if (object.contains("vendor"))
parseVendor(object.value("vendor"), preset.vendor);
if (object.contains("displayName"))
preset.displayName = object.value("displayName").toString();
if (object.contains("description"))
@@ -435,30 +465,6 @@ bool parseBuildPresets(const QJsonValue &jsonValue,
return true;
}
bool parseVendor(const QJsonValue &jsonValue, std::optional<QVariantMap> &vendorSettings)
{
// The whole section is optional
if (jsonValue.isUndefined())
return true;
if (!jsonValue.isObject())
return false;
const QJsonObject object = jsonValue.toObject();
const QJsonValue qtIo = object.value("qt.io/QtCreator/1.0");
if (qtIo.isUndefined())
return true;
if (!qtIo.isObject())
return false;
const QJsonObject qtIoObject = qtIo.toObject();
vendorSettings = QVariantMap();
for (const QString &settingKey : qtIoObject.keys()) {
const QJsonValue settingValue = qtIoObject.value(settingKey);
vendorSettings->insert(settingKey, settingValue.toVariant());
}
return true;
}
const PresetsData &PresetsParser::presetsData() const
{
return m_presetsData;
@@ -535,10 +541,9 @@ bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage
return true;
}
static QHash<QString, QString> merge(const QHash<QString, QString> &first,
const QHash<QString, QString> &second)
static QVariantMap merge(const QVariantMap &first, const QVariantMap &second)
{
QHash<QString, QString> result = first;
QVariantMap result = first;
for (auto it = second.constKeyValueBegin(); it != second.constKeyValueEnd(); ++it) {
result[it->first] = it->second;
}

View File

@@ -94,7 +94,7 @@ public:
std::optional<bool> hidden = false;
std::optional<QStringList> inherits;
std::optional<Condition> condition;
std::optional<QHash<QString, QString>> vendor;
std::optional<QVariantMap> vendor;
std::optional<QString> displayName;
std::optional<QString> description;
std::optional<QString> generator;
@@ -120,7 +120,7 @@ public:
std::optional<bool> hidden = false;
std::optional<QStringList> inherits;
std::optional<Condition> condition;
std::optional<QHash<QString, QString>> vendor;
std::optional<QVariantMap> vendor;
std::optional<QString> displayName;
std::optional<QString> description;
std::optional<Utils::Environment> environment;