Commit af6bbc44 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Add debugger engine type to configuration.



Introduce a struct DebuggerItem as a debugger configuration
item, containing debugger engine type and binary. Store
information as a variant map. Add a combo box.

Remove engine guessing logic. Parts of it are still required
when checking the suggested debugger from the SDK.

Split error checking to be able to do a quick error check
and find only valid profiles in the matchers.

Pass on errors up to RunControl::create().

Change-Id: I08653e2a76ca2c371701082f8173b0b8f8ed462e
Reviewed-by: default avatarTobias Hunger <tobias.hunger@nokia.com>
parent 824d0425
......@@ -374,8 +374,7 @@ bool StartApplicationDialog::run(QWidget *parent, QSettings *settings, DebuggerS
}
Kit *kit = dialog.d->kitChooser->currentKit();
QTC_ASSERT(kit, return false);
fillParameters(sp, kit);
QTC_ASSERT(kit && fillParameters(sp, kit), return false);
sp->executable = newParameters.localExecutable;
sp->displayName = newParameters.displayName();
......
......@@ -29,7 +29,6 @@
**************************************************************************/
#include "debuggerkitconfigwidget.h"
#include "debuggerkitinformation.h"
#include <projectexplorer/abi.h>
......@@ -48,6 +47,8 @@
#include <QHBoxLayout>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QComboBox>
namespace Debugger {
namespace Internal {
......@@ -55,6 +56,7 @@ namespace Internal {
static const char dgbToolsDownloadLink32C[] = "http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx";
static const char dgbToolsDownloadLink64C[] = "http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx";
// -----------------------------------------------------------------------
// DebuggerKitConfigWidget:
// -----------------------------------------------------------------------
......@@ -65,34 +67,26 @@ DebuggerKitConfigWidget::DebuggerKitConfigWidget(ProjectExplorer::Kit *k,
ProjectExplorer::KitConfigWidget(parent),
m_kit(k),
m_info(ki),
m_chooser(new Utils::PathChooser)
m_comboBox(new QComboBox(this)),
m_label(new QLabel(this)),
m_chooser(new Utils::PathChooser(this))
{
setToolTip(tr("The debugger to use for this kit."));
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(k);
if (tc && tc->targetAbi().os() == ProjectExplorer::Abi::WindowsOS
&& tc->targetAbi().osFlavor() != ProjectExplorer::Abi::WindowsMSysFlavor) {
QLabel *msvcDebuggerConfigLabel = new QLabel;
#ifdef Q_OS_WIN
const bool is64bit = Utils::winIs64BitSystem();
#else
const bool is64bit = false;
#endif
const QString link = is64bit ? QLatin1String(dgbToolsDownloadLink64C) : QLatin1String(dgbToolsDownloadLink32C);
//: Label text for path configuration. %2 is "x-bit version".
msvcDebuggerConfigLabel->setText(tr("<html><body><p>Specify the path to the "
"<a href=\"%1\">Windows Console Debugger executable</a>"
" (%2) here.</p>"
"</body></html>").arg(link, (is64bit ? tr("64-bit version")
: tr("32-bit version"))));
msvcDebuggerConfigLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
msvcDebuggerConfigLabel->setOpenExternalLinks(true);
layout->addWidget(msvcDebuggerConfigLabel);
m_comboBox->addItem(DebuggerKitInformation::debuggerEngineName(GdbEngineType), QVariant(int(GdbEngineType)));
if (ProjectExplorer::Abi::hostAbi().os() == ProjectExplorer::Abi::WindowsOS) {
m_comboBox->addItem(DebuggerKitInformation::debuggerEngineName(CdbEngineType), QVariant(int(CdbEngineType)));
} else {
m_comboBox->addItem(DebuggerKitInformation::debuggerEngineName(LldbEngineType), QVariant(int(LldbEngineType)));
}
layout->addWidget(m_comboBox);
m_label->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_label->setOpenExternalLinks(true);
layout->addWidget(m_label);
m_chooser->setContentsMargins(0, 0, 0, 0);
m_chooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
......@@ -102,6 +96,8 @@ DebuggerKitConfigWidget::DebuggerKitConfigWidget(ProjectExplorer::Kit *k,
discard();
connect(m_chooser, SIGNAL(changed(QString)), this, SIGNAL(dirty()));
connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(dirty()));
connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(refreshLabel()));
}
QString DebuggerKitConfigWidget::displayName() const
......@@ -111,23 +107,26 @@ QString DebuggerKitConfigWidget::displayName() const
void DebuggerKitConfigWidget::makeReadOnly()
{
m_comboBox->setEnabled(false);
m_chooser->setEnabled(false);
}
void DebuggerKitConfigWidget::apply()
{
Utils::FileName fn = m_chooser->fileName();
DebuggerKitInformation::setDebuggerCommand(m_kit, fn);
DebuggerKitInformation::setDebuggerItem(m_kit, DebuggerKitInformation::DebuggerItem(engineType(), fileName()));
}
void DebuggerKitConfigWidget::discard()
{
m_chooser->setFileName(DebuggerKitInformation::debuggerCommand(m_kit));
const DebuggerKitInformation::DebuggerItem item = DebuggerKitInformation::debuggerItem(m_kit);
setEngineType(item.engineType);
setFileName(item.binary);
}
bool DebuggerKitConfigWidget::isDirty() const
{
return m_chooser->fileName() != DebuggerKitInformation::debuggerCommand(m_kit);
const DebuggerKitInformation::DebuggerItem item = DebuggerKitInformation::debuggerItem(m_kit);
return item.engineType != engineType() || item.binary != fileName();
}
QWidget *DebuggerKitConfigWidget::buttonWidget() const
......@@ -137,8 +136,62 @@ QWidget *DebuggerKitConfigWidget::buttonWidget() const
void DebuggerKitConfigWidget::autoDetectDebugger()
{
QVariant v = m_info->defaultValue(m_kit);
m_chooser->setFileName(Utils::FileName::fromString(v.toString()));
const DebuggerKitInformation::DebuggerItem item = DebuggerKitInformation::autoDetectItem(m_kit);
setEngineType(item.engineType);
setFileName(item.binary);
}
DebuggerEngineType DebuggerKitConfigWidget::engineType() const
{
const int index = m_comboBox->currentIndex();
return static_cast<DebuggerEngineType>(m_comboBox->itemData(index).toInt());
}
void DebuggerKitConfigWidget::setEngineType(DebuggerEngineType et)
{
const int size = m_comboBox->count();
for (int i = 0; i < size; ++i) {
if (m_comboBox->itemData(i).toInt() == et) {
m_comboBox->setCurrentIndex(i);
refreshLabel();
break;
}
}
}
Utils::FileName DebuggerKitConfigWidget::fileName() const
{
return m_chooser->fileName();
}
void DebuggerKitConfigWidget::setFileName(const Utils::FileName &fn)
{
m_chooser->setFileName(fn);
}
void DebuggerKitConfigWidget::refreshLabel()
{
QString text;
switch (engineType()) {
case CdbEngineType: {
#ifdef Q_OS_WIN
const bool is64bit = Utils::winIs64BitSystem();
#else
const bool is64bit = false;
#endif
const QString link = is64bit ? QLatin1String(dgbToolsDownloadLink64C) : QLatin1String(dgbToolsDownloadLink32C);
const QString versionString = is64bit ? tr("64-bit version") : tr("32-bit version");
//: Label text for path configuration. %2 is "x-bit version".
text = tr("<html><body><p>Specify the path to the "
"<a href=\"%1\">Windows Console Debugger executable</a>"
" (%2) here.</p>""</body></html>").arg(link, versionString);
}
break;
default:
break;
}
m_label->setText(text);
m_label->setVisible(!text.isEmpty());
}
} // namespace Internal
......
......@@ -33,11 +33,16 @@
#include <projectexplorer/kitconfigwidget.h>
#include <QLabel>
#include <debuggerkitinformation.h>
#include "debuggerconstants.h"
QT_FORWARD_DECLARE_CLASS(QLabel)
QT_FORWARD_DECLARE_CLASS(QComboBox)
namespace ProjectExplorer { class Kit; }
namespace Utils { class PathChooser; }
namespace Utils {
class PathChooser;
class FileName;
}
namespace Debugger {
class DebuggerKitInformation;
......@@ -65,12 +70,21 @@ public:
bool isDirty() const;
QWidget *buttonWidget() const;
DebuggerEngineType engineType() const;
void setEngineType(DebuggerEngineType et);
Utils::FileName fileName() const;
void setFileName(const Utils::FileName &fn);
private slots:
void autoDetectDebugger();
void refreshLabel();
private:
ProjectExplorer::Kit *m_kit;
const DebuggerKitInformation *m_info;
QComboBox *m_comboBox;
QLabel *m_label;
Utils::PathChooser *m_chooser;
};
......
......@@ -114,12 +114,32 @@ static QPair<QString, QString> autoDetectCdbDebugger()
namespace Debugger {
static DebuggerEngineType engineTypeFromBinary(const QString &binary)
{
if (binary.contains(QLatin1String("cdb"), Qt::CaseInsensitive))
return CdbEngineType;
if (binary.contains(QLatin1String("lldb"), Qt::CaseInsensitive))
return LldbEngineType;
return GdbEngineType;
}
// --------------------------------------------------------------------------
// DebuggerKitInformation:
// --------------------------------------------------------------------------
static const char DEBUGGER_INFORMATION[] = "Debugger.Information";
DebuggerKitInformation::DebuggerItem::DebuggerItem()
: engineType(NoEngineType)
{
}
DebuggerKitInformation::DebuggerItem::DebuggerItem(DebuggerEngineType et, const Utils::FileName &fn)
: engineType(et)
, binary(fn)
{
}
DebuggerKitInformation::DebuggerKitInformation()
{
setObjectName(QLatin1String("DebuggerKitInformation"));
......@@ -136,9 +156,10 @@ unsigned int DebuggerKitInformation::priority() const
return 28000;
}
QVariant DebuggerKitInformation::defaultValue(Kit *k) const
DebuggerKitInformation::DebuggerItem DebuggerKitInformation::autoDetectItem(const Kit *k)
{
ToolChain *tc = ToolChainKitInformation::toolChain(k);
DebuggerItem result;
const ToolChain *tc = ToolChainKitInformation::toolChain(k);
Abi abi = Abi::hostAbi();
if (tc)
abi = tc->targetAbi();
......@@ -146,59 +167,100 @@ QVariant DebuggerKitInformation::defaultValue(Kit *k) const
// CDB for windows:
if (abi.os() == Abi::WindowsOS && abi.osFlavor() != Abi::WindowsMSysFlavor) {
QPair<QString, QString> cdbs = autoDetectCdbDebugger();
return (abi.wordWidth() == 32) ? cdbs.first : cdbs.second;
result.binary = Utils::FileName::fromString(abi.wordWidth() == 32 ? cdbs.first : cdbs.second);
result.engineType = CdbEngineType;
return result;
}
// fall back to system GDB:
QString debugger = QLatin1String("gdb");
// Check suggestions from the SDK.
const Environment env = Environment::systemEnvironment();
if (tc) {
// Check suggestions from the SDK:
const QString path = tc->suggestedDebugger().toString();
QString path = tc->suggestedDebugger().toString();
if (!path.isEmpty()) {
QFileInfo fi(path);
if (fi.isAbsolute())
return path;
debugger = path;
const QFileInfo fi(path);
if (!fi.isAbsolute())
path = env.searchInPath(path);
result.binary = Utils::FileName::fromString(path);
result.engineType = engineTypeFromBinary(path);
return result;
}
}
Environment env = Environment::systemEnvironment();
return env.searchInPath(debugger);
// Default to GDB, system GDB
result.engineType = GdbEngineType;
QString gdb;
const QString systemGdb = QLatin1String("gdb");
// MinGW: Search for the python-enabled gdb first.
if (abi.os() == Abi::WindowsOS && abi.osFlavor() == Abi::WindowsMSysFlavor)
gdb = env.searchInPath(QLatin1String("gdb-i686-pc-mingw32"));
if (gdb.isEmpty())
gdb = env.searchInPath(systemGdb);
result.binary = Utils::FileName::fromString(env.searchInPath(gdb.isEmpty() ? systemGdb : gdb));
return result;
}
QList<Task> DebuggerKitInformation::validate(Kit *k) const
// Check the configuration errors and return a flag mask. Provide a quick check and
// a verbose one with a list of errors.
enum DebuggerConfigurationErrors {
NoDebugger = 0x1,
DebuggerNotFound = 0x2,
DebuggerNotExecutable = 0x4,
DebuggerNeedsAbsolutePath = 0x8
};
static unsigned debuggerConfigurationErrors(const ProjectExplorer::Kit *p)
{
const Core::Id id(Constants::TASK_CATEGORY_BUILDSYSTEM);
QList<Task> result;
FileName dbg = debuggerCommand(k);
if (dbg.isEmpty()) {
result << Task(Task::Warning, tr("No debugger set up."), FileName(), -1, id);
return result;
unsigned result = 0;
const DebuggerKitInformation::DebuggerItem item = DebuggerKitInformation::debuggerItem(p);
if (item.engineType == NoEngineType || item.binary.isEmpty())
return NoDebugger;
const QFileInfo fi = item.binary.toFileInfo();
if (!fi.exists() || fi.isDir()) {
result |= DebuggerNotFound;
} else if (!fi.isExecutable()) {
result |= DebuggerNotExecutable;
}
QFileInfo fi = dbg.toFileInfo();
if (!fi.exists() || fi.isDir())
result << Task(Task::Error, tr("Debugger not found."), FileName(), -1, id);
else if (!fi.isExecutable())
result << Task(Task::Error, tr("Debugger not exectutable."), FileName(), -1, id);
if (ToolChain *tc = ToolChainKitInformation::toolChain(k)) {
// We need an absolute path to be able to locate Python on Windows.
const Abi abi = tc->targetAbi();
if (abi.os() == Abi::WindowsOS && !fi.isAbsolute()) {
result << Task(Task::Error, tr("The debugger location must be given as an "
"absolute path (%1).").arg(dbg.toString()), FileName(), -1, id);
}
// FIXME: Make sure debugger matches toolchain.
// if (isCdb()) {
// if (abi.binaryFormat() != Abi::PEFormat || abi.os() != Abi::WindowsOS) {
// result << Task(Tas->errorDetails.push_back(CdbEngine::tr("The CDB debug engine does not support the %1 ABI.").
// arg(abi.toString()));
// return false;
// }
// }
}
if (item.engineType == GdbEngineType)
if (const ToolChain *tc = ToolChainKitInformation::toolChain(p))
if (tc->targetAbi().os() == Abi::WindowsOS && !fi.isAbsolute())
result |= DebuggerNeedsAbsolutePath;
return result;
}
bool DebuggerKitInformation::isValidDebugger(const ProjectExplorer::Kit *p)
{
return debuggerConfigurationErrors(p) == 0;
}
QList<ProjectExplorer::Task> DebuggerKitInformation::validateDebugger(const ProjectExplorer::Kit *p)
{
const unsigned errors = debuggerConfigurationErrors(p);
const Core::Id id(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
QList<Task> result;
if (errors & NoDebugger)
result << Task(Task::Warning, tr("No debugger set up."), FileName(), -1, id);
if (errors & DebuggerNotFound) {
const QString path = DebuggerKitInformation::debuggerCommand(p).toUserOutput();
result << Task(Task::Error, tr("Debugger '%1' not found.").arg(path),
FileName(), -1, id);
}
if (errors & DebuggerNotExecutable) {
const QString path = DebuggerKitInformation::debuggerCommand(p).toUserOutput();
result << Task(Task::Error, tr("Debugger '%1' not executable.").arg(path), FileName(), -1, id);
}
if (errors & DebuggerNeedsAbsolutePath) {
const QString path = DebuggerKitInformation::debuggerCommand(p).toUserOutput();
const QString message =
tr("The debugger location must be given as an "
"absolute path (%1).").arg(path);
result << Task(Task::Error, message, FileName(), -1, id);
}
return result;
}
......@@ -207,20 +269,81 @@ KitConfigWidget *DebuggerKitInformation::createConfigWidget(Kit *k) const
return new Internal::DebuggerKitConfigWidget(k, this);
}
QString DebuggerKitInformation::userOutput(const ProjectExplorer::Kit *k)
{
const DebuggerItem item = DebuggerKitInformation::debuggerItem(k);
return tr("%1 using '%2'").arg(debuggerEngineName(item.engineType),
item.binary.toUserOutput());
}
KitInformation::ItemList DebuggerKitInformation::toUserOutput(Kit *k) const
{
return ItemList() << qMakePair(tr("Debugger"), debuggerCommand(k).toUserOutput());
return ItemList() << qMakePair(tr("Debugger"), DebuggerKitInformation::userOutput(k));
}
static const char engineTypeKeyC[] = "EngineType";
static const char binaryKeyC[] = "Binary";
DebuggerKitInformation::DebuggerItem DebuggerKitInformation::variantToItem(const QVariant &v)
{
DebuggerItem result;
if (v.type() == QVariant::String) { // Convert legacy config items, remove later.
const QString binary = v.toString();
result.binary = Utils::FileName::fromString(binary);
result.engineType = engineTypeFromBinary(binary);
return result;
}
QTC_ASSERT(v.type() == QVariant::Map, return result);
const QVariantMap vmap = v.toMap();
result.binary = Utils::FileName::fromString(vmap.value(QLatin1String(binaryKeyC)).toString());
result.engineType = static_cast<DebuggerEngineType>(vmap.value(QLatin1String(engineTypeKeyC)).toInt());
return result;
}
FileName DebuggerKitInformation::debuggerCommand(const Kit *k)
QVariant DebuggerKitInformation::itemToVariant(const DebuggerItem &i)
{
return FileName::fromString(k ? k->value(Core::Id(DEBUGGER_INFORMATION)).toString() : QString());
QVariantMap vmap;
vmap.insert(QLatin1String(binaryKeyC), QVariant(i.binary.toUserOutput()));
vmap.insert(QLatin1String(engineTypeKeyC), QVariant(int(i.engineType)));
return QVariant(vmap);
}
void DebuggerKitInformation::setDebuggerCommand(Kit *k, const FileName &command)
DebuggerKitInformation::DebuggerItem DebuggerKitInformation::debuggerItem(const ProjectExplorer::Kit *p)
{
QTC_ASSERT(k, return);
k->setValue(Core::Id(DEBUGGER_INFORMATION), command.toString());
return p ?
DebuggerKitInformation::variantToItem(p->value(Core::Id(DEBUGGER_INFORMATION))) :
DebuggerItem();
}
void DebuggerKitInformation::setDebuggerItem(ProjectExplorer::Kit *p, const DebuggerItem &item)
{
QTC_ASSERT(p, return);
p->setValue(Core::Id(DEBUGGER_INFORMATION), itemToVariant(item));
}
void DebuggerKitInformation::setDebuggerCommand(ProjectExplorer::Kit *k, const FileName &command)
{
setDebuggerItem(k, DebuggerItem(engineType(k), command));
}
void DebuggerKitInformation::setEngineType(ProjectExplorer::Kit *p, DebuggerEngineType type)
{
setDebuggerItem(p, DebuggerItem(type, debuggerCommand(p)));
}
QString DebuggerKitInformation::debuggerEngineName(DebuggerEngineType t)
{
switch (t) {
case Debugger::GdbEngineType:
return tr("GDB Engine");
case Debugger::CdbEngineType:
return tr("CDB Engine");
case Debugger::LldbEngineType:
return tr("LLDB Engine");
default:
break;
}
return QString();
}
} // namespace Debugger
......@@ -32,6 +32,7 @@
#define DEBUGGER_DEBUGGERKITINFORMATION_H
#include "debugger_global.h"
#include "debuggerconstants.h"
#include <projectexplorer/kitinformation.h>
......@@ -42,22 +43,54 @@ class DEBUGGER_EXPORT DebuggerKitInformation : public ProjectExplorer::KitInform
Q_OBJECT
public:
class DEBUGGER_EXPORT DebuggerItem {
public:
DebuggerItem();
DebuggerItem(DebuggerEngineType engineType, const Utils::FileName &fn);
DebuggerEngineType engineType;
Utils::FileName binary;
};
DebuggerKitInformation();
Core::Id dataId() const;
unsigned int priority() const; // the higher the closer to the top.
QVariant defaultValue(ProjectExplorer::Kit *k) const;
static DebuggerItem autoDetectItem(const ProjectExplorer::Kit *k);
QVariant defaultValue(ProjectExplorer::Kit *k) const
{ return DebuggerKitInformation::itemToVariant(DebuggerKitInformation::autoDetectItem(k)); }
QList<ProjectExplorer::Task> validate(ProjectExplorer::Kit *k) const
{ return DebuggerKitInformation::validateDebugger(k); }
QList<ProjectExplorer::Task> validate(ProjectExplorer::Kit *k) const;
static QList<ProjectExplorer::Task> validateDebugger(const ProjectExplorer::Kit *p);
static bool isValidDebugger(const ProjectExplorer::Kit *p);
ProjectExplorer::KitConfigWidget *createConfigWidget(ProjectExplorer::Kit *k) const;
ItemList toUserOutput(ProjectExplorer::Kit *k) const;
static QString userOutput(const ProjectExplorer::Kit *k);
static DebuggerItem debuggerItem(const ProjectExplorer::Kit *p);
static void setDebuggerItem(ProjectExplorer::Kit *p, const DebuggerItem &item);
static Utils::FileName debuggerCommand(const ProjectExplorer::Kit *p)
{ return debuggerItem(p).binary; }
static void setDebuggerCommand(ProjectExplorer::Kit *p, const Utils::FileName &command);
static DebuggerEngineType engineType(const ProjectExplorer::Kit *p)
{ return debuggerItem(p).engineType; }
static void setEngineType(ProjectExplorer::Kit *p, DebuggerEngineType type);
static QString debuggerEngineName(DebuggerEngineType t);
static Utils::FileName debuggerCommand(const ProjectExplorer::Kit *k);
static void setDebuggerCommand(ProjectExplorer::Kit *k, const Utils::FileName &command);
private:
static DebuggerItem variantToItem(const QVariant &v);
static QVariant itemToVariant(const DebuggerItem &i);
};
} // namespace Debugger
......
......@@ -567,8 +567,10 @@ public:
explicit AbiKitMatcher(const QList<Abi> &abis) : m_abis(abis) {}
bool matches(const Kit *p) const
{
if (const ToolChain *tc = ToolChainKitInformation::toolChain(p))
return m_abis.contains(tc->targetAbi());
if (const ToolChain *tc = ToolChainKitInformation::toolChain(p)) {
return m_abis.contains(tc->targetAbi())
&& DebuggerKitInformation::isValidDebugger(p);
}
return false;
}
......@@ -584,7 +586,7 @@ public:
{
if (const ToolChain *tc = ToolChainKitInformation::toolChain(p))
foreach (const Abi &a, m_abis)
if (a.isCompatibleWith(tc->targetAbi()))
if (a.isCompatibleWith(tc->targetAbi()) && DebuggerKitInformation::isValidDebugger(p))