From 07d4c290439282b83c84c5ebd7dcd0f108290ed3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 6 May 2014 18:48:10 +0200 Subject: [PATCH] RemoteLinux: Provide a custom run configuration. Like the existing "Custom Executable" run config, but for a remote Linux target. Task-number: QTCREATORBUG-12168 Change-Id: I0527c2f8080f0e3467fe7210968435fc401fbf76 Reviewed-by: Daniel Teske --- .../abstractremotelinuxrunconfiguration.cpp | 15 ++ .../abstractremotelinuxrunconfiguration.h | 2 + src/plugins/remotelinux/remotelinux.pro | 5 +- src/plugins/remotelinux/remotelinux.qbs | 3 + .../remotelinuxcustomrunconfiguration.cpp | 217 ++++++++++++++++++ .../remotelinuxcustomrunconfiguration.h | 82 +++++++ ...remotelinuxcustomrunconfigurationwidget.ui | 73 ++++++ .../remotelinuxrunconfiguration.cpp | 14 -- .../remotelinux/remotelinuxrunconfiguration.h | 2 - .../remotelinuxrunconfigurationfactory.cpp | 18 +- .../remotelinuxruncontrolfactory.cpp | 15 +- 11 files changed, 423 insertions(+), 23 deletions(-) create mode 100644 src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp create mode 100644 src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h create mode 100644 src/plugins/remotelinux/remotelinuxcustomrunconfigurationwidget.ui diff --git a/src/plugins/remotelinux/abstractremotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/abstractremotelinuxrunconfiguration.cpp index 5367360edfa..109f8659bc2 100644 --- a/src/plugins/remotelinux/abstractremotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxrunconfiguration.cpp @@ -28,6 +28,8 @@ ****************************************************************************/ #include "abstractremotelinuxrunconfiguration.h" +#include + namespace RemoteLinux { AbstractRemoteLinuxRunConfiguration::AbstractRemoteLinuxRunConfiguration(ProjectExplorer::Target *parent, @@ -47,4 +49,17 @@ AbstractRemoteLinuxRunConfiguration::AbstractRemoteLinuxRunConfiguration(Project } +int AbstractRemoteLinuxRunConfiguration::portsUsedByDebuggers() const +{ + int ports = 0; + Debugger::DebuggerRunConfigurationAspect *aspect + = extraAspect(); + if (aspect->useQmlDebugger()) + ++ports; + if (aspect->useCppDebugger()) + ++ports; + + return ports; +} + } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/abstractremotelinuxrunconfiguration.h b/src/plugins/remotelinux/abstractremotelinuxrunconfiguration.h index a9fdbeec51a..d5c75c2e0dc 100644 --- a/src/plugins/remotelinux/abstractremotelinuxrunconfiguration.h +++ b/src/plugins/remotelinux/abstractremotelinuxrunconfiguration.h @@ -55,6 +55,8 @@ public: virtual QString workingDirectory() const = 0; virtual Utils::Environment environment() const = 0; + int portsUsedByDebuggers() const; + protected: AbstractRemoteLinuxRunConfiguration(ProjectExplorer::Target *parent, AbstractRemoteLinuxRunConfiguration *source); diff --git a/src/plugins/remotelinux/remotelinux.pro b/src/plugins/remotelinux/remotelinux.pro index e511ac36b97..12a53819966 100644 --- a/src/plugins/remotelinux/remotelinux.pro +++ b/src/plugins/remotelinux/remotelinux.pro @@ -48,6 +48,7 @@ HEADERS += \ remotelinuxanalyzesupport.h \ abstractremotelinuxrunsupport.h \ linuxdeviceprocess.h \ + remotelinuxcustomrunconfiguration.h \ remotelinuxsignaloperation.h SOURCES += \ @@ -94,12 +95,14 @@ SOURCES += \ remotelinuxanalyzesupport.cpp \ abstractremotelinuxrunsupport.cpp \ linuxdeviceprocess.cpp \ + remotelinuxcustomrunconfiguration.cpp \ remotelinuxsignaloperation.cpp FORMS += \ genericlinuxdeviceconfigurationwizardsetuppage.ui \ genericlinuxdeviceconfigurationwidget.ui \ - remotelinuxcheckforfreediskspacestepwidget.ui + remotelinuxcheckforfreediskspacestepwidget.ui \ + remotelinuxcustomrunconfigurationwidget.ui RESOURCES += remotelinux.qrc diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index 3f661787f22..bf8bf94242f 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -73,6 +73,9 @@ QtcPlugin { "remotelinuxcustomcommanddeploymentstep.h", "remotelinuxcustomcommanddeployservice.cpp", "remotelinuxcustomcommanddeployservice.h", + "remotelinuxcustomrunconfiguration.cpp", + "remotelinuxcustomrunconfiguration.h", + "remotelinuxcustomrunconfigurationwidget.ui", "remotelinuxdebugsupport.cpp", "remotelinuxdebugsupport.h", "remotelinuxdeployconfiguration.cpp", diff --git a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp new file mode 100644 index 00000000000..e046be19861 --- /dev/null +++ b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "remotelinuxcustomrunconfiguration.h" + +#include "remotelinuxenvironmentaspect.h" +#include "ui_remotelinuxcustomrunconfigurationwidget.h" + +#include +#include +#include +#include + +namespace RemoteLinux { +namespace Internal { + +class RemoteLinuxCustomRunConfigWidget : public ProjectExplorer::RunConfigWidget +{ + Q_OBJECT +public: + RemoteLinuxCustomRunConfigWidget(RemoteLinuxCustomRunConfiguration *runConfig) + : m_runConfig(runConfig) + { + QVBoxLayout * const mainLayout = new QVBoxLayout(this); + mainLayout->setMargin(0); + auto * const detailsContainer = new Utils::DetailsWidget(this); + mainLayout->addWidget(detailsContainer); + detailsContainer->setState(Utils::DetailsWidget::NoSummary); + QWidget * const detailsWidget = new QWidget(this); + detailsContainer->setWidget(detailsWidget); + m_ui.setupUi(detailsWidget); + m_ui.localExecutablePathChooser->setExpectedKind(Utils::PathChooser::File); + m_ui.localExecutablePathChooser->setPath(m_runConfig->localExecutableFilePath()); + m_ui.remoteExeLineEdit->setText(m_runConfig->remoteExecutableFilePath()); + m_ui.argsLineEdit->setText(Utils::QtcProcess::joinArgs(m_runConfig->arguments(), + Utils::OsTypeLinux)); + m_ui.workingDirLineEdit->setText(m_runConfig->workingDirectory()); + connect(m_ui.localExecutablePathChooser, SIGNAL(pathChanged(QString)), + SLOT(handleLocalExecutableChanged(QString))); + connect(m_ui.remoteExeLineEdit, SIGNAL(textEdited(QString)), + SLOT(handleRemoteExecutableChanged(QString))); + connect(m_ui.argsLineEdit, SIGNAL(textEdited(QString)), + SLOT(handleArgumentsChanged(QString))); + connect(m_ui.workingDirLineEdit, SIGNAL(textEdited(QString)), + SLOT(handleWorkingDirChanged(QString))); + } + +private slots: + void handleLocalExecutableChanged(const QString &path) { + m_runConfig->setLocalExecutableFilePath(path.trimmed()); + } + + void handleRemoteExecutableChanged(const QString &path) { + m_runConfig->setRemoteExecutableFilePath(path.trimmed()); + emit displayNameChanged(displayName()); + } + + void handleArgumentsChanged(const QString &arguments) { + m_runConfig->setArguments(Utils::QtcProcess::splitArgs(arguments.trimmed(), + Utils::OsTypeLinux)); + } + + void handleWorkingDirChanged(const QString &wd) { + m_runConfig->setWorkingDirectory(wd.trimmed()); + } + +private: + QString displayName() const { return m_runConfig->displayName(); } + + RemoteLinuxCustomRunConfiguration * const m_runConfig; + Ui::RemoteLinuxCustomRunConfigurationWidget m_ui; +}; + +RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *parent) + : AbstractRemoteLinuxRunConfiguration(parent, runConfigId()) +{ + init(); +} + +RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *parent, + RemoteLinuxCustomRunConfiguration *source) + : AbstractRemoteLinuxRunConfiguration(parent, source) + , m_localExecutable(source->m_localExecutable) + , m_remoteExecutable(source->m_remoteExecutable) + , m_arguments(source->m_arguments) + , m_workingDirectory(source->m_workingDirectory) +{ + init(); +} + +bool RemoteLinuxCustomRunConfiguration::isConfigured() const +{ + return !m_remoteExecutable.isEmpty(); +} + +bool RemoteLinuxCustomRunConfiguration::ensureConfigured(QString *errorMessage) +{ + if (!isConfigured()) { + if (errorMessage) { + *errorMessage = tr("The remote executable must be set " + "in order to run a custom remote run configuration."); + } + return false; + } + return true; +} + +QWidget *RemoteLinuxCustomRunConfiguration::createConfigurationWidget() +{ + return new RemoteLinuxCustomRunConfigWidget(this); +} + +Utils::OutputFormatter *RemoteLinuxCustomRunConfiguration::createOutputFormatter() const +{ + return new QtSupport::QtOutputFormatter(target()->project()); +} + +Utils::Environment RemoteLinuxCustomRunConfiguration::environment() const +{ + RemoteLinuxEnvironmentAspect *aspect = extraAspect(); + QTC_ASSERT(aspect, return Utils::Environment()); + return aspect->environment(); +} + +void RemoteLinuxCustomRunConfiguration::setRemoteExecutableFilePath(const QString &executable) +{ + m_remoteExecutable = executable; + setDisplayName(tr("Run \"%1\" on Linux Device").arg(executable)); +} + +Core::Id RemoteLinuxCustomRunConfiguration::runConfigId() +{ + return "RemoteLinux.CustomRunConfig"; +} + +QString RemoteLinuxCustomRunConfiguration::runConfigDefaultDisplayName() +{ + return tr("Custom Executable (on Remote Generic Linux Host)"); +} + +void RemoteLinuxCustomRunConfiguration::init() +{ + setDefaultDisplayName(runConfigDefaultDisplayName()); + addExtraAspect(new RemoteLinuxEnvironmentAspect(this)); +} + +static QString localExeKey() +{ + return QLatin1String("RemoteLinux.CustomRunConfig.LocalExecutable"); +} + +static QString remoteExeKey() +{ + return QLatin1String("RemoteLinux.CustomRunConfig.RemoteExecutable"); +} + +static QString argsKey() +{ + return QLatin1String("RemoteLinux.CustomRunConfig.Arguments"); +} + +static QString workingDirKey() +{ + return QLatin1String("RemoteLinux.CustomRunConfig.WorkingDirectory"); +} + +bool RemoteLinuxCustomRunConfiguration::fromMap(const QVariantMap &map) +{ + if (!AbstractRemoteLinuxRunConfiguration::fromMap(map)) + return false; + setLocalExecutableFilePath(map.value(localExeKey()).toString()); + setRemoteExecutableFilePath(map.value(remoteExeKey()).toString()); + setArguments(map.value(argsKey()).toStringList()); + setWorkingDirectory(map.value(workingDirKey()).toString()); + return true; +} + +QVariantMap RemoteLinuxCustomRunConfiguration::toMap() const +{ + QVariantMap map = AbstractRemoteLinuxRunConfiguration::toMap(); + map.insert(localExeKey(), m_localExecutable); + map.insert(remoteExeKey(), m_remoteExecutable); + map.insert(argsKey(), m_arguments); + map.insert(workingDirKey(), m_workingDirectory); + return map; +} + +} // namespace Internal +} // namespace RemoteLinux + +#include "remotelinuxcustomrunconfiguration.moc" diff --git a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h new file mode 100644 index 00000000000..97867ad871d --- /dev/null +++ b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef REMOTELINUXCUSTOMRUNCONFIGURATION_H +#define REMOTELINUXCUSTOMRUNCONFIGURATION_H + +#include "abstractremotelinuxrunconfiguration.h" + +namespace RemoteLinux { +namespace Internal { + +class RemoteLinuxCustomRunConfiguration : public AbstractRemoteLinuxRunConfiguration +{ + Q_OBJECT +public: + RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *parent); + RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *parent, + RemoteLinuxCustomRunConfiguration *source); + + bool fromMap(const QVariantMap &map); + QVariantMap toMap() const; + + bool isEnabled() const { return true; } + bool isConfigured() const; + bool ensureConfigured(QString *errorMessage); + QWidget *createConfigurationWidget(); + Utils::OutputFormatter *createOutputFormatter() const; + + QString localExecutableFilePath() const { return m_localExecutable; } + QString remoteExecutableFilePath() const { return m_remoteExecutable; } + QStringList arguments() const { return m_arguments; } + QString workingDirectory() const { return m_workingDirectory; } + Utils::Environment environment() const; + + void setLocalExecutableFilePath(const QString &executable) { m_localExecutable = executable; } + void setRemoteExecutableFilePath(const QString &executable); + void setArguments(const QStringList &args) { m_arguments = args; } + void setWorkingDirectory(const QString &wd) { m_workingDirectory = wd; } + + static Core::Id runConfigId(); + static QString runConfigDefaultDisplayName(); + +private: + void init(); + + QString m_localExecutable; + QString m_remoteExecutable; + QStringList m_arguments; + QString m_workingDirectory; + +}; + +} // namespace Internal +} // namespace RemoteLinux + +#endif // Include guard. diff --git a/src/plugins/remotelinux/remotelinuxcustomrunconfigurationwidget.ui b/src/plugins/remotelinux/remotelinuxcustomrunconfigurationwidget.ui new file mode 100644 index 00000000000..273faaefe82 --- /dev/null +++ b/src/plugins/remotelinux/remotelinuxcustomrunconfigurationwidget.ui @@ -0,0 +1,73 @@ + + + RemoteLinux::Internal::RemoteLinuxCustomRunConfigurationWidget + + + + 0 + 0 + 445 + 120 + + + + Form + + + + + + Local Executable: + + + + + + + + + + Remote Executable: + + + + + + + + + + Arguments: + + + + + + + + + + Working Directory: + + + + + + + + + + + Utils::PathChooser + QWidget +
utils/pathchooser.h
+ 1 + + editingFinished() + browsingFinished() + +
+
+ + +
diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp index 0473f6e9dc9..dbdd2698478 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp @@ -32,7 +32,6 @@ #include "remotelinuxenvironmentaspect.h" #include "remotelinuxrunconfigurationwidget.h" -#include #include #include #include @@ -240,19 +239,6 @@ QString RemoteLinuxRunConfiguration::alternateRemoteExecutable() const return d->alternateRemoteExecutable; } -int RemoteLinuxRunConfiguration::portsUsedByDebuggers() const -{ - int ports = 0; - Debugger::DebuggerRunConfigurationAspect *aspect - = extraAspect(); - if (aspect->useQmlDebugger()) - ++ports; - if (aspect->useCppDebugger()) - ++ports; - - return ports; -} - void RemoteLinuxRunConfiguration::handleBuildSystemDataUpdated() { emit deploySpecsChanged(); diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.h b/src/plugins/remotelinux/remotelinuxrunconfiguration.h index 4f48dcccf81..0080d35f105 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.h +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.h @@ -83,8 +83,6 @@ public: QVariantMap toMap() const; - int portsUsedByDebuggers() const; - QString projectFilePath() const; static const char *IdPrefix; diff --git a/src/plugins/remotelinux/remotelinuxrunconfigurationfactory.cpp b/src/plugins/remotelinux/remotelinuxrunconfigurationfactory.cpp index db83d6b0b0b..37438dcc2ba 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfigurationfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfigurationfactory.cpp @@ -29,6 +29,7 @@ #include "remotelinuxrunconfigurationfactory.h" #include "remotelinux_constants.h" +#include "remotelinuxcustomrunconfiguration.h" #include "remotelinuxrunconfiguration.h" #include @@ -70,14 +71,17 @@ bool RemoteLinuxRunConfigurationFactory::canCreate(Target *parent, const Core::I { if (!canHandle(parent)) return false; - return !parent->applicationTargets().targetForProject(pathFromId(id)).isEmpty(); + return id == RemoteLinuxCustomRunConfiguration::runConfigId() + || !parent->applicationTargets().targetForProject(pathFromId(id)).isEmpty(); } bool RemoteLinuxRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const { if (!canHandle(parent)) return false; - return idFromMap(map).name().startsWith(RemoteLinuxRunConfiguration::IdPrefix); + const Core::Id id = idFromMap(map); + return id == RemoteLinuxCustomRunConfiguration::runConfigId() + || id.name().startsWith(RemoteLinuxRunConfiguration::IdPrefix); } bool RemoteLinuxRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const @@ -96,24 +100,30 @@ QList RemoteLinuxRunConfigurationFactory::availableCreationIds(Target const Core::Id base = Core::Id(RemoteLinuxRunConfiguration::IdPrefix); foreach (const BuildTargetInfo &bti, parent->applicationTargets().list) result << base.withSuffix(bti.projectFilePath.toString()); + result << RemoteLinuxCustomRunConfiguration::runConfigId(); return result; } QString RemoteLinuxRunConfigurationFactory::displayNameForId(const Core::Id id) const { + if (id == RemoteLinuxCustomRunConfiguration::runConfigId()) + return RemoteLinuxCustomRunConfiguration::runConfigDefaultDisplayName(); return QFileInfo(pathFromId(id)).completeBaseName() + QLatin1Char(' ') + tr("(on Remote Generic Linux Host)"); } RunConfiguration *RemoteLinuxRunConfigurationFactory::doCreate(Target *parent, const Core::Id id) { + if (id == RemoteLinuxCustomRunConfiguration::runConfigId()) + return new RemoteLinuxCustomRunConfiguration(parent); return new RemoteLinuxRunConfiguration(parent, id, pathFromId(id)); } RunConfiguration *RemoteLinuxRunConfigurationFactory::doRestore(Target *parent, const QVariantMap &map) { - Q_UNUSED(map); + if (idFromMap(map) == RemoteLinuxCustomRunConfiguration::runConfigId()) + return new RemoteLinuxCustomRunConfiguration(parent); return new RemoteLinuxRunConfiguration(parent, Core::Id(RemoteLinuxRunConfiguration::IdPrefix), QString()); } @@ -122,6 +132,8 @@ RunConfiguration *RemoteLinuxRunConfigurationFactory::clone(Target *parent, RunConfiguration *source) { QTC_ASSERT(canClone(parent, source), return 0); + if (RemoteLinuxCustomRunConfiguration *old = qobject_cast(source)) + return new RemoteLinuxCustomRunConfiguration(parent, old); RemoteLinuxRunConfiguration *old = static_cast(source); return new RemoteLinuxRunConfiguration(parent, old); } diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp index 7086c4b2297..83015194925 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp @@ -31,6 +31,7 @@ #include "remotelinuxanalyzesupport.h" #include "remotelinuxdebugsupport.h" +#include "remotelinuxcustomrunconfiguration.h" #include "remotelinuxrunconfiguration.h" #include "remotelinuxruncontrol.h" @@ -69,8 +70,10 @@ bool RemoteLinuxRunControlFactory::canRun(RunConfiguration *runConfiguration, Ru return false; } - const QByteArray idStr = runConfiguration->id().name(); - return runConfiguration->isEnabled() && idStr.startsWith(RemoteLinuxRunConfiguration::IdPrefix); + const Core::Id id = runConfiguration->id(); + return runConfiguration->isEnabled() + && (id == RemoteLinuxCustomRunConfiguration::runConfigId() + || id.name().startsWith(RemoteLinuxRunConfiguration::IdPrefix)); } RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, RunMode mode, @@ -78,7 +81,7 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Ru { QTC_ASSERT(canRun(runConfig, mode), return 0); - RemoteLinuxRunConfiguration *rc = qobject_cast(runConfig); + auto * const rc = qobject_cast(runConfig); QTC_ASSERT(rc, return 0); switch (mode) { case NormalRunMode: @@ -94,6 +97,12 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Ru *errorMessage = tr("Cannot debug: Not enough free ports available."); return 0; } + auto *crc = qobject_cast(rc); + if (crc && crc->localExecutableFilePath().isEmpty()) { + *errorMessage = tr("Cannot debug: Local executable is not set."); + return 0; + } + DebuggerStartParameters params = LinuxDeviceDebugSupport::startParameters(rc); if (mode == ProjectExplorer::DebugRunModeWithBreakOnMain) params.breakOnMain = true;