forked from qt-creator/qt-creator
Toolchains: Add debugger autodetection.
Clean up code.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
// Create 64bit
|
||||
QScopedPointer<GccToolChain> tc(createToolChain(true));
|
||||
if (tc.isNull())
|
||||
return result;
|
||||
|
||||
GccToolChain *tc = createToolChain(true);
|
||||
if (!tc)
|
||||
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;
|
||||
|
Reference in New Issue
Block a user