diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index e9ecec13866c946dc6053d4de7619a8392e479a8..b34f149ea66121afcedbd8709c4122ba00b3e311 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -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() diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index 6fcd5c93124cc62a5890216427f458004c8a2da5..e350e857361708e8d3274c96c36566c04daa5aae 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -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; }; diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 1a166d0707c188fa6274a2be0e2f04dc16a69776..0648d8c8eed7e3a308f46425f20e37b6e999399b 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -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 diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index dde66f60633f6f28f982357e91363aa4bf185b5a..32f023c97145cb7acc80ba0005a7f850ba15f14a 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -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 diff --git a/src/plugins/projectexplorer/toolchainconfigwidget.cpp b/src/plugins/projectexplorer/toolchainconfigwidget.cpp index b4997252ded6a177cf6a2fad9c7f16a658585066..50ff46a0afbedf4940afddca135b4e386a22da65 100644 --- a/src/plugins/projectexplorer/toolchainconfigwidget.cpp +++ b/src/plugins/projectexplorer/toolchainconfigwidget.cpp @@ -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 diff --git a/src/plugins/projectexplorer/toolchainconfigwidget.h b/src/plugins/projectexplorer/toolchainconfigwidget.h index cfd11f2d849c584d371cc0143c133a9ff0a516ab..c4dd1ba2d83517ff09878927992fa41550356734 100644 --- a/src/plugins/projectexplorer/toolchainconfigwidget.h +++ b/src/plugins/projectexplorer/toolchainconfigwidget.h @@ -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); diff --git a/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.cpp b/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.cpp index 52eb1f8169b12745f18463257fa4551cd6a3c683..8ca13dff5721ee3288931673374f166f6c5a5192 100644 --- a/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.cpp @@ -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; diff --git a/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.h b/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.h index 95a23a1e616d82771d7897ed4fb21f35c6063fb0..e78528cee36ddec5ac0394dfac4329f7dfe06197 100644 --- a/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.h +++ b/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.h @@ -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;