// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "cmakedapengine.h" #include "dapclient.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace Core; using namespace Utils; namespace Debugger::Internal { class LocalSocketDataProvider : public IDataProvider { public: LocalSocketDataProvider(const QString &socketName, QObject *parent = nullptr) : IDataProvider(parent) , m_socketName(socketName) { connect(&m_socket, &QLocalSocket::connected, this, &IDataProvider::started); connect(&m_socket, &QLocalSocket::disconnected, this, &IDataProvider::done); connect(&m_socket, &QLocalSocket::readyRead, this, &IDataProvider::readyReadStandardOutput); connect(&m_socket, &QLocalSocket::errorOccurred, this, &IDataProvider::readyReadStandardError); } ~LocalSocketDataProvider() { m_socket.disconnectFromServer(); } void start() override { m_socket.connectToServer(m_socketName, QIODevice::ReadWrite); } bool isRunning() const override { return m_socket.isOpen(); } void writeRaw(const QByteArray &data) override { if (m_socket.isOpen()) m_socket.write(data); } void kill() override { if (m_socket.isOpen()) m_socket.disconnectFromServer(); else { m_socket.abort(); emit done(); } } QByteArray readAllStandardOutput() override { return m_socket.readAll(); } QString readAllStandardError() override { return QString(); } int exitCode() const override { return 0; } QString executable() const override { return m_socket.serverName(); } QProcess::ExitStatus exitStatus() const override { return QProcess::NormalExit; } QProcess::ProcessError error() const override { return QProcess::UnknownError; } Utils::ProcessResult result() const override { return ProcessResult::FinishedWithSuccess; } QString exitMessage() const override { return QString(); }; private: QLocalSocket m_socket; const QString m_socketName; }; class CMakeDapClient : public DapClient { public: CMakeDapClient(IDataProvider *provider, QObject *parent = nullptr) : DapClient(provider, parent) {} void sendInitialize() override { postRequest("initialize", QJsonObject{{"clientID", "QtCreator"}, {"clientName", "QtCreator"}, {"adapterID", "cmake"}, {"pathFormat", "path"}}); } private: const QLoggingCategory &logCategory() override { static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.cmake", QtWarningMsg); return logCategory; } }; CMakeDapEngine::CMakeDapEngine() : DapEngine() { setObjectName("CmakeDapEngine"); setDebuggerName("CMake"); setDebuggerType("DAP"); } void CMakeDapEngine::setupEngine() { QTC_ASSERT(state() == EngineSetupRequested, qCDebug(logCategory()) << state()); qCDebug(logCategory()) << "build system name" << ProjectExplorer::activeBuildSystemForCurrentProject()->name(); IDataProvider *dataProvider; if (TemporaryDirectory::masterDirectoryFilePath().osType() == Utils::OsType::OsTypeWindows) { dataProvider = new LocalSocketDataProvider("\\\\.\\pipe\\cmake-dap", this); } else { dataProvider = new LocalSocketDataProvider(TemporaryDirectory::masterDirectoryPath() + "/cmake-dap.sock", this); } m_dapClient = new CMakeDapClient(dataProvider, this); connectDataGeneratorSignals(); connect(ProjectExplorer::activeBuildSystemForCurrentProject(), &ProjectExplorer::BuildSystem::debuggingStarted, this, [this] { m_dapClient->dataProvider()->start(); }); ProjectExplorer::activeBuildSystemForCurrentProject()->requestDebugging(); QTimer::singleShot(5000, this, [this] { if (!m_dapClient->dataProvider()->isRunning()) { m_dapClient->dataProvider()->kill(); MessageManager::writeDisrupting( "CMake server is not running. Please check that your CMake is 3.27 or higher."); return; } }); } bool CMakeDapEngine::acceptsBreakpoint(const BreakpointParameters &bp) const { const auto mimeType = Utils::mimeTypeForFile(bp.fileName); return mimeType.matchesName(Utils::Constants::CMAKE_MIMETYPE) || mimeType.matchesName(Utils::Constants::CMAKE_PROJECT_MIMETYPE); } bool CMakeDapEngine::hasCapability(unsigned cap) const { return cap & (ReloadModuleCapability | BreakConditionCapability | ShowModuleSymbolsCapability /*| AddWatcherCapability*/ // disable while the #25282 bug is not fixed | RunToLineCapability); } const QLoggingCategory &CMakeDapEngine::logCategory() { static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.cmake", QtWarningMsg); return logCategory; } } // namespace Debugger::Internal