Debugger: Provide a way for plugins to init a local DebuggerRunControl

In order for plugins to create their own local DebuggerRunControl
without the need to copy lots of code, the
fillParametersFromRunConfiguration is introduced and exported.

Change-Id: I50edc3f6f048a9f34e358b4104ef75c94c74dbb8
Reviewed-by: hjk <hjk@theqtcompany.com>
Reviewed-by: Benjamin Zeller <benjamin.zeller@canonical.com>
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
Benjamin Zeller
2015-06-12 11:37:46 +02:00
parent 540f5677e8
commit 0c6bc58e8d
5 changed files with 107 additions and 92 deletions

View File

@@ -99,8 +99,7 @@ enum { debug = 0 };
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
DebuggerRunParameters::DebuggerRunParameters() DebuggerRunParameters::DebuggerRunParameters()
: cppEngineType(NoEngineType), : isSnapshot(false),
isSnapshot(false),
testCase(0) testCase(0)
{} {}

View File

@@ -90,7 +90,6 @@ public:
QString coreFile; QString coreFile;
QString overrideStartScript; // Used in attach to core and remote debugging QString overrideStartScript; // Used in attach to core and remote debugging
QString startMessage; // First status message shown. QString startMessage; // First status message shown.
DebuggerEngineType cppEngineType;
QByteArray remoteSourcesDir; QByteArray remoteSourcesDir;
QString remoteMountPoint; QString remoteMountPoint;
QMap<QString, QString> sourcePathMap; QMap<QString, QString> sourcePathMap;
@@ -430,10 +429,7 @@ private:
DebuggerEngine *createEngine(DebuggerEngineType et, const DebuggerRunParameters &rp, QString *errorMessage); DebuggerEngine *createEngine(DebuggerEngineType et, const DebuggerRunParameters &rp, QString *errorMessage);
bool fillParametersFromKit(DebuggerRunParameters *rp, const ProjectExplorer::Kit *kit, QString *errorMessage = 0); bool fillParametersFromKit(DebuggerStartParameters *sp, const ProjectExplorer::Kit *kit, QString *errorMessage = 0);
bool fillParametersFromLocalRunConfiguration(DebuggerRunParameters *rp,
const ProjectExplorer::RunConfiguration *runConfig, QString *errorMessage = 0);
DebuggerRunControl *createAndScheduleRun(const DebuggerRunParameters &rp); DebuggerRunControl *createAndScheduleRun(const DebuggerRunParameters &rp);

View File

@@ -303,8 +303,10 @@ public:
} }
}; };
bool fillParametersFromLocalRunConfiguration } // namespace Internal
(DebuggerRunParameters *rp, const RunConfiguration *runConfig, QString *errorMessage)
bool fillParametersFromRunConfiguration
(DebuggerStartParameters *sp, const RunConfiguration *runConfig, QString *errorMessage)
{ {
QTC_ASSERT(runConfig, return false); QTC_ASSERT(runConfig, return false);
EnvironmentAspect *environmentAspect = runConfig->extraAspect<EnvironmentAspect>(); EnvironmentAspect *environmentAspect = runConfig->extraAspect<EnvironmentAspect>();
@@ -312,9 +314,63 @@ bool fillParametersFromLocalRunConfiguration
Target *target = runConfig->target(); Target *target = runConfig->target();
Kit *kit = target ? target->kit() : KitManager::defaultKit(); Kit *kit = target ? target->kit() : KitManager::defaultKit();
if (!fillParametersFromKit(rp, kit, errorMessage)) if (!fillParametersFromKit(sp, kit, errorMessage))
return false;
sp->environment = environmentAspect->environment();
if (target) {
if (const Project *project = target->project()) {
sp->projectSourceDirectory = project->projectDirectory().toString();
if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration())
sp->projectBuildDirectory = buildConfig->buildDirectory().toString();
sp->projectSourceFiles = project->files(Project::ExcludeGeneratedFiles);
}
}
DebuggerRunConfigurationAspect *debuggerAspect = runConfig->extraAspect<DebuggerRunConfigurationAspect>();
QTC_ASSERT(debuggerAspect, return false);
sp->multiProcess = debuggerAspect->useMultiProcess();
if (debuggerAspect->useCppDebugger())
sp->languages |= CppLanguage;
if (debuggerAspect->useQmlDebugger()) {
const IDevice::ConstPtr device = DeviceKitInformation::device(runConfig->target()->kit());
QTC_ASSERT(device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE, return sp);
QTcpServer server;
const bool canListen = server.listen(QHostAddress::LocalHost)
|| server.listen(QHostAddress::LocalHostIPv6);
if (!canListen) {
if (errorMessage)
*errorMessage = DebuggerPlugin::tr("Not enough free ports for QML debugging.") + QLatin1Char(' ');
return sp;
}
sp->qmlServerAddress = server.serverAddress().toString();
sp->qmlServerPort = server.serverPort();
sp->languages |= QmlLanguage;
// Makes sure that all bindings go through the JavaScript engine, so that
// breakpoints are actually hit!
const QString optimizerKey = _("QML_DISABLE_OPTIMIZER");
if (!sp->environment.hasKey(optimizerKey))
sp->environment.set(optimizerKey, _("1"));
QtcProcess::addArg(&sp->processArgs, QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(sp->qmlServerPort));
}
sp->startMode = StartInternal;
sp->displayName = runConfig->displayName();
return true;
}
namespace Internal {
bool fillParametersFromLocalRunConfiguration
(DebuggerRunParameters *rp, const RunConfiguration *runConfig, QString *errorMessage)
{
if (!fillParametersFromRunConfiguration(rp, runConfig, errorMessage))
return false; return false;
rp->environment = environmentAspect->environment();
auto rc = qobject_cast<const LocalApplicationRunConfiguration *>(runConfig); auto rc = qobject_cast<const LocalApplicationRunConfiguration *>(runConfig);
QTC_ASSERT(rc, return false); QTC_ASSERT(rc, return false);
@@ -328,55 +384,13 @@ bool fillParametersFromLocalRunConfiguration
rp->processArgs = rc->commandLineArguments(); rp->processArgs = rc->commandLineArguments();
rp->useTerminal = rc->runMode() == ApplicationLauncher::Console; rp->useTerminal = rc->runMode() == ApplicationLauncher::Console;
if (target) {
if (const Project *project = target->project()) {
rp->projectSourceDirectory = project->projectDirectory().toString();
if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration())
rp->projectBuildDirectory = buildConfig->buildDirectory().toString();
rp->projectSourceFiles = project->files(Project::ExcludeGeneratedFiles);
}
}
DebuggerRunConfigurationAspect *debuggerAspect = runConfig->extraAspect<DebuggerRunConfigurationAspect>();
QTC_ASSERT(debuggerAspect, return false);
rp->multiProcess = debuggerAspect->useMultiProcess();
if (debuggerAspect->useCppDebugger())
rp->languages |= CppLanguage;
if (debuggerAspect->useQmlDebugger()) {
const IDevice::ConstPtr device = DeviceKitInformation::device(runConfig->target()->kit());
QTC_ASSERT(device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE, return rp);
QTcpServer server;
const bool canListen = server.listen(QHostAddress::LocalHost)
|| server.listen(QHostAddress::LocalHostIPv6);
if (!canListen) {
if (errorMessage)
*errorMessage = DebuggerPlugin::tr("Not enough free ports for QML debugging.") + QLatin1Char(' ');
return rp;
}
rp->qmlServerAddress = server.serverAddress().toString();
rp->qmlServerPort = server.serverPort();
rp->languages |= QmlLanguage;
// Makes sure that all bindings go through the JavaScript engine, so that
// breakpoints are actually hit!
const QString optimizerKey = _("QML_DISABLE_OPTIMIZER");
if (!rp->environment.hasKey(optimizerKey))
rp->environment.set(optimizerKey, _("1"));
QtcProcess::addArg(&rp->processArgs, QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(rp->qmlServerPort));
}
rp->startMode = StartInternal;
rp->displayName = runConfig->displayName();
return true; return true;
} }
RunControl *DebuggerRunControlFactory::create RunControl *DebuggerRunControlFactory::create
(RunConfiguration *runConfiguration, RunMode mode, QString *errorMessage) (RunConfiguration *runConfiguration, RunMode mode, QString *errorMessage)
{ {
QTC_ASSERT(runConfiguration, return 0);
QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0); QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0);
// We cover only local setup here. Remote setups are handled by the // We cover only local setup here. Remote setups are handled by the
@@ -402,6 +416,10 @@ QObject *createDebuggerRunControlFactory(QObject *parent)
DebuggerRunControl *createDebuggerRunControlInternal(const DebuggerRunParameters &rp0, QString *errorMessage) DebuggerRunControl *createDebuggerRunControlInternal(const DebuggerRunParameters &rp0, QString *errorMessage)
{ {
QTC_ASSERT(rp0.runConfiguration, return 0);
const Target *target = rp0.runConfiguration->target();
QTC_ASSERT(target, return 0);
DebuggerRunParameters rp = rp0; DebuggerRunParameters rp = rp0;
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO);
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
@@ -424,28 +442,30 @@ DebuggerRunControl *createDebuggerRunControlInternal(const DebuggerRunParameters
|| rp.executable == _("/usr/bin/python3")) { || rp.executable == _("/usr/bin/python3")) {
rp.masterEngineType = PdbEngineType; rp.masterEngineType = PdbEngineType;
} else { } else {
if (RunConfiguration *rc = rp.runConfiguration) { if (!fillParametersFromKit(&rp, target->kit(), errorMessage))
DebuggerRunConfigurationAspect *aspect return 0;
= rc->extraAspect<Debugger::DebuggerRunConfigurationAspect>(); auto aspect = rp.runConfiguration->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
if (const Target *target = rc->target()) const bool useCppDebugger = aspect->useCppDebugger() && (rp.languages & CppLanguage);
if (!fillParametersFromKit(&rp, target->kit(), errorMessage)) const bool useQmlDebugger = aspect->useQmlDebugger() && (rp.languages & QmlLanguage);
return 0; if (useQmlDebugger) {
const bool useCppDebugger = aspect->useCppDebugger() && (rp.languages & CppLanguage); if (useCppDebugger)
const bool useQmlDebugger = aspect->useQmlDebugger() && (rp.languages & QmlLanguage); rp.masterEngineType = QmlCppEngineType;
if (useQmlDebugger) { else
if (useCppDebugger) rp.masterEngineType = QmlEngineType;
rp.masterEngineType = QmlCppEngineType;
else
rp.masterEngineType = QmlEngineType;
} else {
rp.masterEngineType = rp.cppEngineType;
}
} else { } else {
rp.masterEngineType = rp.cppEngineType; rp.masterEngineType = rp.cppEngineType;
} }
} }
} }
rp.device = DeviceKitInformation::device(target->kit());
if (rp.device && rp.connParams.port == 0)
rp.connParams = rp.device->sshParameters();
// Could have been set from command line.
if (rp.remoteChannel.isEmpty())
rp.remoteChannel = rp.connParams.host + QLatin1Char(':') + QString::number(rp.connParams.port);
QString error; QString error;
DebuggerEngine *engine = createEngine(rp.masterEngineType, rp, &error); DebuggerEngine *engine = createEngine(rp.masterEngineType, rp, &error);
if (!engine) { if (!engine) {
@@ -478,23 +498,23 @@ static QString executableForPid(qint64 pid)
return QString(); return QString();
} }
bool fillParametersFromKit(DebuggerRunParameters *rp, const Kit *kit, QString *errorMessage /* = 0 */) bool fillParametersFromKit(DebuggerStartParameters *sp, const Kit *kit, QString *errorMessage /* = 0 */)
{ {
if (!kit) { if (!kit) {
// This code can only be reached when starting via the command line // This code can only be reached when starting via the command line
// (-debug pid or executable) or attaching from runconfiguration // (-debug pid or executable) or attaching from runconfiguration
// without specifying a kit. Try to find a kit via ABI. // without specifying a kit. Try to find a kit via ABI.
QList<Abi> abis; QList<Abi> abis;
if (rp->toolChainAbi.isValid()) { if (sp->toolChainAbi.isValid()) {
abis.push_back(rp->toolChainAbi); abis.push_back(sp->toolChainAbi);
} else { } else {
// Try via executable. // Try via executable.
if (rp->executable.isEmpty() if (sp->executable.isEmpty()
&& (rp->startMode == AttachExternal || rp->startMode == AttachCrashedExternal)) { && (sp->startMode == AttachExternal || sp->startMode == AttachCrashedExternal)) {
rp->executable = executableForPid(rp->attachPID); sp->executable = executableForPid(sp->attachPID);
} }
if (!rp->executable.isEmpty()) if (!sp->executable.isEmpty())
abis = Abi::abisOfBinary(FileName::fromString(rp->executable)); abis = Abi::abisOfBinary(FileName::fromString(sp->executable));
} }
if (!abis.isEmpty()) { if (!abis.isEmpty()) {
// Try exact abis. // Try exact abis.
@@ -522,16 +542,16 @@ bool fillParametersFromKit(DebuggerRunParameters *rp, const Kit *kit, QString *e
// Verify that debugger and profile are valid // Verify that debugger and profile are valid
if (!kit) { if (!kit) {
rp->startMode = NoStartMode; sp->startMode = NoStartMode;
if (errorMessage) if (errorMessage)
*errorMessage = DebuggerKitInformation::tr("No kit found."); *errorMessage = DebuggerKitInformation::tr("No kit found.");
return false; return false;
} }
// validate debugger if C++ debugging is enabled // validate debugger if C++ debugging is enabled
if (rp->languages & CppLanguage) { if (sp->languages & CppLanguage) {
const QList<Task> tasks = DebuggerKitInformation::validateDebugger(kit); const QList<Task> tasks = DebuggerKitInformation::validateDebugger(kit);
if (!tasks.isEmpty()) { if (!tasks.isEmpty()) {
rp->startMode = NoStartMode; sp->startMode = NoStartMode;
if (errorMessage) { if (errorMessage) {
foreach (const Task &t, tasks) { foreach (const Task &t, tasks) {
if (errorMessage->isEmpty()) if (errorMessage->isEmpty())
@@ -542,21 +562,14 @@ bool fillParametersFromKit(DebuggerRunParameters *rp, const Kit *kit, QString *e
return false; return false;
} }
} }
rp->cppEngineType = DebuggerKitInformation::engineType(kit); sp->cppEngineType = DebuggerKitInformation::engineType(kit);
rp->sysRoot = SysRootKitInformation::sysRoot(kit).toString(); sp->sysRoot = SysRootKitInformation::sysRoot(kit).toString();
rp->debuggerCommand = DebuggerKitInformation::debuggerCommand(kit).toString(); sp->debuggerCommand = DebuggerKitInformation::debuggerCommand(kit).toString();
ToolChain *tc = ToolChainKitInformation::toolChain(kit); ToolChain *tc = ToolChainKitInformation::toolChain(kit);
if (tc) if (tc)
rp->toolChainAbi = tc->targetAbi(); sp->toolChainAbi = tc->targetAbi();
rp->device = DeviceKitInformation::device(kit);
if (rp->device) {
rp->connParams = rp->device->sshParameters();
// Could have been set from command line.
if (rp->remoteChannel.isEmpty())
rp->remoteChannel = rp->connParams.host + QLatin1Char(':') + QString::number(rp->connParams.port);
}
return true; return true;
} }

View File

@@ -50,6 +50,10 @@ DebuggerRunControl *createDebuggerRunControlInternal(const DebuggerRunParameters
DEBUGGER_EXPORT DebuggerRunControl *createDebuggerRunControl(const DebuggerStartParameters &sp, DEBUGGER_EXPORT DebuggerRunControl *createDebuggerRunControl(const DebuggerStartParameters &sp,
QString *errorMessage); QString *errorMessage);
DEBUGGER_EXPORT bool fillParametersFromRunConfiguration(DebuggerStartParameters *sp,
const ProjectExplorer::RunConfiguration *runConfig,
QString *errorMessage);
namespace Internal { class DebuggerEngine; } namespace Internal { class DebuggerEngine; }
class DEBUGGER_EXPORT DebuggerRunControl class DEBUGGER_EXPORT DebuggerRunControl

View File

@@ -38,6 +38,7 @@
#include <utils/environment.h> #include <utils/environment.h>
#include <projectexplorer/abi.h> #include <projectexplorer/abi.h>
#include <projectexplorer/runconfiguration.h> #include <projectexplorer/runconfiguration.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <QMetaType> #include <QMetaType>
#include <QVector> #include <QVector>
@@ -73,6 +74,7 @@ class DEBUGGER_EXPORT DebuggerStartParameters
public: public:
DebuggerStartParameters() DebuggerStartParameters()
: masterEngineType(NoEngineType), : masterEngineType(NoEngineType),
cppEngineType(NoEngineType),
runConfiguration(0), runConfiguration(0),
attachPID(-1), attachPID(-1),
useTerminal(false), useTerminal(false),
@@ -91,6 +93,7 @@ public:
{} {}
DebuggerEngineType masterEngineType; DebuggerEngineType masterEngineType;
DebuggerEngineType cppEngineType;
QString sysRoot; QString sysRoot;
QString deviceSymbolsRoot; QString deviceSymbolsRoot;
QString debuggerCommand; QString debuggerCommand;