diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 69e8c74a10b..4579ccdc941 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -115,6 +115,7 @@ CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc) &CMakeBuildSystem::handleParsingSucceeded); connect(&m_reader, &FileApiReader::errorOccurred, this, &CMakeBuildSystem::handleParsingFailed); connect(&m_reader, &FileApiReader::dirty, this, &CMakeBuildSystem::becameDirty); + connect(&m_reader, &FileApiReader::debuggingStarted, this, &BuildSystem::debuggingStarted); wireUpConnections(); @@ -193,7 +194,15 @@ void CMakeBuildSystem::triggerParsing() qCDebug(cmakeBuildSystemLog) << "Asking reader to parse"; m_reader.parse(reparseParameters & REPARSE_FORCE_CMAKE_RUN, reparseParameters & REPARSE_FORCE_INITIAL_CONFIGURATION, - reparseParameters & REPARSE_FORCE_EXTRA_CONFIGURATION); + reparseParameters & REPARSE_FORCE_EXTRA_CONFIGURATION, + reparseParameters & REPARSE_DEBUG); +} + +void CMakeBuildSystem::requestDebugging() +{ + qCDebug(cmakeBuildSystemLog) << "Requesting parse due to \"Rescan Project\" command"; + reparse(REPARSE_FORCE_CMAKE_RUN | REPARSE_FORCE_EXTRA_CONFIGURATION | REPARSE_URGENT + | REPARSE_DEBUG); } bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 694840af26b..068fbc986e1 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -40,6 +40,7 @@ public: ~CMakeBuildSystem() final; void triggerParsing() final; + void requestDebugging() final; bool supportsAction(ProjectExplorer::Node *context, ProjectExplorer::ProjectAction action, @@ -143,6 +144,7 @@ private: = (1 << 1), // Force initial configuration arguments to cmake REPARSE_FORCE_EXTRA_CONFIGURATION = (1 << 2), // Force extra configuration arguments to cmake REPARSE_URGENT = (1 << 3), // Do not delay the parser run by 1s + REPARSE_DEBUG = (1 << 4), // Start with debugging }; void reparse(int reparseParameters); QString reparseParametersString(int reparseFlags); diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index b9eb017b94b..05dba3e8376 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -122,8 +122,9 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & m_process->setWorkingDirectory(buildDirectory); m_process->setEnvironment(parameters.environment); - m_process->setStdOutLineCallback([](const QString &s) { + m_process->setStdOutLineCallback([this](const QString &s) { BuildSystem::appendBuildSystemOutput(stripTrailingNewline(s)); + emit stdOutReady(s); }); m_process->setStdErrLineCallback([this](const QString &s) { @@ -139,19 +140,6 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & commandLine.addArgs({"-S", sourceDirectory.path(), "-B", buildDirectory.path()}); commandLine.addArgs(arguments); - if (qEnvironmentVariableIsSet("QTC_USE_CMAKE_DEBUGGER")) { - FilePath file = FilePath::fromString("/tmp/cmake-dap.sock"); - file.removeFile(); - commandLine.addArgs({"--debugger", "--debugger-pipe=/tmp/cmake-dap.sock"}); - connect(m_process.get(), &Process::started, this, [this, cmakeExecutable] { - QMetaObject::invokeMethod(debuggerPlugin(), - "attachToProcess", - Qt::QueuedConnection, - Q_ARG(qint64, m_process->processId()), - Q_ARG(const Utils::FilePath &, cmakeExecutable)); - }); - } - TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); BuildSystem::startNewBuildSystemOutput(::CMakeProjectManager::Tr::tr("Running %1 in %2.") diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.h b/src/plugins/cmakeprojectmanager/cmakeprocess.h index bb365d337cc..a49033c929b 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.h +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.h @@ -33,6 +33,7 @@ public: signals: void finished(int exitCode); + void stdOutReady(const QString &s); private: void handleProcessDone(const Utils::ProcessResultData &resultData); diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index f680cdc0a38..66995ba5d32 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -82,19 +82,26 @@ void FileApiReader::resetData() void FileApiReader::parse(bool forceCMakeRun, bool forceInitialConfiguration, - bool forceExtraConfiguration) + bool forceExtraConfiguration, + bool debugging) { qCDebug(cmakeFileApiMode) << "Parse called with arguments: ForceCMakeRun:" << forceCMakeRun << " - forceConfiguration:" << forceInitialConfiguration << " - forceExtraConfiguration:" << forceExtraConfiguration; startState(); - const QStringList args = (forceInitialConfiguration ? m_parameters.initialCMakeArguments + QStringList args = (forceInitialConfiguration ? m_parameters.initialCMakeArguments : QStringList()) + (forceExtraConfiguration ? (m_parameters.configurationChangesArguments + m_parameters.additionalCMakeArguments) : QStringList()); + if (debugging) { + FilePath file = FilePath::fromString("/tmp/cmake-dap.sock"); + file.removeFile(); + args << "--debugger" << "--debugger-pipe=/tmp/cmake-dap.sock"; + } + qCDebug(cmakeFileApiMode) << "Parameters request these CMake arguments:" << args; const FilePath replyFile = FileApiParser::scanForCMakeReplyFile(m_parameters.buildDirectory); @@ -339,6 +346,10 @@ void FileApiReader::startCMakeState(const QStringList &configurationArguments) m_cmakeProcess = std::make_unique(); connect(m_cmakeProcess.get(), &CMakeProcess::finished, this, &FileApiReader::cmakeFinishedState); + connect(m_cmakeProcess.get(), &CMakeProcess::stdOutReady, this, [this](const QString &data) { + if (data.endsWith("Waiting for debugger client to connect...\n")) + emit debuggingStarted(); + }); qCDebug(cmakeFileApiMode) << ">>>>>> Running cmake with arguments:" << configurationArguments; // Reset watcher: diff --git a/src/plugins/cmakeprojectmanager/fileapireader.h b/src/plugins/cmakeprojectmanager/fileapireader.h index 115d22ea71a..b013770982d 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.h +++ b/src/plugins/cmakeprojectmanager/fileapireader.h @@ -38,7 +38,10 @@ public: void setParameters(const BuildDirParameters &p); void resetData(); - void parse(bool forceCMakeRun, bool forceInitialConfiguration, bool forceExtraConfiguration); + void parse(bool forceCMakeRun, + bool forceInitialConfiguration, + bool forceExtraConfiguration, + bool debugging); void stop(); void stopCMakeRun(); @@ -64,6 +67,7 @@ signals: void dataAvailable(bool restoredFromBackup) const; void dirty() const; void errorOccurred(const QString &message) const; + void debuggingStarted() const; private: void startState(); diff --git a/src/plugins/debugger/dap/dapengine.cpp b/src/plugins/debugger/dap/dapengine.cpp index 3cddfa9dc81..16a314db000 100644 --- a/src/plugins/debugger/dap/dapengine.cpp +++ b/src/plugins/debugger/dap/dapengine.cpp @@ -7,8 +7,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -20,6 +23,8 @@ #include #include +#include + #include #include #include @@ -31,6 +36,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -45,7 +54,7 @@ using namespace Core; using namespace Utils; -static Q_LOGGING_CATEGORY(dapEngineLog, "qtc.dbg.dapengin", QtWarningMsg) +static Q_LOGGING_CATEGORY(dapEngineLog, "qtc.dbg.dapengine", QtWarningMsg) namespace Debugger::Internal { @@ -221,21 +230,47 @@ void DapEngine::setupEngine() { QTC_ASSERT(state() == EngineSetupRequested, qCDebug(dapEngineLog) << state()); - if (qEnvironmentVariableIsSet("QTC_USE_CMAKE_DEBUGGER")) { + const auto connectDataGeneratorSignals = [this] { + if (!m_dataGenerator) + return; + + connect(m_dataGenerator.get(), &IDataProvider::started, this, &DapEngine::handleDapStarted); + connect(m_dataGenerator.get(), &IDataProvider::done, this, &DapEngine::handleDapDone); + connect(m_dataGenerator.get(), + &IDataProvider::readyReadStandardOutput, + this, + &DapEngine::readDapStandardOutput); + connect(m_dataGenerator.get(), + &IDataProvider::readyReadStandardError, + this, + &DapEngine::readDapStandardError); + }; + + Perspective *currentPerspective = DebuggerMainWindow::instance()->currentPerspective(); + if (currentPerspective->parentPerspectiveId() == Constants::CMAKE_PERSPECTIVE_ID) { + qCDebug(dapEngineLog) << "build system name" << ProjectExplorer::ProjectTree::currentBuildSystem()->name(); + + m_nextBreakpointId = 0; m_dataGenerator = std::make_unique("/tmp/cmake-dap.sock"); + connectDataGeneratorSignals(); + + connect(ProjectExplorer::ProjectTree::currentBuildSystem(), + &ProjectExplorer::BuildSystem::debuggingStarted, + this, + [this] { + m_dataGenerator->start(); + }); + + ProjectExplorer::ProjectTree::currentBuildSystem()->requestDebugging(); } else { const DebuggerRunParameters &rp = runParameters(); const CommandLine cmd{rp.debugger.command.executable(), {"-i", "dap"}}; + m_dataGenerator = std::make_unique(rp, cmd); + connectDataGeneratorSignals(); + m_dataGenerator->start(); + } - - connect(m_dataGenerator.get(), &IDataProvider::started, this, &DapEngine::handleDapStarted); - connect(m_dataGenerator.get(), &IDataProvider::done, this, &DapEngine::handleDapDone); - connect(m_dataGenerator.get(), &IDataProvider::readyReadStandardOutput, this, &DapEngine::readDapStandardOutput); - connect(m_dataGenerator.get(), &IDataProvider::readyReadStandardError, this, &DapEngine::readDapStandardError); - - m_dataGenerator->start(); - notifyEngineSetupOk(); } @@ -325,13 +360,13 @@ void DapEngine::dapStackTrace() }); } -void DapEngine::dapScopes() +void DapEngine::dapScopes(int frameId) { postDirectCommand({ {"command", "scopes"}, {"type", "request"}, {"arguments", QJsonObject{ - {"frameId", 0} + {"frameId", frameId} }} }); } @@ -791,7 +826,7 @@ void DapEngine::handleOutput(const QJsonDocument &data) gotoLocation(Location(file, line)); refreshStack(stackFrames); - dapScopes(); + dapScopes(stackFrame.value("id").toInt()); return; } @@ -802,8 +837,8 @@ void DapEngine::handleOutput(const QJsonDocument &data) const QString name = scope.toObject().value("name").toString(); const int variablesReference = scope.toObject().value("variablesReference").toInt(); qCDebug(dapEngineLog) << "scoped success" << name << variablesReference; - if (name == "Locals") - dapVariables(variablesReference); +// if (name == "Locals") +// dapVariables(variablesReference); } } } @@ -851,15 +886,6 @@ void DapEngine::handleOutput(const QJsonDocument &data) const QJsonObject body = ob.value("body").toObject(); if (event == "exited") { - postDirectCommand({ - {"command", "disconnect"}, - {"type", "request"}, - {"arguments", QJsonObject{ - {"restart", false}, - {"terminateDebuggee", true} - }} - }); - notifyInferiorExited(); showMessage("exited", LogDebug); return; diff --git a/src/plugins/debugger/dap/dapengine.h b/src/plugins/debugger/dap/dapengine.h index 7402385943d..16181b96669 100644 --- a/src/plugins/debugger/dap/dapengine.h +++ b/src/plugins/debugger/dap/dapengine.h @@ -4,6 +4,7 @@ #pragma once #include + #include #include @@ -108,7 +109,7 @@ private: void handleDapConfigurationDone(); void dapStackTrace(); - void dapScopes(); + void dapScopes(int frameId); void threads(); void dapVariables(int variablesReference); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 729f8082c06..e7f8b47848d 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -541,13 +541,15 @@ void DebuggerEnginePrivate::setupViews() QTC_CHECK(!m_perspective); + Perspective *currentPerspective = DebuggerMainWindow::instance()->currentPerspective(); + const QString perspectiveId = "Debugger.Perspective." + m_runId + '.' + m_debuggerName; const QString settingsId = "Debugger.Perspective." + m_debuggerName; + const QString parentPerspectiveId = currentPerspective ? currentPerspective->id() + : Constants::PRESET_PERSPECTIVE_ID; - m_perspective = new Perspective(perspectiveId, - m_engine->displayName(), - Debugger::Constants::PRESET_PERSPECTIVE_ID, - settingsId); + m_perspective + = new Perspective(perspectiveId, m_engine->displayName(), parentPerspectiveId, settingsId); m_progress.setProgressRange(0, 1000); FutureProgress *fp = ProgressManager::addTask(m_progress.future(), @@ -724,7 +726,8 @@ void DebuggerEnginePrivate::setupViews() m_breakWindow->setObjectName("Debugger.Dock.Break." + engineId); m_breakWindow->setWindowTitle(Tr::tr("&Breakpoints")); - m_perspective->useSubPerspectiveSwitcher(EngineManager::engineChooser()); + if (!currentPerspective || currentPerspective->id() == Constants::PRESET_PERSPECTIVE_ID) + m_perspective->useSubPerspectiveSwitcher(EngineManager::engineChooser()); m_perspective->addToolBarAction(&m_continueAction); m_perspective->addToolBarAction(&m_interruptAction); diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h index bb3e5181ee2..024e2cd3e2a 100644 --- a/src/plugins/debugger/debuggerinternalconstants.h +++ b/src/plugins/debugger/debuggerinternalconstants.h @@ -41,6 +41,7 @@ const char C_QMLDEBUGGER[] = "Qml/JavaScript Debugger"; const char C_DEBUGGER_NOTRUNNING[] = "Debugger.NotRunning"; const char PRESET_PERSPECTIVE_ID[] = "Debugger.Perspective.Preset"; +const char CMAKE_PERSPECTIVE_ID[] = "Debugger.Perspective.Cmake"; const char TASK_CATEGORY_DEBUGGER_RUNTIME[] = "DebugRuntime"; diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 2a5ec866edb..fbe3c8079ab 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -785,6 +785,11 @@ QString Perspective::id() const return d->m_id; } +QString Perspective::parentPerspectiveId() const +{ + return d->m_parentPerspectiveId; +} + QString Perspective::name() const { return d->m_name; diff --git a/src/plugins/debugger/debuggermainwindow.h b/src/plugins/debugger/debuggermainwindow.h index 051704d4d9d..fbe959f19fd 100644 --- a/src/plugins/debugger/debuggermainwindow.h +++ b/src/plugins/debugger/debuggermainwindow.h @@ -76,6 +76,7 @@ public: void setShouldPersistChecker(const ShouldPersistChecker &checker); QString id() const; // Currently used by GammaRay plugin. + QString parentPerspectiveId() const; QString name() const; QWidget *centralWidget() const; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 152f928fb1e..b2d9e46595b 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -660,6 +661,7 @@ public: ProxyAction m_hiddenStopAction; QAction m_undisturbableAction; OptionalAction m_startAction; + OptionalAction m_startCmakeAction; QAction m_debugWithoutDeployAction{Tr::tr("Start Debugging Without Deployment")}; QAction m_startAndDebugApplicationAction{Tr::tr("Start and Debug External Application...")}; QAction m_attachToRunningApplication{Tr::tr("Attach to Running Application...")}; @@ -692,6 +694,7 @@ public: IContext m_debugModeContext; Perspective m_perspective{Constants::PRESET_PERSPECTIVE_ID, Tr::tr("Debugger")}; + std::unique_ptr m_perspectiveCmake; DebuggerKitAspect debuggerKitAspect; CommonOptionsPage commonOptionsPage; @@ -838,6 +841,11 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false); }); + connect(&m_startCmakeAction, &QAction::triggered, this, [] { +// ProjectTree::currentBuildSystem()->requestDebugging(); + ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::CMAKE_DEBUG_RUN_MODE, true); + }); + connect(&m_debugWithoutDeployAction, &QAction::triggered, this, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, true); }); @@ -1182,6 +1190,28 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) m_perspective.addWindow(breakpointManagerWindow, Perspective::SplitHorizontal, engineManagerWindow); m_perspective.addWindow(globalLogWindow, Perspective::AddToTab, nullptr, false, Qt::TopDockWidgetArea); + if (qEnvironmentVariableIsSet("QTC_USE_CMAKE_DEBUGGER")) { + m_perspectiveCmake = std::make_unique(Constants::CMAKE_PERSPECTIVE_ID, + Tr::tr("CMake")); + m_startCmakeAction.setText(Tr::tr("Start CMake Debugging")); + m_startCmakeAction.setEnabled(true); + m_startCmakeAction.setIcon(startIcon(true)); + m_startCmakeAction.setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_startCmakeAction.setVisible(true); + + m_perspectiveCmake->addToolBarAction(&m_startCmakeAction); + + m_perspectiveCmake->addWindow(engineManagerWindow, Perspective::SplitVertical, nullptr); + m_perspectiveCmake->addWindow(breakpointManagerWindow, + Perspective::SplitHorizontal, + engineManagerWindow); + m_perspectiveCmake->addWindow(globalLogWindow, + Perspective::AddToTab, + nullptr, + false, + Qt::TopDockWidgetArea); + } + setInitialState(); connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 85ad01d76df..67cefc7b27d 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -1136,6 +1136,7 @@ DebuggerRunWorkerFactory::DebuggerRunWorkerFactory() { setProduct(); addSupportedRunMode(ProjectExplorer::Constants::DEBUG_RUN_MODE); + addSupportedRunMode(ProjectExplorer::Constants::CMAKE_DEBUG_RUN_MODE); addSupportedDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); addSupportedDeviceType("DockerDeviceType"); } diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h index 1cd1e41a060..55de9b30ac8 100644 --- a/src/plugins/projectexplorer/buildsystem.h +++ b/src/plugins/projectexplorer/buildsystem.h @@ -66,6 +66,7 @@ public: Utils::Environment activeParseEnvironment() const; + virtual void requestDebugging() {} virtual bool addFiles(Node *context, const Utils::FilePaths &filePaths, Utils::FilePaths *notAdded = nullptr); @@ -153,6 +154,7 @@ signals: void parsingFinished(bool success); void deploymentDataChanged(); void testInformationUpdated(); + void debuggingStarted(); protected: // Helper methods to manage parsing state and signalling diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 9b9ae3886ab..bcfc8197ebd 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2932,10 +2932,15 @@ void ProjectExplorerPlugin::runRunConfiguration(RunConfiguration *rc, dd->m_delayedRunConfiguration = rc; dd->m_shouldHaveRunConfiguration = true; }; - const BuildForRunConfigStatus buildStatus = forceSkipDeploy + + BuildForRunConfigStatus buildStatus = forceSkipDeploy ? BuildManager::isBuilding(rc->project()) ? BuildForRunConfigStatus::Building : BuildForRunConfigStatus::NotBuilding : BuildManager::potentiallyBuildForRunConfig(rc); + + if (dd->m_runMode != Constants::CMAKE_DEBUG_RUN_MODE) + buildStatus = BuildForRunConfigStatus::NotBuilding; + switch (buildStatus) { case BuildForRunConfigStatus::BuildFailed: return; diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 50bacef3a41..27bd5936cc2 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -178,6 +178,7 @@ const char GENERATOR_ID_PREFIX[] = "PE.Wizard.Generator."; const char NO_RUN_MODE[]="RunConfiguration.NoRunMode"; const char NORMAL_RUN_MODE[]="RunConfiguration.NormalRunMode"; const char DEBUG_RUN_MODE[]="RunConfiguration.DebugRunMode"; +const char CMAKE_DEBUG_RUN_MODE[]="RunConfiguration.CmakeDebugRunMode"; const char QML_PROFILER_RUN_MODE[]="RunConfiguration.QmlProfilerRunMode"; const char QML_PROFILER_RUNNER[]="RunConfiguration.QmlProfilerRunner"; const char QML_PREVIEW_RUN_MODE[]="RunConfiguration.QmlPreviewRunMode";