2013-04-25 16:02:17 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2013-04-25 16:02:17 +02:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2013-04-25 16:02:17 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2013-04-25 16:02:17 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "iosbuildstep.h"
|
|
|
|
|
#include "iosconfigurations.h"
|
|
|
|
|
#include "iosdevice.h"
|
|
|
|
|
#include "iosrunconfiguration.h"
|
|
|
|
|
#include "iosrunner.h"
|
|
|
|
|
#include "iossimulator.h"
|
2014-03-28 19:05:35 +01:00
|
|
|
#include "iosconstants.h"
|
2013-04-25 16:02:17 +02:00
|
|
|
|
2017-05-19 16:59:02 +02:00
|
|
|
#include <debugger/debuggerplugin.h>
|
|
|
|
|
#include <debugger/debuggerkitinformation.h>
|
|
|
|
|
#include <debugger/debuggerruncontrol.h>
|
|
|
|
|
|
2013-04-25 16:02:17 +02:00
|
|
|
#include <projectexplorer/kitinformation.h>
|
2017-05-19 16:59:02 +02:00
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
2018-05-07 12:20:04 +02:00
|
|
|
#include <projectexplorer/runconfigurationaspects.h>
|
2013-04-25 16:02:17 +02:00
|
|
|
#include <projectexplorer/target.h>
|
2013-11-04 22:45:52 +01:00
|
|
|
#include <projectexplorer/taskhub.h>
|
2017-05-19 16:59:02 +02:00
|
|
|
#include <projectexplorer/toolchain.h>
|
|
|
|
|
|
2015-08-10 17:43:58 +02:00
|
|
|
#include <qmldebug/qmldebugcommandlinearguments.h>
|
2013-04-25 16:02:17 +02:00
|
|
|
|
2017-05-19 16:59:02 +02:00
|
|
|
#include <utils/fileutils.h>
|
|
|
|
|
#include <utils/qtcprocess.h>
|
2017-11-14 14:06:44 +01:00
|
|
|
#include <utils/url.h>
|
2017-05-19 16:59:02 +02:00
|
|
|
#include <utils/utilsicons.h>
|
|
|
|
|
|
|
|
|
|
#include <QDateTime>
|
2013-04-25 16:02:17 +02:00
|
|
|
#include <QDir>
|
|
|
|
|
#include <QMessageBox>
|
2014-02-25 22:48:19 +01:00
|
|
|
#include <QRegExp>
|
2017-05-19 16:59:02 +02:00
|
|
|
#include <QSettings>
|
|
|
|
|
#include <QTcpServer>
|
|
|
|
|
#include <QTime>
|
2013-04-25 16:02:17 +02:00
|
|
|
|
2017-05-19 16:59:02 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <io.h>
|
|
|
|
|
#endif
|
2013-10-28 08:16:05 +01:00
|
|
|
#include <signal.h>
|
|
|
|
|
|
2017-05-19 16:59:02 +02:00
|
|
|
using namespace Debugger;
|
2013-11-04 22:45:52 +01:00
|
|
|
using namespace ProjectExplorer;
|
2017-05-19 16:59:02 +02:00
|
|
|
using namespace Utils;
|
2013-11-04 22:45:52 +01:00
|
|
|
|
2013-04-25 16:02:17 +02:00
|
|
|
namespace Ios {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2017-07-14 10:12:37 +02:00
|
|
|
static void stopRunningRunControl(RunControl *runControl)
|
|
|
|
|
{
|
|
|
|
|
static QMap<Core::Id, QPointer<RunControl>> activeRunControls;
|
|
|
|
|
|
Avoid some visible uses of RunControl::runConfiguration()
For a long time, probably from the very beginning, a RunControl
was meant to hold (a copy of) data needed for its operation, that was
valid at the time of its construction, to be resilient in cases
where RunConfiguration setting were changed while the RunControl
was running, or to properly re-run with the original settings.
Unfortunately, the task was repetitive, as RunConfiguration
classes had no generic access to properties / "aspects"
and there was was the runConfiguration() accessor (probably
for mostly unrelated reasons in the output pane handling) which
made the idea of just casting that to the original runConfiguration
and access the data directly there appealing, with all the
expected consequences.
This patch here partially addresses the issue by copying some
more of the related data at RunControl construction time and
adjust the using code, avoiding most uses of the runConfiguration()
accessor in a mostly mechanical matter.
Complete removal appears possible, but will be less mechanical
in "difficult" plugins like ios, so this is left for later.
The new accessors in RunControl are very much ad-hoc, leaving
room for improvement, e.g. by consolidating the access to the
run config settings aspects with the other runconfig aspects
or similar. For now the goal is to remove the runConfiguration()
accessor, and to as much as possible fixed data after RunControl
setup is finished.
Next step would be to officially allow construction of RunControls
without a specific RunConfiguration by setting the necessary
data independently, removing the need for the various workarounds
that are currently used for the purpose of faking (parts of) the
effect of the non-existing RunConfiguration or refusing to operate
at all, even if it would be possible.
Change-Id: If8e5596da8422c70e90f97270389adbe6d0b46f2
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
2019-03-11 15:42:43 +01:00
|
|
|
Target *target = runControl->target();
|
2019-02-06 12:50:51 +01:00
|
|
|
Core::Id devId = DeviceKitAspect::deviceId(target->kit());
|
2017-07-14 10:12:37 +02:00
|
|
|
|
|
|
|
|
// The device can only run an application at a time, if an app is running stop it.
|
|
|
|
|
if (activeRunControls.contains(devId)) {
|
|
|
|
|
if (QPointer<RunControl> activeRunControl = activeRunControls[devId])
|
|
|
|
|
activeRunControl->initiateStop();
|
|
|
|
|
activeRunControls.remove(devId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (devId.isValid())
|
|
|
|
|
activeRunControls[devId] = runControl;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-19 16:59:02 +02:00
|
|
|
IosRunner::IosRunner(RunControl *runControl)
|
|
|
|
|
: RunWorker(runControl)
|
2013-04-25 16:02:17 +02:00
|
|
|
{
|
2019-08-30 14:22:01 +02:00
|
|
|
setId("IosRunner");
|
2017-07-14 10:12:37 +02:00
|
|
|
stopRunningRunControl(runControl);
|
2017-03-28 18:51:29 +02:00
|
|
|
auto runConfig = qobject_cast<IosRunConfiguration *>(runControl->runConfiguration());
|
|
|
|
|
m_bundleDir = runConfig->bundleDirectory().toString();
|
Avoid some visible uses of RunControl::runConfiguration()
For a long time, probably from the very beginning, a RunControl
was meant to hold (a copy of) data needed for its operation, that was
valid at the time of its construction, to be resilient in cases
where RunConfiguration setting were changed while the RunControl
was running, or to properly re-run with the original settings.
Unfortunately, the task was repetitive, as RunConfiguration
classes had no generic access to properties / "aspects"
and there was was the runConfiguration() accessor (probably
for mostly unrelated reasons in the output pane handling) which
made the idea of just casting that to the original runConfiguration
and access the data directly there appealing, with all the
expected consequences.
This patch here partially addresses the issue by copying some
more of the related data at RunControl construction time and
adjust the using code, avoiding most uses of the runConfiguration()
accessor in a mostly mechanical matter.
Complete removal appears possible, but will be less mechanical
in "difficult" plugins like ios, so this is left for later.
The new accessors in RunControl are very much ad-hoc, leaving
room for improvement, e.g. by consolidating the access to the
run config settings aspects with the other runconfig aspects
or similar. For now the goal is to remove the runConfiguration()
accessor, and to as much as possible fixed data after RunControl
setup is finished.
Next step would be to officially allow construction of RunControls
without a specific RunConfiguration by setting the necessary
data independently, removing the need for the various workarounds
that are currently used for the purpose of faking (parts of) the
effect of the non-existing RunConfiguration or refusing to operate
at all, even if it would be possible.
Change-Id: If8e5596da8422c70e90f97270389adbe6d0b46f2
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
2019-03-11 15:42:43 +01:00
|
|
|
m_arguments = runControl->aspect<ArgumentsAspect>()->arguments(runConfig->macroExpander());
|
|
|
|
|
m_device = DeviceKitAspect::device(runControl->target()->kit());
|
2014-03-28 19:05:35 +01:00
|
|
|
m_deviceType = runConfig->deviceType();
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IosRunner::~IosRunner()
|
|
|
|
|
{
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-19 16:59:02 +02:00
|
|
|
void IosRunner::setCppDebugging(bool cppDebug)
|
|
|
|
|
{
|
|
|
|
|
m_cppDebug = cppDebug;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunner::setQmlDebugging(QmlDebug::QmlDebugServicesPreset qmlDebugServices)
|
|
|
|
|
{
|
|
|
|
|
m_qmlDebugServices = qmlDebugServices;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-25 16:02:17 +02:00
|
|
|
QString IosRunner::bundlePath()
|
|
|
|
|
{
|
|
|
|
|
return m_bundleDir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString IosRunner::deviceId()
|
|
|
|
|
{
|
|
|
|
|
IosDevice::ConstPtr dev = m_device.dynamicCast<const IosDevice>();
|
|
|
|
|
if (!dev)
|
|
|
|
|
return QString();
|
|
|
|
|
return dev->uniqueDeviceID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IosToolHandler::RunKind IosRunner::runType()
|
|
|
|
|
{
|
2014-02-25 22:48:19 +01:00
|
|
|
if (m_cppDebug)
|
2013-04-25 16:02:17 +02:00
|
|
|
return IosToolHandler::DebugRun;
|
|
|
|
|
return IosToolHandler::NormalRun;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-25 22:48:19 +01:00
|
|
|
bool IosRunner::cppDebug() const
|
|
|
|
|
{
|
|
|
|
|
return m_cppDebug;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-26 14:15:44 +02:00
|
|
|
bool IosRunner::qmlDebug() const
|
|
|
|
|
{
|
|
|
|
|
return m_qmlDebugServices != QmlDebug::NoQmlDebugServices;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-10 17:43:58 +02:00
|
|
|
QmlDebug::QmlDebugServicesPreset IosRunner::qmlDebugServices() const
|
2014-02-25 22:48:19 +01:00
|
|
|
{
|
2015-08-10 17:43:58 +02:00
|
|
|
return m_qmlDebugServices;
|
2014-02-25 22:48:19 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-25 16:02:17 +02:00
|
|
|
void IosRunner::start()
|
|
|
|
|
{
|
2017-05-19 16:59:02 +02:00
|
|
|
if (m_toolHandler && isAppRunning())
|
2013-04-25 16:02:17 +02:00
|
|
|
m_toolHandler->stop();
|
2017-05-19 16:59:02 +02:00
|
|
|
|
2013-04-25 16:02:17 +02:00
|
|
|
m_cleanExit = false;
|
2017-05-19 16:59:02 +02:00
|
|
|
m_qmlServerPort = Port();
|
2014-10-24 10:28:28 +02:00
|
|
|
if (!QFileInfo::exists(m_bundleDir)) {
|
2014-03-11 11:15:37 +01:00
|
|
|
TaskHub::addTask(Task::Warning,
|
|
|
|
|
tr("Could not find %1.").arg(m_bundleDir),
|
|
|
|
|
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
|
2017-05-19 16:59:02 +02:00
|
|
|
reportFailure();
|
2014-03-11 11:15:37 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2014-02-25 22:48:19 +01:00
|
|
|
if (m_device->type() == Ios::Constants::IOS_DEVICE_TYPE) {
|
|
|
|
|
IosDevice::ConstPtr iosDevice = m_device.dynamicCast<const IosDevice>();
|
|
|
|
|
if (m_device.isNull()) {
|
2017-05-19 16:59:02 +02:00
|
|
|
reportFailure();
|
2014-02-25 22:48:19 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2015-08-10 17:43:58 +02:00
|
|
|
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices)
|
2017-05-19 16:59:02 +02:00
|
|
|
m_qmlServerPort = iosDevice->nextPort();
|
2014-02-25 22:48:19 +01:00
|
|
|
} else {
|
2013-04-25 16:02:17 +02:00
|
|
|
IosSimulator::ConstPtr sim = m_device.dynamicCast<const IosSimulator>();
|
|
|
|
|
if (sim.isNull()) {
|
2017-05-19 16:59:02 +02:00
|
|
|
reportFailure();
|
2013-04-25 16:02:17 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2015-08-10 17:43:58 +02:00
|
|
|
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices)
|
2017-05-19 16:59:02 +02:00
|
|
|
m_qmlServerPort = sim->nextPort();
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
2014-02-25 22:48:19 +01:00
|
|
|
|
2014-03-28 19:05:35 +01:00
|
|
|
m_toolHandler = new IosToolHandler(m_deviceType, this);
|
2015-09-11 13:32:45 +02:00
|
|
|
connect(m_toolHandler, &IosToolHandler::appOutput,
|
|
|
|
|
this, &IosRunner::handleAppOutput);
|
|
|
|
|
connect(m_toolHandler, &IosToolHandler::errorMsg,
|
|
|
|
|
this, &IosRunner::handleErrorMsg);
|
|
|
|
|
connect(m_toolHandler, &IosToolHandler::gotServerPorts,
|
|
|
|
|
this, &IosRunner::handleGotServerPorts);
|
|
|
|
|
connect(m_toolHandler, &IosToolHandler::gotInferiorPid,
|
|
|
|
|
this, &IosRunner::handleGotInferiorPid);
|
|
|
|
|
connect(m_toolHandler, &IosToolHandler::toolExited,
|
|
|
|
|
this, &IosRunner::handleToolExited);
|
|
|
|
|
connect(m_toolHandler, &IosToolHandler::finished,
|
|
|
|
|
this, &IosRunner::handleFinished);
|
2018-05-07 12:20:04 +02:00
|
|
|
|
|
|
|
|
QStringList args = QtcProcess::splitArgs(m_arguments, OsTypeMac);
|
2019-08-23 11:13:29 +02:00
|
|
|
if (m_qmlServerPort.isValid()) {
|
|
|
|
|
QUrl qmlServer;
|
|
|
|
|
qmlServer.setPort(m_qmlServerPort.number());
|
|
|
|
|
args.append(QmlDebug::qmlDebugTcpArguments(m_qmlDebugServices, qmlServer));
|
|
|
|
|
}
|
2018-05-07 12:20:04 +02:00
|
|
|
|
|
|
|
|
m_toolHandler->requestRunApp(bundlePath(), args, runType(), deviceId());
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunner::stop()
|
|
|
|
|
{
|
2017-05-19 16:59:02 +02:00
|
|
|
if (isAppRunning())
|
2013-04-25 16:02:17 +02:00
|
|
|
m_toolHandler->stop();
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-25 22:48:19 +01:00
|
|
|
void IosRunner::handleGotServerPorts(IosToolHandler *handler, const QString &bundlePath,
|
2017-05-19 16:59:02 +02:00
|
|
|
const QString &deviceId, Port gdbPort,
|
|
|
|
|
Port qmlPort)
|
2013-04-25 16:02:17 +02:00
|
|
|
{
|
2017-05-19 16:59:02 +02:00
|
|
|
// Called when debugging on Device.
|
2019-09-02 10:32:51 +02:00
|
|
|
Q_UNUSED(bundlePath)
|
|
|
|
|
Q_UNUSED(deviceId)
|
2017-06-26 14:15:44 +02:00
|
|
|
|
|
|
|
|
if (m_toolHandler != handler)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_gdbServerPort = gdbPort;
|
|
|
|
|
m_qmlServerPort = qmlPort;
|
|
|
|
|
|
|
|
|
|
bool prerequisiteOk = false;
|
|
|
|
|
if (cppDebug() && qmlDebug())
|
|
|
|
|
prerequisiteOk = m_gdbServerPort.isValid() && m_qmlServerPort.isValid();
|
|
|
|
|
else if (cppDebug())
|
|
|
|
|
prerequisiteOk = m_gdbServerPort.isValid();
|
|
|
|
|
else if (qmlDebug())
|
|
|
|
|
prerequisiteOk = m_qmlServerPort.isValid();
|
|
|
|
|
else
|
|
|
|
|
prerequisiteOk = true; // Not debugging. Ports not required.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (prerequisiteOk)
|
|
|
|
|
reportStarted();
|
|
|
|
|
else
|
|
|
|
|
reportFailure(tr("Could not get necessary ports for the debugger connection."));
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunner::handleGotInferiorPid(IosToolHandler *handler, const QString &bundlePath,
|
2015-09-11 13:13:04 +02:00
|
|
|
const QString &deviceId, qint64 pid)
|
2013-04-25 16:02:17 +02:00
|
|
|
{
|
2017-05-19 16:59:02 +02:00
|
|
|
// Called when debugging on Simulator.
|
2019-09-02 10:32:51 +02:00
|
|
|
Q_UNUSED(bundlePath)
|
|
|
|
|
Q_UNUSED(deviceId)
|
2017-06-26 14:15:44 +02:00
|
|
|
|
|
|
|
|
if (m_toolHandler != handler)
|
|
|
|
|
return;
|
|
|
|
|
|
2013-10-28 08:16:05 +01:00
|
|
|
m_pid = pid;
|
2017-06-26 14:15:44 +02:00
|
|
|
bool prerequisiteOk = false;
|
|
|
|
|
if (m_pid > 0) {
|
|
|
|
|
prerequisiteOk = true;
|
|
|
|
|
} else {
|
2017-05-19 16:59:02 +02:00
|
|
|
reportFailure(tr("Could not get inferior PID."));
|
2017-06-26 14:15:44 +02:00
|
|
|
return;
|
2017-05-19 16:59:02 +02:00
|
|
|
}
|
2017-06-26 14:15:44 +02:00
|
|
|
|
|
|
|
|
if (qmlDebug())
|
|
|
|
|
prerequisiteOk = m_qmlServerPort.isValid();
|
|
|
|
|
|
|
|
|
|
if (prerequisiteOk)
|
|
|
|
|
reportStarted();
|
|
|
|
|
else
|
2017-12-27 13:56:54 +01:00
|
|
|
reportFailure(tr("Could not get necessary ports for the debugger connection."));
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunner::handleAppOutput(IosToolHandler *handler, const QString &output)
|
|
|
|
|
{
|
2019-07-23 10:58:00 +02:00
|
|
|
Q_UNUSED(handler)
|
2017-05-19 16:59:02 +02:00
|
|
|
QRegExp qmlPortRe("QML Debugger: Waiting for connection on port ([0-9]+)...");
|
2014-02-25 22:48:19 +01:00
|
|
|
int index = qmlPortRe.indexIn(output);
|
|
|
|
|
QString res(output);
|
2017-05-19 16:59:02 +02:00
|
|
|
if (index != -1 && m_qmlServerPort.isValid())
|
|
|
|
|
res.replace(qmlPortRe.cap(1), QString::number(m_qmlServerPort.number()));
|
|
|
|
|
appendMessage(output, StdOutFormat);
|
|
|
|
|
appOutput(res);
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunner::handleErrorMsg(IosToolHandler *handler, const QString &msg)
|
|
|
|
|
{
|
2019-07-23 10:58:00 +02:00
|
|
|
Q_UNUSED(handler)
|
2014-03-24 10:53:26 +01:00
|
|
|
QString res(msg);
|
2017-05-19 16:59:02 +02:00
|
|
|
QString lockedErr ="Unexpected reply: ELocked (454c6f636b6564) vs OK (4f4b)";
|
|
|
|
|
if (msg.contains("AMDeviceStartService returned -402653150")) {
|
2013-11-04 22:45:52 +01:00
|
|
|
TaskHub::addTask(Task::Warning,
|
|
|
|
|
tr("Run failed. The settings in the Organizer window of Xcode might be incorrect."),
|
|
|
|
|
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
|
2014-06-24 14:16:30 +02:00
|
|
|
} else if (res.contains(lockedErr)) {
|
2014-03-24 10:53:26 +01:00
|
|
|
QString message = tr("The device is locked, please unlock.");
|
|
|
|
|
TaskHub::addTask(Task::Error, message,
|
2013-11-04 22:45:52 +01:00
|
|
|
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
|
2014-06-24 14:16:30 +02:00
|
|
|
res.replace(lockedErr, message);
|
2014-03-24 10:53:26 +01:00
|
|
|
}
|
2017-05-19 16:59:02 +02:00
|
|
|
QRegExp qmlPortRe("QML Debugger: Waiting for connection on port ([0-9]+)...");
|
2014-02-25 22:48:19 +01:00
|
|
|
int index = qmlPortRe.indexIn(msg);
|
2017-05-19 16:59:02 +02:00
|
|
|
if (index != -1 && m_qmlServerPort.isValid())
|
|
|
|
|
res.replace(qmlPortRe.cap(1), QString::number(m_qmlServerPort.number()));
|
|
|
|
|
|
|
|
|
|
appendMessage(res, StdErrFormat);
|
|
|
|
|
errorMsg(res);
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunner::handleToolExited(IosToolHandler *handler, int code)
|
|
|
|
|
{
|
2019-07-23 10:58:00 +02:00
|
|
|
Q_UNUSED(handler)
|
2013-04-25 16:02:17 +02:00
|
|
|
m_cleanExit = (code == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunner::handleFinished(IosToolHandler *handler)
|
|
|
|
|
{
|
|
|
|
|
if (m_toolHandler == handler) {
|
2017-05-19 16:59:02 +02:00
|
|
|
if (m_cleanExit)
|
|
|
|
|
appendMessage(tr("Run ended."), NormalMessageFormat);
|
|
|
|
|
else
|
|
|
|
|
appendMessage(tr("Run ended with error."), ErrorMessageFormat);
|
|
|
|
|
m_toolHandler = nullptr;
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
handler->deleteLater();
|
2017-05-19 16:59:02 +02:00
|
|
|
reportStopped();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qint64 IosRunner::pid() const
|
|
|
|
|
{
|
|
|
|
|
return m_pid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IosRunner::isAppRunning() const
|
|
|
|
|
{
|
|
|
|
|
return m_toolHandler && m_toolHandler->isRunning();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Utils::Port IosRunner::gdbServerPort() const
|
|
|
|
|
{
|
|
|
|
|
return m_gdbServerPort;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Utils::Port IosRunner::qmlServerPort() const
|
|
|
|
|
{
|
|
|
|
|
return m_qmlServerPort;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// IosRunner
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
IosRunSupport::IosRunSupport(RunControl *runControl)
|
|
|
|
|
: IosRunner(runControl)
|
|
|
|
|
{
|
2019-08-30 15:00:02 +02:00
|
|
|
setId("IosRunSupport");
|
2017-05-19 16:59:02 +02:00
|
|
|
runControl->setIcon(Icons::RUN_SMALL_TOOLBAR);
|
|
|
|
|
QString displayName = QString("Run on %1").arg(device().isNull() ? QString() : device()->displayName());
|
|
|
|
|
runControl->setDisplayName(displayName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IosRunSupport::~IosRunSupport()
|
|
|
|
|
{
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunSupport::start()
|
|
|
|
|
{
|
|
|
|
|
appendMessage(tr("Starting remote process."), NormalMessageFormat);
|
|
|
|
|
IosRunner::start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosRunSupport::stop()
|
|
|
|
|
{
|
|
|
|
|
IosRunner::stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
2017-06-14 14:01:16 +02:00
|
|
|
// IosQmlProfilerSupport
|
2017-05-19 16:59:02 +02:00
|
|
|
//
|
|
|
|
|
|
2017-06-14 14:01:16 +02:00
|
|
|
IosQmlProfilerSupport::IosQmlProfilerSupport(RunControl *runControl)
|
|
|
|
|
: RunWorker(runControl)
|
2017-05-19 16:59:02 +02:00
|
|
|
{
|
2019-08-30 14:22:01 +02:00
|
|
|
setId("IosQmlProfilerSupport");
|
2017-05-19 16:59:02 +02:00
|
|
|
|
2017-06-14 14:01:16 +02:00
|
|
|
m_runner = new IosRunner(runControl);
|
|
|
|
|
m_runner->setQmlDebugging(QmlDebug::QmlProfilerServices);
|
2017-08-08 14:09:50 +02:00
|
|
|
addStartDependency(m_runner);
|
2017-05-19 16:59:02 +02:00
|
|
|
|
ProjectExplorer: Standardize RunWorker creation logic
This unifies the remaining paths of RunWorker creation to always
use RunWorkerFactories in the plugin pimpls.
There were, and are, still effectively three basic kinds of workers:
- "toplevel" tools corresponding to the run modes, that are often all
that's used for local runs and directly started via the fat buttons
or e.g. entries in the analyze menu, with factories already previously
located in the plugin pimpls
- core "tool helpers", providing tool specific functionality typically
used in conjunction with a remote device specific run mechanism,
set up via RunControl::registerWorkerCreator
- target/device specific runhelper like port gatherers contructed e.g.
via *Device::workerCreator(Core::Id id)
Worse, these categories are partially overlapping, so it was not
clear how a "clean" setup would look like, instead some ad-hoc cobbling
"to make it work" happened.
In some cases, the runMode id was used throughout the whole ensemble
of run workers for a given run, and which worker exactly was created
depended on which of the mechanism above was used in which order.
With the new central setup, the top-level runmodes remain, but the
second kind gets new ids, so the implicit dependencies on order
of setup mechanism are avoided.
This also helps in the cases where there was previously unclarity of where
and how to set up worker factories: It's always and only the plugin
pimpl now.
Change-Id: Icd9a08e2d53e19abe8b21fe546f469fae353a69f
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-08-23 15:31:35 +02:00
|
|
|
m_profiler = runControl->createWorker(ProjectExplorer::Constants::QML_PROFILER_RUNNER);
|
2017-08-08 14:09:50 +02:00
|
|
|
m_profiler->addStartDependency(this);
|
2017-05-19 16:59:02 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-14 14:01:16 +02:00
|
|
|
void IosQmlProfilerSupport::start()
|
2017-05-19 16:59:02 +02:00
|
|
|
{
|
2017-06-29 18:32:01 +02:00
|
|
|
QUrl serverUrl;
|
2017-06-14 14:01:16 +02:00
|
|
|
QTcpServer server;
|
|
|
|
|
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|
|
|
|
|
|| server.listen(QHostAddress::LocalHostIPv6), return);
|
2017-11-14 14:06:44 +01:00
|
|
|
serverUrl.setScheme(Utils::urlTcpScheme());
|
2017-06-14 14:01:16 +02:00
|
|
|
serverUrl.setHost(server.serverAddress().toString());
|
2017-05-19 16:59:02 +02:00
|
|
|
|
2017-06-14 14:01:16 +02:00
|
|
|
Port qmlPort = m_runner->qmlServerPort();
|
|
|
|
|
serverUrl.setPort(qmlPort.number());
|
|
|
|
|
m_profiler->recordData("QmlServerUrl", serverUrl);
|
|
|
|
|
if (qmlPort.isValid())
|
|
|
|
|
reportStarted();
|
|
|
|
|
else
|
|
|
|
|
reportFailure(tr("Could not get necessary ports for the profiler connection."));
|
2017-05-19 16:59:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// IosDebugSupport
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
IosDebugSupport::IosDebugSupport(RunControl *runControl)
|
|
|
|
|
: Debugger::DebuggerRunTool(runControl)
|
|
|
|
|
{
|
2019-08-30 14:22:01 +02:00
|
|
|
setId("IosDebugSupport");
|
|
|
|
|
|
2017-05-19 16:59:02 +02:00
|
|
|
m_runner = new IosRunner(runControl);
|
|
|
|
|
m_runner->setCppDebugging(isCppDebugging());
|
|
|
|
|
m_runner->setQmlDebugging(isQmlDebugging() ? QmlDebug::QmlDebuggerServices : QmlDebug::NoQmlDebugServices);
|
|
|
|
|
|
2017-08-08 14:09:50 +02:00
|
|
|
addStartDependency(m_runner);
|
2017-05-19 16:59:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDebugSupport::start()
|
|
|
|
|
{
|
2017-06-13 08:49:18 +02:00
|
|
|
if (!m_runner->isAppRunning()) {
|
|
|
|
|
reportFailure(tr("Application not running."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-19 16:59:02 +02:00
|
|
|
if (device()->type() == Ios::Constants::IOS_DEVICE_TYPE) {
|
|
|
|
|
IosDevice::ConstPtr dev = device().dynamicCast<const IosDevice>();
|
2017-08-24 17:38:06 +02:00
|
|
|
setStartMode(AttachToRemoteProcess);
|
|
|
|
|
setIosPlatform("remote-ios");
|
2017-05-19 16:59:02 +02:00
|
|
|
QString osVersion = dev->osVersion();
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath deviceSdk1 = FilePath::fromString(QDir::homePath()
|
2017-05-19 16:59:02 +02:00
|
|
|
+ "/Library/Developer/Xcode/iOS DeviceSupport/"
|
|
|
|
|
+ osVersion + "/Symbols");
|
|
|
|
|
QString deviceSdk;
|
|
|
|
|
if (deviceSdk1.toFileInfo().isDir()) {
|
|
|
|
|
deviceSdk = deviceSdk1.toString();
|
|
|
|
|
} else {
|
2019-05-28 13:49:26 +02:00
|
|
|
const FilePath deviceSdk2 = IosConfigurations::developerPath()
|
2019-05-15 15:49:19 +02:00
|
|
|
.pathAppended("Platforms/iPhoneOS.platform/DeviceSupport/"
|
|
|
|
|
+ osVersion + "/Symbols");
|
2017-05-19 16:59:02 +02:00
|
|
|
if (deviceSdk2.toFileInfo().isDir()) {
|
|
|
|
|
deviceSdk = deviceSdk2.toString();
|
|
|
|
|
} else {
|
|
|
|
|
TaskHub::addTask(Task::Warning, tr(
|
|
|
|
|
"Could not find device specific debug symbols at %1. "
|
|
|
|
|
"Debugging initialization will be slow until you open the Organizer window of "
|
|
|
|
|
"Xcode with the device connected to have the symbols generated.")
|
|
|
|
|
.arg(deviceSdk1.toUserOutput()),
|
|
|
|
|
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-24 17:38:06 +02:00
|
|
|
setDeviceSymbolsRoot(deviceSdk);
|
2017-05-19 16:59:02 +02:00
|
|
|
} else {
|
2017-08-24 17:38:06 +02:00
|
|
|
setStartMode(AttachExternal);
|
|
|
|
|
setIosPlatform("ios-simulator");
|
2017-05-19 16:59:02 +02:00
|
|
|
}
|
|
|
|
|
|
Avoid some visible uses of RunControl::runConfiguration()
For a long time, probably from the very beginning, a RunControl
was meant to hold (a copy of) data needed for its operation, that was
valid at the time of its construction, to be resilient in cases
where RunConfiguration setting were changed while the RunControl
was running, or to properly re-run with the original settings.
Unfortunately, the task was repetitive, as RunConfiguration
classes had no generic access to properties / "aspects"
and there was was the runConfiguration() accessor (probably
for mostly unrelated reasons in the output pane handling) which
made the idea of just casting that to the original runConfiguration
and access the data directly there appealing, with all the
expected consequences.
This patch here partially addresses the issue by copying some
more of the related data at RunControl construction time and
adjust the using code, avoiding most uses of the runConfiguration()
accessor in a mostly mechanical matter.
Complete removal appears possible, but will be less mechanical
in "difficult" plugins like ios, so this is left for later.
The new accessors in RunControl are very much ad-hoc, leaving
room for improvement, e.g. by consolidating the access to the
run config settings aspects with the other runconfig aspects
or similar. For now the goal is to remove the runConfiguration()
accessor, and to as much as possible fixed data after RunControl
setup is finished.
Next step would be to officially allow construction of RunControls
without a specific RunConfiguration by setting the necessary
data independently, removing the need for the various workarounds
that are currently used for the purpose of faking (parts of) the
effect of the non-existing RunConfiguration or refusing to operate
at all, even if it would be possible.
Change-Id: If8e5596da8422c70e90f97270389adbe6d0b46f2
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
2019-03-11 15:42:43 +01:00
|
|
|
auto iosRunConfig = qobject_cast<IosRunConfiguration *>(runControl()->runConfiguration());
|
2017-08-24 17:38:06 +02:00
|
|
|
setRunControlName(iosRunConfig->applicationName());
|
|
|
|
|
setContinueAfterAttach(true);
|
2017-05-19 16:59:02 +02:00
|
|
|
|
|
|
|
|
Utils::Port gdbServerPort = m_runner->gdbServerPort();
|
|
|
|
|
Utils::Port qmlServerPort = m_runner->qmlServerPort();
|
2017-08-24 17:38:06 +02:00
|
|
|
setAttachPid(ProcessHandle(m_runner->pid()));
|
2017-05-19 16:59:02 +02:00
|
|
|
|
|
|
|
|
const bool cppDebug = isCppDebugging();
|
|
|
|
|
const bool qmlDebug = isQmlDebugging();
|
|
|
|
|
if (cppDebug) {
|
2019-06-20 17:19:12 +02:00
|
|
|
setInferiorExecutable(iosRunConfig->localExecutable());
|
2017-08-24 17:38:06 +02:00
|
|
|
setRemoteChannel("connect://localhost:" + gdbServerPort.toString());
|
2017-05-19 16:59:02 +02:00
|
|
|
|
|
|
|
|
QString bundlePath = iosRunConfig->bundleDirectory().toString();
|
|
|
|
|
bundlePath.chop(4);
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath dsymPath = FilePath::fromString(bundlePath.append(".dSYM"));
|
2017-10-10 13:01:06 +02:00
|
|
|
if (dsymPath.exists() && dsymPath.toFileInfo().lastModified()
|
|
|
|
|
< QFileInfo(iosRunConfig->localExecutable().toUserOutput()).lastModified()) {
|
2017-05-19 16:59:02 +02:00
|
|
|
TaskHub::addTask(Task::Warning,
|
|
|
|
|
tr("The dSYM %1 seems to be outdated, it might confuse the debugger.")
|
|
|
|
|
.arg(dsymPath.toUserOutput()),
|
|
|
|
|
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 17:38:06 +02:00
|
|
|
QUrl qmlServer;
|
2017-05-19 16:59:02 +02:00
|
|
|
if (qmlDebug) {
|
|
|
|
|
QTcpServer server;
|
|
|
|
|
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|
|
|
|
|
|| server.listen(QHostAddress::LocalHostIPv6), return);
|
2017-08-24 17:38:06 +02:00
|
|
|
qmlServer.setHost(server.serverAddress().toString());
|
2017-05-19 16:59:02 +02:00
|
|
|
if (!cppDebug)
|
2017-08-24 17:38:06 +02:00
|
|
|
setStartMode(AttachToRemoteServer);
|
2017-05-19 16:59:02 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-24 17:38:06 +02:00
|
|
|
if (qmlServerPort.isValid())
|
|
|
|
|
qmlServer.setPort(qmlServerPort.number());
|
2017-05-19 16:59:02 +02:00
|
|
|
|
2017-08-24 17:38:06 +02:00
|
|
|
setQmlServer(qmlServer);
|
2017-05-19 16:59:02 +02:00
|
|
|
|
|
|
|
|
DebuggerRunTool::start();
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
2013-10-16 11:02:37 +02:00
|
|
|
} // namespace Ios
|