Commit adb4ce20 authored by Friedemann Kleint's avatar Friedemann Kleint

Toolchains: Add debugger autodetection.

Clean up code.
parent ad3bac6a
......@@ -38,11 +38,13 @@
#include <utils/environment.h>
#include <utils/synchronousprocess.h>
#include <utils/qtcassert.h>
#include <QtCore/QBuffer>
#include <QtCore/QCoreApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QProcess>
#include <QtCore/QScopedPointer>
#include <QtGui/QFormLayout>
#include <QtGui/QLabel>
......@@ -456,7 +458,12 @@ ToolChain *Internal::GccToolChainFactory::create()
QList<ToolChain *> Internal::GccToolChainFactory::autoDetect()
{
return autoDetectCompiler(QLatin1String("gcc"), Abi::hostAbi());
QStringList debuggers;
#ifdef Q_OS_MAC
// Fixme Prefer lldb once it is implemented: debuggers.push_back(QLatin1String("lldb"));
#endif
debuggers.push_back(QLatin1String("gdb"));
return autoDetectToolchains(QLatin1String("gcc"), debuggers, Abi::hostAbi());
}
// Used by the ToolChainManager to restore user-generated ToolChains
......@@ -480,36 +487,46 @@ GccToolChain *Internal::GccToolChainFactory::createToolChain(bool autoDetect)
return new GccToolChain(autoDetect);
}
QList<ToolChain *> Internal::GccToolChainFactory::autoDetectCompiler(const QString &cc, const Abi &requiredAbi)
QList<ToolChain *> Internal::GccToolChainFactory::autoDetectToolchains(const QString &compiler,
const QStringList &debuggers,
const Abi &requiredAbi)
{
QList<ToolChain *> result;
QString path = Utils::Environment::systemEnvironment().searchInPath(cc);
if (path.isEmpty())
const Utils::Environment systemEnvironment = Utils::Environment::systemEnvironment();
const QString compilerPath = systemEnvironment.searchInPath(compiler);
if (compilerPath.isEmpty())
return result;
QString debuggerPath; // Find the first debugger
foreach (const QString &debugger, debuggers) {
debuggerPath = systemEnvironment.searchInPath(debugger);
if (!debuggerPath.isEmpty())
break;
}
GccToolChain *tc = createToolChain(true);
if (!tc)
// Create 64bit
QScopedPointer<GccToolChain> tc(createToolChain(true));
if (tc.isNull())
return result;
tc->setCompilerPath(path);
ProjectExplorer::Abi abi = tc->targetAbi();
tc->setCompilerPath(compilerPath);
tc->setDebuggerCommand(debuggerPath);
const ProjectExplorer::Abi abi = tc->targetAbi();
if (abi.isValid() && abi == requiredAbi)
result.append(tc);
else
delete tc;
result.append(tc.take());
if (abi.wordWidth() != 64)
return result;
tc = createToolChain(true);
Q_ASSERT(tc); // worked once, so should work again:-)
// Create 32bit
tc.reset(createToolChain(true));
QTC_ASSERT(!tc.isNull(), return result; ); // worked once, so should work again:-)
tc->forceTo32Bit(true);
tc->setCompilerPath(path);
tc->setCompilerPath(compilerPath);
tc->setDebuggerCommand(debuggerPath);
if (tc->targetAbi().isValid())
result.append(tc);
else
delete tc;
result.append(tc.take());
return result;
}
......@@ -537,8 +554,9 @@ Internal::GccToolChainConfigWidget::GccToolChainConfigWidget(GccToolChain *tc) :
connect(m_force32BitCheckBox, SIGNAL(toggled(bool)), this, SLOT(handle32BitChange()));
addDebuggerCommandControls(layout, gnuVersionArgs);
addErrorLabel(layout);
discard();
setFromToolchain();
}
void Internal::GccToolChainConfigWidget::apply()
......@@ -558,7 +576,7 @@ void Internal::GccToolChainConfigWidget::apply()
tc->setDebuggerCommand(debuggerCommand());
}
void Internal::GccToolChainConfigWidget::discard()
void Internal::GccToolChainConfigWidget::setFromToolchain()
{
GccToolChain *tc = static_cast<GccToolChain *>(toolChain());
Q_ASSERT(tc);
......@@ -634,7 +652,7 @@ QString Internal::MingwToolChainFactory::id() const
QList<ToolChain *> Internal::MingwToolChainFactory::autoDetect()
{
return autoDetectCompiler(QLatin1String("gcc"), Abi::hostAbi());
return autoDetectToolchains(QLatin1String("gcc"), QStringList(), Abi::hostAbi());
}
bool Internal::MingwToolChainFactory::canCreate()
......@@ -706,7 +724,9 @@ QString Internal::LinuxIccToolChainFactory::id() const
QList<ToolChain *> Internal::LinuxIccToolChainFactory::autoDetect()
{
return autoDetectCompiler(QLatin1String("icpc"), Abi::hostAbi());
return autoDetectToolchains(QLatin1String("icpc"),
QStringList(QLatin1String("gdb")),
Abi::hostAbi());
}
ToolChain *Internal::LinuxIccToolChainFactory::create()
......
......@@ -143,7 +143,9 @@ public:
protected:
virtual GccToolChain *createToolChain(bool autoDetect);
QList<ToolChain *> autoDetectCompiler(const QString &path, const Abi &);
QList<ToolChain *> autoDetectToolchains(const QString &compiler,
const QStringList &debuggers,
const Abi &);
};
} // namespace Internal
......@@ -161,7 +163,7 @@ class GccToolChainConfigWidget : public ToolChainConfigWidget
public:
GccToolChainConfigWidget(GccToolChain *);
void apply();
void discard();
void discard() { setFromToolchain(); }
bool isDirty() const;
private slots:
......@@ -169,6 +171,8 @@ private slots:
void handle32BitChange();
private:
void setFromToolchain();
Utils::PathChooser *m_compilerPath;
QCheckBox *m_force32BitCheckBox;
};
......
......@@ -403,12 +403,12 @@ ToolChainConfigWidget *MsvcToolChain::configurationWidget()
bool MsvcToolChain::canClone() const
{
return false;
return true;
}
ToolChain *MsvcToolChain::clone() const
{
return 0;
return new MsvcToolChain(*this);
}
// --------------------------------------------------------------------------
......@@ -420,7 +420,10 @@ MsvcToolChainConfigWidget::MsvcToolChainConfigWidget(ToolChain *tc) :
{
QFormLayout *formLayout = new QFormLayout(this);
formLayout->addRow(new QLabel(tc->displayName()));
addDebuggerCommandControls(formLayout);
addDebuggerCommandControls(formLayout, QStringList(QLatin1String("-version")));
addDebuggerAutoDetection(this, SLOT(autoDetectDebugger()));
addErrorLabel(formLayout);
setFromToolChain();
}
void MsvcToolChainConfigWidget::apply()
......@@ -430,7 +433,7 @@ void MsvcToolChainConfigWidget::apply()
tc->setDebuggerCommand(debuggerCommand());
}
void MsvcToolChainConfigWidget::discard()
void MsvcToolChainConfigWidget::setFromToolChain()
{
MsvcToolChain *tc = static_cast<MsvcToolChain *>(toolChain());
QTC_ASSERT(tc, return);
......@@ -444,6 +447,22 @@ bool MsvcToolChainConfigWidget::isDirty() const
return debuggerCommand() != tc->debuggerCommand();
}
void MsvcToolChainConfigWidget::autoDetectDebugger()
{
QStringList directories;
const QString cdbExecutable = MsvcToolChain::autoDetectCdbDebugger(&directories);
if (cdbExecutable.isEmpty()) {
const QString msg = tr("The CDB debugger could not be found in %1").arg(directories.join(QLatin1String(", ")));
setErrorMessage(msg);
} else {
clearErrorMessage();
if (cdbExecutable != debuggerCommand()) {
setDebuggerCommand(cdbExecutable);
emitDirty();
}
}
}
// --------------------------------------------------------------------------
// MsvcToolChainFactory
// --------------------------------------------------------------------------
......@@ -552,8 +571,71 @@ QList<ToolChain *> MsvcToolChainFactory::autoDetect()
}
}
#endif
if (!results.isEmpty()) { // Detect debugger
const QString cdbDebugger = MsvcToolChain::autoDetectCdbDebugger();
if (!cdbDebugger.isEmpty()) {
foreach (ToolChain *tc, results)
static_cast<MsvcToolChain *>(tc)->setDebuggerCommand(cdbDebugger);
}
}
return results;
}
// Check the CDB executable and accumulate the list of checked paths
// for reporting.
static QString checkCdbExecutable(const QString &programDir, const QString &postfix,
QStringList *checkedDirectories = 0)
{
QString executable = programDir;
executable += QLatin1String("/Debugging Tools For Windows");
executable += postfix;
if (checkedDirectories)
checkedDirectories->push_back(QDir::toNativeSeparators(executable));
executable += QLatin1String("/cdb.exe");
const QFileInfo fi(executable);
return fi.isFile() && fi.isExecutable() ? fi.absoluteFilePath() : QString();
}
QString MsvcToolChain::autoDetectCdbDebugger(QStringList *checkedDirectories /* = 0 */)
{
// Look for $ProgramFiles/"Debugging Tools For Windows <bit-idy>/cdb.exe" and its
// " (x86)", " (x64)" variations.
static const char *postFixes[] = {"", " (x64)", " 64-bit", " (x86)", " (x32)" };
if (checkedDirectories)
checkedDirectories->clear();
const QString programDir = QString::fromLocal8Bit(qgetenv("ProgramFiles"));
if (programDir.isEmpty())
return QString();
// Try the post fixes
QString outPath;
for (unsigned i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) {
outPath = checkCdbExecutable(programDir, QLatin1String(postFixes[i]), checkedDirectories);
if (!outPath.isEmpty())
return outPath;
}
// A 32bit-compile running on a 64bit system sees the 64 bit installation
// as "$ProgramFiles (x64)/Debugging Tools..." and (untested), a 64 bit-
// compile running on a 64bit system sees the 32 bit installation as
// "$ProgramFiles (x86)/Debugging Tools..." (assuming this works at all)
#ifdef Q_OS_WIN64
outPath = checkCdbExecutable(programDir + QLatin1String(" (x32)"), QString(), checkedDirectories);
if (!outPath.isEmpty())
return QString();
#else
// A 32bit process on 64 bit sees "ProgramFiles\Debg.. (x64)"
if (programDir.endsWith(QLatin1String(" (x86)"))) {
outPath = checkCdbExecutable(programDir.left(programDir.size() - 6),
QLatin1String(" (x64)"), checkedDirectories);
if (!outPath.isEmpty())
return QString();
}
#endif
return QString();
}
} // namespace Internal
} // namespace ProjectExplorer
......@@ -76,6 +76,8 @@ public:
bool canClone() const;
ToolChain *clone() const;
static QString autoDetectCdbDebugger(QStringList *checkedDirectories = 0);
private:
QString m_varsBat; // Script to setup environment
QString m_varsBatArg; // Argument
......@@ -117,8 +119,14 @@ public:
MsvcToolChainConfigWidget(ToolChain *);
void apply();
void discard();
void discard() { setFromToolChain(); }
bool isDirty() const;
private slots:
void autoDetectDebugger();
private:
void setFromToolChain();
};
} // namespace Internal
......
......@@ -53,7 +53,7 @@ class ToolChainConfigWidgetPrivate
{
public:
ToolChainConfigWidgetPrivate(ToolChain *tc) :
m_toolChain(tc), m_debuggerPathChooser(0)
m_toolChain(tc), m_debuggerPathChooser(0), m_errorLabel(0)
{
Q_ASSERT(tc);
}
......@@ -62,6 +62,7 @@ public:
ToolChain *m_toolChain;
Utils::PathChooser *m_debuggerPathChooser;
QLabel *m_errorLabel;
};
} // namespace Internal
......@@ -119,6 +120,12 @@ void ToolChainConfigWidget::ensureDebuggerPathChooser(const QStringList &version
connect(m_d->m_debuggerPathChooser, SIGNAL(changed(QString)), this, SLOT(emitDirty()));
}
void ToolChainConfigWidget::addDebuggerAutoDetection(QObject *receiver, const char *autoDetectSlot)
{
QTC_ASSERT(m_d->m_debuggerPathChooser, return; )
m_d->m_debuggerPathChooser->addButton(tr("Autodetect"), receiver, autoDetectSlot);
}
QString ToolChainConfigWidget::debuggerCommand() const
{
QTC_ASSERT(m_d->m_debuggerPathChooser, return QString(); )
......@@ -131,4 +138,43 @@ void ToolChainConfigWidget::setDebuggerCommand(const QString &d)
m_d->m_debuggerPathChooser->setPath(d);
}
void ToolChainConfigWidget::addErrorLabel(QFormLayout *lt)
{
if (!m_d->m_errorLabel) {
m_d->m_errorLabel = new QLabel;
m_d->m_errorLabel->setVisible(false);
}
lt->addRow(m_d->m_errorLabel);
}
void ToolChainConfigWidget::addErrorLabel(QGridLayout *lt, int row, int column, int colSpan)
{
if (!m_d->m_errorLabel) {
m_d->m_errorLabel = new QLabel;
m_d->m_errorLabel->setVisible(false);
}
lt->addWidget(m_d->m_errorLabel, row, column, 1, colSpan);
}
void ToolChainConfigWidget::setErrorMessage(const QString &m)
{
QTC_ASSERT(m_d->m_errorLabel, return; )
if (m.isEmpty()) {
clearErrorMessage();
} else {
m_d->m_errorLabel->setText(m);
m_d->m_errorLabel->setStyleSheet(QLatin1String("background-color: \"red\""));
m_d->m_errorLabel->setVisible(true);
}
}
void ToolChainConfigWidget::clearErrorMessage()
{
QTC_ASSERT(m_d->m_errorLabel, return; )
m_d->m_errorLabel->clear();
m_d->m_errorLabel->setStyleSheet(QString());
m_d->m_errorLabel->setVisible(false);
}
} // namespace ProjectExplorer
......@@ -73,6 +73,8 @@ signals:
protected slots:
void emitDirty();
void setErrorMessage(const QString &);
void clearErrorMessage();
protected:
void addDebuggerCommandControls(QFormLayout *lt,
......@@ -80,6 +82,9 @@ protected:
void addDebuggerCommandControls(QGridLayout *lt,
int row = 0, int column = 0,
const QStringList &versionArguments = QStringList());
void addDebuggerAutoDetection(QObject *receiver, const char *autoDetectSlot);
void addErrorLabel(QFormLayout *lt);
void addErrorLabel(QGridLayout *lt, int row = 0, int column = 0, int colSpan = 1);
QString debuggerCommand() const;
void setDebuggerCommand(const QString &d);
......
......@@ -358,15 +358,15 @@ RvctToolChainConfigWidget::RvctToolChainConfigWidget(RvctToolChain *tc) :
m_ui->environmentView->setModel(m_model);
m_ui->environmentView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
m_ui->environmentView->horizontalHeader()->setStretchLastSection(true);
connect(m_model, SIGNAL(userChangesChanged()), this, SLOT(makeDirty()));
connect(m_model, SIGNAL(userChangesChanged()), this, SLOT(emitDirty()));
m_ui->compilerPath->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_ui->compilerPath->setPath(tc->compilerPath());
connect(m_ui->compilerPath, SIGNAL(changed(QString)), this, SLOT(makeDirty()));
connect(m_ui->compilerPath, SIGNAL(changed(QString)), this, SLOT(emitDirty()));
m_ui->versionComboBox->setCurrentIndex(static_cast<int>(tc->armVersion()));
connect(m_ui->versionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(makeDirty()));
connect(m_ui->versionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(emitDirty()));
discard();
setFromToolChain();
}
void RvctToolChainConfigWidget::apply()
......@@ -382,7 +382,7 @@ void RvctToolChainConfigWidget::apply()
m_model->setUserChanges(changes);
}
void RvctToolChainConfigWidget::discard()
void RvctToolChainConfigWidget::setFromToolChain()
{
RvctToolChain *tc = static_cast<RvctToolChain *>(toolChain());
Q_ASSERT(tc);
......@@ -403,11 +403,6 @@ bool RvctToolChainConfigWidget::isDirty() const
|| tc->environmentChanges() != environmentChanges();
}
void RvctToolChainConfigWidget::makeDirty()
{
emit dirty(toolChain());
}
QList<Utils::EnvironmentItem> RvctToolChainConfigWidget::environmentChanges() const
{
Utils::Environment baseEnv;
......
......@@ -139,13 +139,11 @@ public:
RvctToolChainConfigWidget(RvctToolChain *tc);
void apply();
void discard();
void discard() { setFromToolChain(); }
bool isDirty() const;
private slots:
void makeDirty();
private:
void setFromToolChain();
QList<Utils::EnvironmentItem> environmentChanges() const;
Ui::RvctToolChainConfigWidget *m_ui;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment