WinRT: Enable debugging for local packages.

Change-Id: Ic04f1a471f951caf7a79c69cceecb0ebd5d09919
Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
David Schulz
2014-04-25 09:20:57 +02:00
committed by hjk
parent 93e37b7e78
commit 751a61b2e4
18 changed files with 748 additions and 142 deletions

View File

@@ -2699,8 +2699,7 @@ void CdbEngine::parseOutputLine(QByteArray line)
m_autoBreakPointCorrection = major > 6 || (major == 6 && minor >= 2 && minor < 10);
showMessage(QString::fromLocal8Bit(line), LogMisc);
showMessage(QString::fromLatin1("Using ")
+ m_autoBreakPointCorrection ? QLatin1String("CDB ")
: QLatin1String("codemodel ")
+ QLatin1String(m_autoBreakPointCorrection ? "CDB " : "codemodel ")
+ QString::fromLatin1("based breakpoint correction."), LogMisc);
}
}

View File

@@ -135,18 +135,6 @@ int breakPointIdToCdbId(const BreakpointModelId &id)
return cdbBreakPointStartId + id.majorPart() * cdbBreakPointIdMinorPart + id.minorPart();
}
template <class ModelId>
inline ModelId cdbIdToBreakpointId(const GdbMi &data)
{
if (data.isValid()) { // Might not be valid if there is not id
bool ok;
const int id = data.data().toInt(&ok);
if (ok)
return cdbIdToBreakpointId<ModelId>(id);
}
return ModelId();
}
template <class ModelId>
inline ModelId cdbIdToBreakpointId(const int &id)
{
@@ -161,6 +149,18 @@ inline ModelId cdbIdToBreakpointId(const int &id)
return ModelId();
}
template <class ModelId>
inline ModelId cdbIdToBreakpointId(const GdbMi &data)
{
if (data.isValid()) { // Might not be valid if there is not id
bool ok;
const int id = data.data().toInt(&ok);
if (ok)
return cdbIdToBreakpointId<ModelId>(id);
}
return ModelId();
}
BreakpointModelId cdbIdToBreakpointModelId(const GdbMi &id)
{
return cdbIdToBreakpointId<BreakpointModelId>(id);

View File

@@ -2,6 +2,7 @@ include(../../qtcreatorplugin.pri)
HEADERS += \
winrtconstants.h \
winrtdebugsupport.h \
winrtdeployconfiguration.h \
winrtdevice.h \
winrtdevicefactory.h \
@@ -14,9 +15,11 @@ HEADERS += \
winrtrunconfiguration.h \
winrtrunconfigurationwidget.h \
winrtruncontrol.h \
winrtrunfactories.h
winrtrunfactories.h \
winrtrunnerhelper.h
SOURCES += \
winrtdebugsupport.cpp \
winrtdeployconfiguration.cpp \
winrtdevice.cpp \
winrtdevicefactory.cpp \
@@ -29,7 +32,8 @@ SOURCES += \
winrtrunconfiguration.cpp \
winrtrunconfigurationwidget.cpp \
winrtruncontrol.cpp \
winrtrunfactories.cpp
winrtrunfactories.cpp \
winrtrunnerhelper.cpp
DEFINES += WINRT_LIBRARY

View File

@@ -7,12 +7,15 @@ QtcPlugin {
minimumQtVersion: "5.0"
Depends { name: "Core" }
Depends { name: "Debugger" }
Depends { name: "ProjectExplorer" }
Depends { name: "QtSupport" }
Depends { name: "Qt.gui" }
files: [
"winrtconstants.h",
"winrtdebugsupport.cpp",
"winrtdebugsupport.h",
"winrtdeployconfiguration.cpp",
"winrtdeployconfiguration.h",
"winrtdevice.cpp",
@@ -40,6 +43,8 @@ QtcPlugin {
"winrtruncontrol.cpp",
"winrtruncontrol.h",
"winrtrunfactories.cpp",
"winrtrunfactories.h"
"winrtrunfactories.h",
"winrtrunnerhelper.cpp",
"winrtrunnerhelper.h"
]
}

View File

@@ -1,5 +1,6 @@
QTC_PLUGIN_NAME = WinRt
QTC_PLUGIN_DEPENDS += \
coreplugin \
debugger \
projectexplorer \
qtsupport

View File

@@ -0,0 +1,141 @@
/****************************************************************************
**
** 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 "winrtdebugsupport.h"
#include "winrtrunconfiguration.h"
#include "winrtrunnerhelper.h"
#include <debugger/debuggerengine.h>
#include <debugger/debuggerkitinformation.h>
#include <debugger/debuggerplugin.h>
#include <debugger/debuggerrunner.h>
#include <debugger/debuggerstartparameters.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <QFileInfo>
#include <QLocalServer>
#include <QLocalSocket>
#include <utils/qtcprocess.h>
namespace WinRt {
namespace Internal {
using namespace ProjectExplorer;
WinRtDebugSupport::WinRtDebugSupport(RunControl *runControl, WinRtRunnerHelper *runner)
: QObject(runControl)
, m_debugRunControl(runControl)
, m_runner(runner)
{
connect(m_debugRunControl, SIGNAL(finished()), this, SLOT(finish()));
}
void WinRtDebugSupport::finish()
{
m_runner->stop();
}
RunControl *WinRtDebugSupport::createDebugRunControl(WinRtRunConfiguration *runConfig,
RunMode mode,
QString *errorMessage)
{
// FIXME: This is just working for local debugging;
using namespace Debugger;
DebuggerStartParameters params;
params.startMode = AttachExternal;
params.languages |= CppLanguage;
params.breakOnMain = mode == DebugRunModeWithBreakOnMain;
// The first Thread needs to be resumed manually.
params.commandsAfterConnect = "~0 m";
Kit *kit = runConfig->target()->kit();
params.debuggerCommand = DebuggerKitInformation::debuggerCommand(kit).toString();
if (ToolChain *tc = ToolChainKitInformation::toolChain(kit))
params.toolChainAbi = tc->targetAbi();
QFileInfo debuggerHelper(QCoreApplication::applicationDirPath()
+ QLatin1String("/winrtdebughelper.exe"));
if (!debuggerHelper.isExecutable()) {
*errorMessage = tr("The WinRT debugging helper is missing from your Qt Creator "
"installation. It was assumed to be located at").arg(
debuggerHelper.absoluteFilePath());
return 0;
}
WinRtRunnerHelper *runner = new WinRtRunnerHelper(runConfig, errorMessage);
if (!errorMessage->isEmpty())
return 0;
runner->debug(debuggerHelper.absoluteFilePath());
if (!runner->waitForStarted()) {
*errorMessage = tr("Cannot start the WinRT Runner Tool.");
return 0;
}
QLocalServer server;
server.listen(QLatin1String("QtCreatorWinRtDebugPIDPipe"));
if (!server.waitForNewConnection(10000)) {
*errorMessage = tr("Cannot establish connection to the WinRT debugging helper.");
return 0;
}
while (server.hasPendingConnections()) {
QLocalSocket *connection = server.nextPendingConnection();
if (connection->waitForReadyRead(1000)) {
const QByteArray &output = connection->readAll();
QList<QByteArray> arg = output.split(':');
if (arg.first() == "PID") {
bool ok =false;
params.attachPID = arg.last().toInt(&ok);
if (!ok) {
*errorMessage = tr("Cannot extract the PID from the WinRT debugging helper. "
"(output: %1)").arg(QString::fromLocal8Bit(output));
return 0;
}
server.close();
Debugger::DebuggerRunControl *debugRunControl
= DebuggerPlugin::createDebugger(params, runConfig, errorMessage);
runner->setRunControl(debugRunControl);
new WinRtDebugSupport(debugRunControl, runner);
return debugRunControl;
}
}
}
server.close();
*errorMessage = tr("Cannot create an appropriate run control for "
"the current run configuration.");
return 0;
}
} // namespace Internal
} // namespace WinRt

View File

@@ -0,0 +1,65 @@
/****************************************************************************
**
** 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 WINRT_INTERNAL_WINRTDEBUGSUPPORT_H
#define WINRT_INTERNAL_WINRTDEBUGSUPPORT_H
#include <projectexplorer/runconfiguration.h>
#include <QObject>
namespace WinRt {
namespace Internal {
class WinRtRunConfiguration;
class WinRtRunnerHelper;
class WinRtDebugSupport : public QObject
{
Q_OBJECT
public:
static ProjectExplorer::RunControl *createDebugRunControl(WinRtRunConfiguration *runConfig,
ProjectExplorer::RunMode mode,
QString *errorMessage);
private:
WinRtDebugSupport(ProjectExplorer::RunControl *runControl, WinRtRunnerHelper *runner);
ProjectExplorer::RunControl *m_debugRunControl;
WinRtRunnerHelper *m_runner;
private slots:
void finish();
};
} // namespace Internal
} // namespace WinRt
#endif // WINRT_INTERNAL_WINRTDEBUGSUPPORT_H

View File

@@ -30,6 +30,7 @@
#include "winrtdevice.h"
#include "winrtconstants.h"
#include <projectexplorer/devicesupport/desktopprocesssignaloperation.h>
#include <projectexplorer/devicesupport/devicemanager.h>
#include <projectexplorer/devicesupport/deviceprocesslist.h>
#include <utils/qtcassert.h>
@@ -84,9 +85,16 @@ void WinRtDevice::executeAction(Core::Id actionId, QWidget *parent)
Q_UNUSED(parent);
}
ProjectExplorer::DeviceProcessSignalOperation::Ptr WinRtDevice::signalOperation() const
DeviceProcessSignalOperation::Ptr WinRtDevice::signalOperation() const
{
return DeviceProcessSignalOperation::Ptr();
class WinRtDesktopSignalOperation : public ProjectExplorer::DesktopProcessSignalOperation
{
public:
WinRtDesktopSignalOperation() {}
~WinRtDesktopSignalOperation() {}
};
return DeviceProcessSignalOperation::Ptr(new WinRtDesktopSignalOperation());
}
void WinRtDevice::fromMap(const QVariantMap &map)

View File

@@ -28,9 +28,10 @@
****************************************************************************/
#include "winrtruncontrol.h"
#include "winrtrunconfiguration.h"
#include "winrtconstants.h"
#include "winrtdevice.h"
#include "winrtrunconfiguration.h"
#include "winrtrunnerhelper.h"
#include <coreplugin/idocument.h>
#include <extensionsystem/pluginmanager.h>
@@ -41,7 +42,8 @@
#include <projectexplorer/kitinformation.h>
#include <qtsupport/qtkitinformation.h>
using ProjectExplorer::BuildConfiguration;
#include <QTimer>
using ProjectExplorer::DeviceKitInformation;
using ProjectExplorer::IDevice;
using ProjectExplorer::RunControl;
@@ -54,39 +56,10 @@ namespace Internal {
WinRtRunControl::WinRtRunControl(WinRtRunConfiguration *runConfiguration, RunMode mode)
: RunControl(runConfiguration, mode)
, m_runConfiguration(runConfiguration)
, m_state(StoppedState)
, m_process(0)
, m_runner(0)
{
Target *target = runConfiguration->target();
IDevice::ConstPtr device = DeviceKitInformation::device(target->kit());
m_device = device.dynamicCast<const WinRtDevice>();
const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit());
if (!qt) {
appendMessage(tr("The current kit has no Qt version."),
Utils::ErrorMessageFormat);
return;
}
m_isWinPhone = (qt->type() == QLatin1String(Constants::WINRT_WINPHONEQT));
m_runnerFilePath = qt->binPath().toString() + QStringLiteral("/winrtrunner.exe");
if (!QFile::exists(m_runnerFilePath)) {
appendMessage(tr("Cannot find winrtrunner.exe in \"%1\".").arg(
QDir::toNativeSeparators(qt->binPath().toString())),
Utils::ErrorMessageFormat);
return;
}
const Utils::FileName proFile = Utils::FileName::fromString(
target->project()->document()->filePath());
m_executableFilePath = target->applicationTargets().targetForProject(proFile).toString()
+ QStringLiteral(".exe"); // ### we should not need to append ".exe" here.
m_arguments = runConfiguration->arguments();
m_uninstallAfterStop = runConfiguration->uninstallAfterStop();
if (BuildConfiguration *bc = target->activeBuildConfiguration())
m_environment = bc->environment();
}
void WinRtRunControl::start()
@@ -99,13 +72,10 @@ void WinRtRunControl::start()
RunControl::StopResult WinRtRunControl::stop()
{
if (m_state != StartedState) {
m_state = StoppedState;
if (m_state == StoppedState)
return StoppedSynchronously;
}
QTC_ASSERT(m_process, return StoppedSynchronously);
m_process->interrupt();
m_runner->stop();
return AsynchronousStop;
}
@@ -126,84 +96,31 @@ void WinRtRunControl::onProcessStarted()
emit started();
}
void WinRtRunControl::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
void WinRtRunControl::onProcessFinished()
{
QTC_ASSERT(m_process, return);
QTC_CHECK(m_state == StartedState);
if (exitStatus == QProcess::CrashExit) {
appendMessage(tr("winrtrunner crashed.") + QLatin1Char('\n'), Utils::ErrorMessageFormat);
} else if (exitCode != 0) {
appendMessage(tr("winrtrunner returned with exit code %1.").arg(exitCode)
+ QLatin1Char('\n'), Utils::ErrorMessageFormat);
} else {
appendMessage(tr("winrtrunner finished successfully.")
+ QLatin1Char('\n'), Utils::NormalMessageFormat);
}
m_process->disconnect();
m_process->deleteLater();
m_process = 0;
m_state = StoppedState;
emit finished();
onProcessError();
}
void WinRtRunControl::onProcessError()
{
QTC_ASSERT(m_process, return);
appendMessage(tr("Error while executing winrtrunner: %1\n").arg(m_process->errorString()),
Utils::ErrorMessageFormat);
m_process->disconnect();
m_process->deleteLater();
m_process = 0;
QTC_ASSERT(m_runner, return);
m_runner->disconnect();
m_runner->deleteLater();
m_runner = 0;
m_state = StoppedState;
emit finished();
}
void WinRtRunControl::onProcessReadyReadStdOut()
{
QTC_ASSERT(m_process, return);
appendMessage(QString::fromLocal8Bit(m_process->readAllStandardOutput()), Utils::StdOutFormat);
}
void WinRtRunControl::onProcessReadyReadStdErr()
{
QTC_ASSERT(m_process, return);
appendMessage(QString::fromLocal8Bit(m_process->readAllStandardError()), Utils::StdErrFormat);
}
bool WinRtRunControl::startWinRtRunner()
{
QString runnerArgs;
QtcProcess::addArg(&runnerArgs, QStringLiteral("--profile"));
QtcProcess::addArg(&runnerArgs, m_isWinPhone ? QStringLiteral("xap") : QStringLiteral("appx"));
if (m_device) {
QtcProcess::addArg(&runnerArgs, QStringLiteral("--device"));
QtcProcess::addArg(&runnerArgs, QString::number(m_device->deviceId()));
}
QtcProcess::addArgs(&runnerArgs, QStringLiteral("--install --start --stop --wait 0"));
QtcProcess::addArg(&runnerArgs, m_executableFilePath);
if (!m_arguments.isEmpty())
QtcProcess::addArgs(&runnerArgs, m_arguments);
appendMessage(QStringLiteral("winrtrunner ") + runnerArgs + QLatin1Char('\n'),
Utils::NormalMessageFormat);
QTC_ASSERT(!m_process, m_process->deleteLater());
m_process = new QtcProcess(this);
connect(m_process, SIGNAL(started()), SLOT(onProcessStarted()));
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
SLOT(onProcessFinished(int,QProcess::ExitStatus)));
connect(m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(onProcessError()));
connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(onProcessReadyReadStdOut()));
connect(m_process, SIGNAL(readyReadStandardError()), SLOT(onProcessReadyReadStdErr()));
QTC_ASSERT(!m_runner, return false);
m_runner = new WinRtRunnerHelper(this);
connect(m_runner, SIGNAL(started()), SLOT(onProcessStarted()));
connect(m_runner, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(onProcessFinished()));
connect(m_runner, SIGNAL(error(QProcess::ProcessError)), SLOT(onProcessError()));
m_state = StartingState;
m_process->setUseCtrlCStub(true);
m_process->setCommand(m_runnerFilePath, runnerArgs);
m_process->setEnvironment(m_environment);
m_process->setWorkingDirectory(QFileInfo(m_executableFilePath).absolutePath());
m_process->start();
m_runner->start();
return true;
}

View File

@@ -47,6 +47,7 @@ namespace WinRt {
namespace Internal {
class WinRtRunConfiguration;
class WinRtRunnerHelper;
class WinRtRunControl : public ProjectExplorer::RunControl
{
@@ -61,24 +62,17 @@ public:
private slots:
void onProcessStarted();
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onProcessFinished();
void onProcessError();
void onProcessReadyReadStdOut();
void onProcessReadyReadStdErr();
private:
enum State { StartingState, StartedState, StoppedState };
bool startWinRtRunner();
WinRtRunConfiguration *m_runConfiguration;
State m_state;
WinRtDevice::ConstPtr m_device;
QString m_runnerFilePath;
QString m_executableFilePath;
QString m_arguments;
bool m_uninstallAfterStop;
bool m_isWinPhone;
Utils::QtcProcess *m_process;
Utils::Environment m_environment;
WinRtRunnerHelper *m_runner;
};
} // namespace Internal

View File

@@ -31,16 +31,24 @@
#include "winrtrunconfiguration.h"
#include "winrtruncontrol.h"
#include "winrtconstants.h"
#include "winrtdebugsupport.h"
#include <projectexplorer/target.h>
#include <projectexplorer/project.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <debugger/debuggerkitinformation.h>
#include <debugger/debuggerplugin.h>
#include <debugger/debuggerrunner.h>
#include <debugger/debuggerstartparameters.h>
#include <utils/qtcassert.h>
#include <QLocalServer>
#include <QLocalSocket>
using namespace ProjectExplorer;
namespace WinRt {
@@ -80,7 +88,6 @@ QString WinRtRunConfigurationFactory::displayNameForId(const Core::Id id) const
bool WinRtRunConfigurationFactory::canCreate(Target *parent, const Core::Id id) const
{
Q_UNUSED(parent);
return id == winrtConfigurationIdC && isKitCompatible(parent->kit());
}
@@ -91,7 +98,6 @@ RunConfiguration *WinRtRunConfigurationFactory::doCreate(Target *parent, const C
bool WinRtRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
{
Q_UNUSED(parent);
return ProjectExplorer::idFromMap(map) == winrtConfigurationIdC && isKitCompatible(parent->kit());
}
@@ -123,9 +129,23 @@ WinRtRunControlFactory::WinRtRunControlFactory()
bool WinRtRunControlFactory::canRun(ProjectExplorer::RunConfiguration *runConfiguration,
ProjectExplorer::RunMode mode) const
{
if (mode != NormalRunMode)
if (!runConfiguration)
return false;
return qobject_cast<WinRtRunConfiguration *>(runConfiguration);
IDevice::ConstPtr device = DeviceKitInformation::device(runConfiguration->target()->kit());
if (!device)
return false;
switch (mode) {
case DebugRunMode:
case DebugRunModeWithBreakOnMain:
if (device->type() != Constants::WINRT_DEVICE_TYPE_LOCAL)
return false;
// fall through
case NormalRunMode:
return qobject_cast<WinRtRunConfiguration *>(runConfiguration);
default:
return false;
}
}
ProjectExplorer::RunControl *WinRtRunControlFactory::create(
@@ -137,6 +157,9 @@ ProjectExplorer::RunControl *WinRtRunControlFactory::create(
switch (mode) {
case NormalRunMode:
return new WinRtRunControl(rc, mode);
case DebugRunMode:
case DebugRunModeWithBreakOnMain:
return WinRtDebugSupport::createDebugRunControl(rc, mode, errorMessage);
default:
break;
}

View File

@@ -0,0 +1,240 @@
/****************************************************************************
**
** 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 "winrtrunnerhelper.h"
#include "winrtconstants.h"
#include "winrtrunconfiguration.h"
#include <coreplugin/idocument.h>
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <utils/qtcprocess.h>
#include <QDir>
using namespace WinRt;
using namespace WinRt::Internal;
WinRtRunnerHelper::WinRtRunnerHelper(WinRtRunConfiguration *runConfiguration, QString *errormessage)
: QObject(runConfiguration)
, m_messenger(0)
, m_runConfiguration(runConfiguration)
, m_process(0)
{
init(runConfiguration, errormessage);
}
WinRtRunnerHelper::WinRtRunnerHelper(ProjectExplorer::RunControl *runControl)
: QObject(runControl)
, m_messenger(runControl)
, m_runConfiguration(0)
, m_process(0)
{
m_runConfiguration = qobject_cast<WinRtRunConfiguration *>(runControl->runConfiguration());
QString errorMessage;
if (!init(m_runConfiguration, &errorMessage))
runControl->appendMessage(errorMessage, Utils::ErrorMessageFormat);
}
bool WinRtRunnerHelper::init(WinRtRunConfiguration *runConfiguration, QString *errorMessage)
{
ProjectExplorer::Target *target = runConfiguration->target();
m_device = ProjectExplorer::DeviceKitInformation::device(
target->kit()).dynamicCast<const WinRtDevice>();
const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit());
if (!qt) {
*errorMessage = tr("The current kit has no Qt version.");
return false;
}
m_isWinPhone = (qt->type() == QLatin1String(Constants::WINRT_WINPHONEQT));
m_runnerFilePath = qt->binPath().toString() + QStringLiteral("/winrtrunner.exe");
if (!QFile::exists(m_runnerFilePath)) {
*errorMessage = tr("Cannot find winrtrunner.exe in \"%1\".").arg(
QDir::toNativeSeparators(qt->binPath().toString()));
return false;
}
const Utils::FileName proFile = Utils::FileName::fromString(
target->project()->document()->filePath());
m_executableFilePath = target->applicationTargets().targetForProject(proFile).toString()
+ QStringLiteral(".exe"); // ### we should not need to append ".exe" here.
m_arguments = runConfiguration->arguments();
m_uninstallAfterStop = runConfiguration->uninstallAfterStop();
if (ProjectExplorer::BuildConfiguration *bc = target->activeBuildConfiguration())
m_environment = bc->environment();
return true;
}
void WinRtRunnerHelper::debug(const QString &debuggerExecutable, const QString &debuggerArguments)
{
m_debuggerExecutable = debuggerExecutable;
m_debuggerArguments = debuggerArguments;
startWinRtRunner(Debug);
}
void WinRtRunnerHelper::start()
{
startWinRtRunner(Start);
}
void WinRtRunnerHelper::stop()
{
if (m_process)
m_process->interrupt();
else
startWinRtRunner(Stop);
}
bool WinRtRunnerHelper::waitForStarted(int msecs)
{
QTC_ASSERT(m_process, return false);
return m_process->waitForStarted(msecs);
}
void WinRtRunnerHelper::setRunControl(ProjectExplorer::RunControl *runControl)
{
m_messenger = runControl;
}
void WinRtRunnerHelper::onProcessReadyReadStdOut()
{
QTC_ASSERT(m_process, return);
if (m_messenger) {
m_messenger->appendMessage(QString::fromLocal8Bit(
m_process->readAllStandardOutput()), Utils::StdOutFormat);
}
}
void WinRtRunnerHelper::onProcessReadyReadStdErr()
{
QTC_ASSERT(m_process, return);
if (m_messenger) {
m_messenger->appendMessage(QString::fromLocal8Bit(
m_process->readAllStandardError()), Utils::StdErrFormat);
}
}
void WinRtRunnerHelper::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
QTC_ASSERT(m_process, return);
m_process->disconnect();
m_process->deleteLater();
m_process = 0;
emit finished(exitCode, exitStatus);
}
void WinRtRunnerHelper::onProcessError(QProcess::ProcessError processError)
{
QTC_ASSERT(m_process, return);
if (m_messenger) {
m_messenger->appendMessage(tr("Error while executing the WinRT Runner Tool: %1\n").arg(
m_process->errorString()),
Utils::ErrorMessageFormat);
}
m_process->disconnect();
m_process->deleteLater();
m_process = 0;
emit error(processError);
}
void WinRtRunnerHelper::startWinRtRunner(const RunConf &conf)
{
using namespace Utils;
QString runnerArgs;
QtcProcess::addArg(&runnerArgs, QStringLiteral("--profile"));
QtcProcess::addArg(&runnerArgs, m_isWinPhone ? QStringLiteral("xap") : QStringLiteral("appx"));
if (m_device) {
QtcProcess::addArg(&runnerArgs, QStringLiteral("--device"));
QtcProcess::addArg(&runnerArgs, QString::number(m_device->deviceId()));
}
Utils::QtcProcess *process = 0;
bool connectProcess = false;
switch (conf) {
case Debug:
Utils::QtcProcess::addArg(&runnerArgs, QStringLiteral("--debug"));
Utils::QtcProcess::addArg(&runnerArgs, m_debuggerExecutable);
if (!m_debuggerArguments.isEmpty()) {
Utils::QtcProcess::addArg(&runnerArgs, QStringLiteral("--debugger-arguments"));
Utils::QtcProcess::addArg(&runnerArgs, m_debuggerArguments);
}
// fall through
case Start:
QtcProcess::addArgs(&runnerArgs, QStringLiteral("--start --stop --install --wait 0"));
connectProcess = true;
QTC_ASSERT(!m_process, m_process->deleteLater());
m_process = new QtcProcess(this);
process = m_process;
break;
case Stop:
Utils::QtcProcess::addArgs(&runnerArgs, QStringLiteral("--stop"));
process = new QtcProcess(this);
break;
}
QtcProcess::addArg(&runnerArgs, m_executableFilePath);
if (!m_arguments.isEmpty())
QtcProcess::addArgs(&runnerArgs, m_arguments);
if (m_messenger) {
m_messenger->appendMessage(QStringLiteral("winrtrunner ") + runnerArgs + QLatin1Char('\n'),
Utils::NormalMessageFormat);
}
if (connectProcess) {
connect(process, SIGNAL(started()), SIGNAL(started()));
connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
SLOT(onProcessFinished(int, QProcess::ExitStatus)));
connect(process, SIGNAL(error(QProcess::ProcessError)),
SLOT(onProcessError(QProcess::ProcessError)));
connect(process, SIGNAL(readyReadStandardOutput()), SLOT(onProcessReadyReadStdOut()));
connect(process, SIGNAL(readyReadStandardError()), SLOT(onProcessReadyReadStdErr()));
}
process->setUseCtrlCStub(true);
process->setCommand(m_runnerFilePath, runnerArgs);
process->setEnvironment(m_environment);
process->setWorkingDirectory(QFileInfo(m_executableFilePath).absolutePath());
process->start();
}

View File

@@ -0,0 +1,99 @@
/****************************************************************************
**
** 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 WINRTRUNNERHELPER_H
#define WINRTRUNNERHELPER_H
#include "winrtdevice.h"
#include <utils/environment.h>
#include <utils/outputformat.h>
#include <QObject>
#include <QProcess>
namespace Utils { class QtcProcess; }
namespace ProjectExplorer { class RunControl; }
namespace WinRt {
namespace Internal {
class WinRtRunConfiguration;
class WinRtRunnerHelper : public QObject
{
Q_OBJECT
public:
WinRtRunnerHelper(ProjectExplorer::RunControl *runControl);
WinRtRunnerHelper(WinRtRunConfiguration *runConfiguration, QString *errormessage);
void debug(const QString &debuggerExecutable, const QString &debuggerArguments = QString());
void start();
void stop();
bool waitForStarted(int msecs = 10000);
void setRunControl(ProjectExplorer::RunControl *runControl);
signals:
void started();
void finished(int exitCode, QProcess::ExitStatus exitStatus);
void error(QProcess::ProcessError error);
private slots:
void onProcessReadyReadStdOut();
void onProcessReadyReadStdErr();
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onProcessError(QProcess::ProcessError processError);
private:
enum RunConf { Start, Stop, Debug };
void startWinRtRunner(const RunConf &conf);
bool init(WinRtRunConfiguration *runConfiguration, QString *errorMessage);
ProjectExplorer::RunControl *m_messenger;
WinRtRunConfiguration *m_runConfiguration;
WinRtDevice::ConstPtr m_device;
Utils::Environment m_environment;
QString m_runnerFilePath;
QString m_executableFilePath;
QString m_debuggerExecutable;
QString m_debuggerArguments;
QString m_arguments;
bool m_uninstallAfterStop;
bool m_isWinPhone;
Utils::QtcProcess *m_process;
};
} // namespace WinRt
} // namespace Internal
#endif // WINRTRUNNERHELPER_H

View File

@@ -9,8 +9,9 @@ SUBDIRS = qtpromaker \
buildoutputparser
win32 {
SUBDIRS += qtcdebugger
SUBDIRS += wininterrupt
SUBDIRS += qtcdebugger \
wininterrupt \
winrtdebughelper
}
mac {

View File

@@ -10,6 +10,7 @@ Project {
"sdktool/sdktool.qbs",
"valgrindfake/valgrindfake.qbs",
"3rdparty/iossim/iossim.qbs",
"iostool/iostool.qbs"
"iostool/iostool.qbs",
"winrtdebughelper/winrtdebughelper.qbs"
].concat(project.additionalTools)
}

View File

@@ -0,0 +1,78 @@
/****************************************************************************
**
** 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 <Windows.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int pid = -1;
const size_t maxPipeNameSize = 256;
wchar_t pipeName[maxPipeNameSize] = { 0 };
for (int i = 0; i < argc - 1; ++i) {
if (!strcmp(argv[i], "-t")) {
++i;
if (swprintf(pipeName, maxPipeNameSize, L"%hs", argv[i]) < 0)
return 0; // Pipe name too long
} else if (!strcmp(argv[i], "-p")) {
++i;
// check if -p is followed by a number
const char *pidString = argv[i];
char *end;
pid = strtoul(pidString, &end, 0);
if (*end != 0)
return 0;
}
}
if (pid < 0)
return 0;
if (*pipeName == 0)
swprintf(pipeName, maxPipeNameSize, L"\\\\.\\pipe\\QtCreatorWinRtDebugPIDPipe");
HANDLE pipe;
while (true) {
pipe = CreateFile(pipeName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (pipe != INVALID_HANDLE_VALUE)
break;
if ((GetLastError() != ERROR_PIPE_BUSY) || (!WaitNamedPipe(pipeName, 10000)))
return 0;
}
const size_t msgBufferSize = 15;
char pidMessageBuffer[msgBufferSize];
int length = sprintf_s(pidMessageBuffer, msgBufferSize, "PID:%d", pid);
if (length >= 0)
WriteFile(pipe, pidMessageBuffer, length, NULL, NULL);
return 0;
}

View File

@@ -0,0 +1,17 @@
CONFIG += warn_on console
CONFIG -= qt app_bundle
include(../../../qtcreator.pri)
TEMPLATE = app
DESTDIR = $$IDE_LIBEXEC_PATH
SOURCES = winrtdebughelper.cpp
build_all:!build_pass {
CONFIG -= build_all
CONFIG += release
}
TARGET = winrtdebughelper
target.path = $$IDE_LIBEXEC_PATH
INSTALLS += target

View File

@@ -0,0 +1,13 @@
import qbs 1.0
import QtcTool
QtcTool {
name: "winrtdebughelper"
condition: qbs.targetOS.contains("windows")
Depends { name: "Qt.network" }
files: [
"winrtdebughelper.cpp",
]
}