From f5909abe09a10bfba5db1b34908203c0c1b9af60 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Fri, 8 Oct 2010 15:13:02 +0200
Subject: [PATCH] Debugging helpers: Fix building
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Report errors correctly.
- Do not pass empty target argument to qmake
- Give 'make' a longer timeout and change timeout checking to
  trigger after last output line was obtained from process
- Make build log dialog non-modal and ensure it pops up on failure
  even if a different Qt version was selected in-between
- Disable Rebuild-button while build is running.

Reviewed-by: Kai Köhne <kai.koehne@nokia.com>
Reviewed-by: Lasse Holmstedt <lasse.holmstedt@nokia.com>
---
 src/libs/utils/buildablehelperlibrary.cpp     | 139 +++++++++++++-----
 src/libs/utils/buildablehelperlibrary.h       |   9 +-
 .../projectexplorer/debugginghelper.cpp       |   7 +-
 src/plugins/projectexplorer/debugginghelper.h |   7 +-
 src/plugins/qt4projectmanager/qmldumptool.cpp |  31 ++--
 src/plugins/qt4projectmanager/qmldumptool.h   |   7 +-
 .../qt4projectmanager/qmlobservertool.cpp     |  10 +-
 .../qt4projectmanager/qmlobservertool.h       |   7 +-
 .../qt4projectmanager/qtoptionspage.cpp       |  81 +++++++---
 src/plugins/qt4projectmanager/qtoptionspage.h |   5 +-
 .../qt4projectmanager/qtversionmanager.cpp    |  84 ++++++-----
 .../qt4projectmanager/qtversionmanager.h      |   3 +-
 src/plugins/qt4projectmanager/showbuildlog.ui |   2 +-
 13 files changed, 260 insertions(+), 132 deletions(-)

diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp
index 9a761e016af..3fa6ca97cfb 100644
--- a/src/libs/utils/buildablehelperlibrary.cpp
+++ b/src/libs/utils/buildablehelperlibrary.cpp
@@ -171,12 +171,79 @@ bool BuildableHelperLibrary::copyFiles(const QString &sourcePath,
     return true;
 }
 
-QString BuildableHelperLibrary::buildHelper(const QString &helperName, const QString &proFilename,
-                                            const QString &directory, const QString &makeCommand,
-                                            const QString &qmakeCommand, const QString &mkspec,
-                                            const Utils::Environment &env, const QString &targetMode)
+// Helper: Run a build process with merged stdout/stderr
+static inline bool runBuildProcessI(QProcess &proc,
+                                    const QString &binary,
+                                    const QStringList &args,
+                                    int timeoutMS,
+                                    bool ignoreNonNullExitCode,
+                                    QString *output, QString *errorMessage)
+{
+    proc.start(binary, args);
+    if (!proc.waitForStarted()) {
+        *errorMessage = QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
+                                                    "Cannot start process: %1").
+                                                    arg(proc.errorString());
+        return false;
+    }
+    // Read stdout/err and check for timeouts
+    QByteArray stdOut;
+    QByteArray stdErr;
+    if (!SynchronousProcess::readDataFromProcess(proc, timeoutMS, &stdOut, &stdErr, false)) {
+        *errorMessage = QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
+                                                    "Timeout after %1s.").
+                                                    arg(timeoutMS / 1000);
+        SynchronousProcess::stopProcess(proc);
+        return false;
+    }
+    if (proc.exitStatus() != QProcess::NormalExit) {
+        *errorMessage = QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
+                                                    "The process crashed.");
+        return false;
+    }
+    const QString stdOutS = QString::fromLocal8Bit(stdOut);
+    if (!ignoreNonNullExitCode && proc.exitCode() != 0) {
+            *errorMessage = QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
+                                                        "The process returned exit code %1:\n%2").
+                                                         arg(proc.exitCode()).arg(stdOutS);
+        return false;
+    }
+    output->append(stdOutS);
+    return true;
+}
+
+// Run a build process with merged stdout/stderr and qWarn about errors.
+static bool runBuildProcess(QProcess &proc,
+                            const QString &binary,
+                            const QStringList &args,
+                            int timeoutMS,
+                            bool ignoreNonNullExitCode,
+                            QString *output, QString *errorMessage)
+{
+    const bool rc = runBuildProcessI(proc, binary, args, timeoutMS, ignoreNonNullExitCode, output, errorMessage);
+    if (!rc) {
+        // Fail - reformat error.
+        QString cmd = binary;
+        if (!args.isEmpty()) {
+            cmd += QLatin1Char(' ');
+            cmd += args.join(QString(QLatin1Char(' ')));
+        }
+        *errorMessage =
+                QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
+                                            "Error running '%1' in %2: %3").
+                                            arg(cmd, proc.workingDirectory(), *errorMessage);
+        qWarning("%s", qPrintable(*errorMessage));
+    }
+    return rc;
+}
+
+
+bool BuildableHelperLibrary::buildHelper(const QString &helperName, const QString &proFilename,
+                                         const QString &directory, const QString &makeCommand,
+                                         const QString &qmakeCommand, const QString &mkspec,
+                                         const Utils::Environment &env, const QString &targetMode,
+                                         QString *output, QString *errorMessage)
 {
-    QString output;
     const QChar newline = QLatin1Char('\n');
     // Setup process
     QProcess proc;
@@ -184,45 +251,43 @@ QString BuildableHelperLibrary::buildHelper(const QString &helperName, const QSt
     proc.setWorkingDirectory(directory);
     proc.setProcessChannelMode(QProcess::MergedChannels);
 
-    output += QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
-                                          "Building helper library '%1' in %2\n").arg(helperName, directory);
-    output += newline;
+    output->append(QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
+                                          "Building helper library '%1' in %2\n").arg(helperName, directory));
+    output->append(newline);
 
     const QString makeFullPath = env.searchInPath(makeCommand);
     if (QFileInfo(directory + QLatin1String("/Makefile")).exists()) {
-        if (!makeFullPath.isEmpty()) {
-            const QString cleanTarget = QLatin1String("distclean");
-            output += QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
-                                                  "Running %1 %2...\n").arg(makeFullPath, cleanTarget);
-            proc.start(makeFullPath, QStringList(cleanTarget));
-            proc.waitForFinished();
-            output += QString::fromLocal8Bit(proc.readAll());
-        } else {
-            output += QCoreApplication::translate("ProjectExplorer::DebuggingHelperLibrary",
-                                                  "%1 not found in PATH\n").arg(makeCommand);
-            return output;
+        if (makeFullPath.isEmpty()) {
+            *errorMessage = QCoreApplication::translate("ProjectExplorer::DebuggingHelperLibrary",
+                                                       "%1 not found in PATH\n").arg(makeCommand);
+            return false;
         }
+        const QString cleanTarget = QLatin1String("distclean");
+        output->append(QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
+                                                   "Running %1 %2...\n").arg(makeFullPath, cleanTarget));
+        if (!runBuildProcess(proc, makeFullPath, QStringList(cleanTarget), 30000, true, output, errorMessage))
+            return false;
     }
-    output += newline;
-    output += QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary", "Running %1 ...\n").arg(qmakeCommand);
+    output->append(newline);
+    output->append(QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary", "Running %1 ...\n").arg(qmakeCommand));
 
-    QStringList makeArgs;
-    makeArgs << targetMode << QLatin1String("-spec") << (mkspec.isEmpty() ? QString(QLatin1String("default")) : mkspec) << proFilename;
-    proc.start(qmakeCommand, makeArgs);
-    proc.waitForFinished();
-
-    output += proc.readAll();
-
-    output += newline;;
-    if (!makeFullPath.isEmpty()) {
-        output += QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary", "Running %1 ...\n").arg(makeFullPath);
-        proc.start(makeFullPath, QStringList());
-        proc.waitForFinished(80000);
-        output += proc.readAll();
-    } else {
-        output += QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary", "%1 not found in PATH\n").arg(makeCommand);
+    QStringList qMakeArgs;
+    if (!targetMode.isEmpty())
+        qMakeArgs << targetMode;
+    if (!mkspec.isEmpty())
+        qMakeArgs << QLatin1String("-spec") << mkspec;
+    qMakeArgs << proFilename;
+    if (!runBuildProcess(proc, qmakeCommand, qMakeArgs, 30000, false, output, errorMessage))
+        return false;
+    output->append(newline);
+    if (makeFullPath.isEmpty()) {
+        *errorMessage = QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary", "%1 not found in PATH\n").arg(makeCommand);
+        return false;
     }
-    return output;
+    output->append(QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary", "Running %1 ...\n").arg(makeFullPath));
+    if (!runBuildProcess(proc, makeFullPath, QStringList(), 120000, false, output, errorMessage))
+        return false;
+    return true;
 }
 
 bool BuildableHelperLibrary::getHelperFileInfoFor(const QStringList &validBinaryFilenames,
diff --git a/src/libs/utils/buildablehelperlibrary.h b/src/libs/utils/buildablehelperlibrary.h
index fa8a85648c6..09615ce06af 100644
--- a/src/libs/utils/buildablehelperlibrary.h
+++ b/src/libs/utils/buildablehelperlibrary.h
@@ -33,10 +33,11 @@ public:
     static bool copyFiles(const QString &sourcePath, const QStringList &files,
                           const QString &targetDirectory, QString *errorMessage);
 
-    static QString buildHelper(const QString &helperName, const QString &proFilename,
-                               const QString &directory, const QString &makeCommand,
-                               const QString &qmakeCommand, const QString &mkspec,
-                               const Utils::Environment &env, const QString &targetMode);
+    static bool buildHelper(const QString &helperName, const QString &proFilename,
+                            const QString &directory, const QString &makeCommand,
+                            const QString &qmakeCommand, const QString &mkspec,
+                            const Utils::Environment &env, const QString &targetMode,
+                            QString *output, QString *errorMessage);
 
     static bool getHelperFileInfoFor(const QStringList &validBinaryFilenames,
                                      const QString &directory, QFileInfo* info);
diff --git a/src/plugins/projectexplorer/debugginghelper.cpp b/src/plugins/projectexplorer/debugginghelper.cpp
index 1fb2b9a488d..612ef096457 100644
--- a/src/plugins/projectexplorer/debugginghelper.cpp
+++ b/src/plugins/projectexplorer/debugginghelper.cpp
@@ -116,11 +116,12 @@ QString DebuggingHelperLibrary::copy(const QString &qtInstallData,
     return QString();
 }
 
-QString DebuggingHelperLibrary::build(const QString &directory, const QString &makeCommand,
+bool DebuggingHelperLibrary::build(const QString &directory, const QString &makeCommand,
                                       const QString &qmakeCommand, const QString &mkspec,
-                                      const Utils::Environment &env, const QString &targetMode)
+                                      const Utils::Environment &env, const QString &targetMode,
+                                      QString *output, QString *errorMessage)
 {
     return buildHelper(QCoreApplication::translate("ProjectExplorer::DebuggingHelperLibrary",
                                                    "GDB helper"), QLatin1String("gdbmacros.pro"), directory,
-                       makeCommand, qmakeCommand, mkspec, env, targetMode);
+                       makeCommand, qmakeCommand, mkspec, env, targetMode, output, errorMessage);
 }
diff --git a/src/plugins/projectexplorer/debugginghelper.h b/src/plugins/projectexplorer/debugginghelper.h
index 4185935d63f..38a4e40770b 100644
--- a/src/plugins/projectexplorer/debugginghelper.h
+++ b/src/plugins/projectexplorer/debugginghelper.h
@@ -47,9 +47,10 @@ public:
     static QStringList locationsByInstallData(const QString &qtInstallData);
 
     // Build the helpers and return the output log/errormessage.
-    static QString build(const QString &directory, const QString &makeCommand,
-                         const QString &qmakeCommand, const QString &mkspec,
-                         const Utils::Environment &env, const QString &targetMode);
+    static bool build(const QString &directory, const QString &makeCommand,
+                      const QString &qmakeCommand, const QString &mkspec,
+                      const Utils::Environment &env, const QString &targetMode,
+                      QString *output, QString *errorMessage);
 
     // Copy the source files to a target location and return the chosen target location.
     static QString copy(const QString &qtInstallData, QString *errorMessage);
diff --git a/src/plugins/qt4projectmanager/qmldumptool.cpp b/src/plugins/qt4projectmanager/qmldumptool.cpp
index af5e7f28122..7ca17122823 100644
--- a/src/plugins/qt4projectmanager/qmldumptool.cpp
+++ b/src/plugins/qt4projectmanager/qmldumptool.cpp
@@ -70,14 +70,19 @@ public:
     {
         future.setProgressRange(0, 5);
         future.setProgressValue(1);
-        const QString output = m_version.buildDebuggingHelperLibrary(future, true);
-
-        const QString qtInstallData = m_version.versionInfo().value("QT_INSTALL_DATA");
-        QString path = QmlDumpTool::toolByInstallData(qtInstallData);
-        if (path.isEmpty()) {
-            qWarning() << "Could not build QML plugin dumping helper for " << m_version.displayName()
-                       << "\nOutput:\n" << output;
-            m_failed = true;
+        QString output;
+        QString errorMessage;
+        QString path;
+        if (m_version.buildDebuggingHelperLibrary(future, true, &output, &errorMessage)) {
+            const QString qtInstallData = m_version.versionInfo().value("QT_INSTALL_DATA");
+            path = QmlDumpTool::toolByInstallData(qtInstallData);
+            if (path.isEmpty())
+                errorMessage = QString::fromLatin1("Could not build QML plugin dumping helper for %1\nOutput:\n%2").
+                               arg(m_version.displayName(), output);
+        }
+        m_failed = path.isEmpty();
+        if (m_failed) {
+            qWarning("%s", qPrintable(errorMessage));
         } else {
             // proceed in gui thread
             metaObject()->invokeMethod(this, "finish", Qt::QueuedConnection, Q_ARG(QString, path));
@@ -222,12 +227,14 @@ QStringList QmlDumpTool::locationsByInstallData(const QString &qtInstallData)
     return result;
 }
 
-QString QmlDumpTool::build(const QString &directory, const QString &makeCommand,
-                     const QString &qmakeCommand, const QString &mkspec,
-                     const Utils::Environment &env, const QString &targetMode)
+bool QmlDumpTool::build(const QString &directory, const QString &makeCommand,
+                        const QString &qmakeCommand, const QString &mkspec,
+                        const Utils::Environment &env, const QString &targetMode,
+                        QString *output,  QString *errorMessage)
 {
     return buildHelper(QCoreApplication::translate("Qt4ProjectManager::QmlDumpTool", "qmldump"), QLatin1String("qmldump.pro"),
-                       directory, makeCommand, qmakeCommand, mkspec, env, targetMode);
+                       directory, makeCommand, qmakeCommand, mkspec, env, targetMode,
+                       output, errorMessage);
 }
 
 QString QmlDumpTool::copy(const QString &qtInstallData, QString *errorMessage)
diff --git a/src/plugins/qt4projectmanager/qmldumptool.h b/src/plugins/qt4projectmanager/qmldumptool.h
index 6924690865b..13fbe483d35 100644
--- a/src/plugins/qt4projectmanager/qmldumptool.h
+++ b/src/plugins/qt4projectmanager/qmldumptool.h
@@ -53,9 +53,10 @@ public:
     static QStringList locationsByInstallData(const QString &qtInstallData);
 
     // Build the helpers and return the output log/errormessage.
-    static QString build(const QString &directory, const QString &makeCommand,
-                         const QString &qmakeCommand, const QString &mkspec,
-                         const Utils::Environment &env, const QString &targetMode);
+    static bool build(const QString &directory, const QString &makeCommand,
+                      const QString &qmakeCommand, const QString &mkspec,
+                      const Utils::Environment &env, const QString &targetMode,
+                      QString *output,  QString *errorMessage);
 
     // Copy the source files to a target location and return the chosen target location.
     static QString copy(const QString &qtInstallData, QString *errorMessage);
diff --git a/src/plugins/qt4projectmanager/qmlobservertool.cpp b/src/plugins/qt4projectmanager/qmlobservertool.cpp
index a9829aff31a..bb8d6615bb5 100644
--- a/src/plugins/qt4projectmanager/qmlobservertool.cpp
+++ b/src/plugins/qt4projectmanager/qmlobservertool.cpp
@@ -99,13 +99,15 @@ QStringList QmlObserverTool::locationsByInstallData(const QString &qtInstallData
     return result;
 }
 
-QString QmlObserverTool::build(const QString &directory, const QString &makeCommand,
-                     const QString &qmakeCommand, const QString &mkspec,
-                     const Utils::Environment &env, const QString &targetMode)
+bool  QmlObserverTool::build(const QString &directory, const QString &makeCommand,
+                             const QString &qmakeCommand, const QString &mkspec,
+                             const Utils::Environment &env, const QString &targetMode,
+                             QString *output,  QString *errorMessage)
 {
     return buildHelper(QCoreApplication::translate("Qt4ProjectManager::QmlObserverTool", "QMLObserver"),
                        QLatin1String("qmlobserver.pro"),
-                       directory, makeCommand, qmakeCommand, mkspec, env, targetMode);
+                       directory, makeCommand, qmakeCommand, mkspec, env, targetMode,
+                       output, errorMessage);
 }
 
 static inline bool mkpath(const QString &targetDirectory, QString *errorMessage)
diff --git a/src/plugins/qt4projectmanager/qmlobservertool.h b/src/plugins/qt4projectmanager/qmlobservertool.h
index 78c8ffc5ae9..f787171bdbd 100644
--- a/src/plugins/qt4projectmanager/qmlobservertool.h
+++ b/src/plugins/qt4projectmanager/qmlobservertool.h
@@ -54,9 +54,10 @@ public:
     static QStringList locationsByInstallData(const QString &qtInstallData);
 
     // Build the helpers and return the output log/errormessage.
-    static QString build(const QString &directory, const QString &makeCommand,
-                         const QString &qmakeCommand, const QString &mkspec,
-                         const Utils::Environment &env, const QString &targetMode);
+    static bool build(const QString &directory, const QString &makeCommand,
+                       const QString &qmakeCommand, const QString &mkspec,
+                       const Utils::Environment &env, const QString &targetMode,
+                       QString *output,  QString *errorMessage);
 
     // Copy the source files to a target location and return the chosen target location.
     static QString copy(const QString &qtInstallData, QString *errorMessage);
diff --git a/src/plugins/qt4projectmanager/qtoptionspage.cpp b/src/plugins/qt4projectmanager/qtoptionspage.cpp
index 9c3d23dcd77..41c5ab1b65a 100644
--- a/src/plugins/qt4projectmanager/qtoptionspage.cpp
+++ b/src/plugins/qt4projectmanager/qtoptionspage.cpp
@@ -54,6 +54,8 @@
 #include <QtGui/QHelpEvent>
 #include <QtGui/QToolTip>
 
+enum ModelRoles { BuildLogRole = Qt::UserRole, BuildRunningRole = Qt::UserRole + 1 };
+
 using namespace Qt4ProjectManager;
 using namespace Qt4ProjectManager::Internal;
 
@@ -74,8 +76,14 @@ void DebuggingHelperBuildTask::run(QFutureInterface<void> &future)
 {
     future.setProgressRange(0, 5);
     future.setProgressValue(1);
-    const QString output = m_version->buildDebuggingHelperLibrary(future);
-    emit finished(m_version->displayName(), output);
+    QString output;
+    QString errorMessage;
+    if (m_version->buildDebuggingHelperLibrary(future, false, &output, &errorMessage)) {
+        emit finished(m_version->displayName(), output);
+    } else {
+        qWarning("%s", qPrintable(errorMessage));
+        emit finished(m_version->displayName(), errorMessage);
+    }
     deleteLater();
 }
 
@@ -232,7 +240,7 @@ QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent, QList<QtVersion *> ver
     connect(m_ui->rebuildButton, SIGNAL(clicked()),
             this, SLOT(buildDebuggingHelper()));
     connect(m_ui->showLogButton, SIGNAL(clicked()),
-            this, SLOT(showDebuggingBuildLog()));
+            this, SLOT(slotShowDebuggingBuildLog()));
 
     showEnvironmentPage(0);
     updateState();
@@ -315,7 +323,9 @@ void QtOptionsPageWidget::debuggingHelperBuildFinished(const QString &name, cons
     // Update item view
     QTreeWidgetItem *item = treeItemForIndex(index);
     QTC_ASSERT(item, return)
-    item->setData(2, Qt::UserRole, output);
+    item->setData(2, BuildRunningRole, QVariant(false));
+    item->setData(2, BuildLogRole, output);
+
     QSharedPointerQtVersion qtVersion = m_versions.at(index);
     const bool success = qtVersion->hasDebuggingHelper()
             && (!QmlDumpTool::canBuild(qtVersion.data()) || qtVersion->hasQmlDump())
@@ -325,10 +335,11 @@ void QtOptionsPageWidget::debuggingHelperBuildFinished(const QString &name, cons
     // Update bottom control if the selection is still the same
     if (index == currentIndex()) {
         m_ui->showLogButton->setEnabled(true);
+        m_ui->rebuildButton->setEnabled(true);
         updateDebuggingHelperStateLabel(m_versions.at(index).data());
-        if (!success)
-            showDebuggingBuildLog();
     }
+    if (!success)
+        showDebuggingBuildLog(item);
 }
 
 void QtOptionsPageWidget::buildDebuggingHelper()
@@ -337,7 +348,12 @@ void QtOptionsPageWidget::buildDebuggingHelper()
     if (index < 0)
         return;
 
+    QTreeWidgetItem *item = treeItemForIndex(index);
+    QTC_ASSERT(item, return);
     m_ui->showLogButton->setEnabled(false);
+    m_ui->rebuildButton->setEnabled(false);
+    item->setData(2, BuildRunningRole, QVariant(true));
+
     // Run a debugging helper build task in the background.
     DebuggingHelperBuildTask *buildTask = new DebuggingHelperBuildTask(m_versions.at(index));
     connect(buildTask, SIGNAL(finished(QString,QString)), this, SLOT(debuggingHelperBuildFinished(QString,QString)),
@@ -348,21 +364,44 @@ void QtOptionsPageWidget::buildDebuggingHelper()
                                                         QLatin1String("Qt4ProjectManager::BuildHelpers"));
 }
 
-void QtOptionsPageWidget::showDebuggingBuildLog()
+// Non-modal dialog
+class BuildLogDialog : public QDialog {
+public:
+    explicit BuildLogDialog(QWidget *parent = 0);
+    void setText(const QString &text);
+
+private:
+    Ui_ShowBuildLog m_ui;
+};
+
+BuildLogDialog::BuildLogDialog(QWidget *parent) : QDialog(parent)
 {
-    QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
+    m_ui.setupUi(this);
+    setAttribute(Qt::WA_DeleteOnClose, true);
+}
 
-    int currentItemIndex = indexForTreeItem(currentItem);
+void BuildLogDialog::setText(const QString &text)
+{
+    m_ui.log->setPlainText(text); // Show and scroll to bottom
+    m_ui.log->moveCursor(QTextCursor::End);
+    m_ui.log->ensureCursorVisible();
+}
+
+void QtOptionsPageWidget::slotShowDebuggingBuildLog()
+{
+    if (const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
+        showDebuggingBuildLog(currentItem);
+}
+
+void QtOptionsPageWidget::showDebuggingBuildLog(const QTreeWidgetItem *currentItem)
+{
+    const int currentItemIndex = indexForTreeItem(currentItem);
     if (currentItemIndex < 0)
         return;
-    // Show and scroll to bottom
-    QDialog dlg(this);
-    Ui_ShowBuildLog ui;
-    ui.setupUi(&dlg);
-    ui.log->setPlainText(currentItem->data(2, Qt::UserRole).toString());
-    ui.log->moveCursor(QTextCursor::End);
-    ui.log->ensureCursorVisible();
-    dlg.exec();
+    BuildLogDialog *dialog = new BuildLogDialog(this);
+    dialog->setWindowTitle(tr("Debugging Helper Build Log for '%1'").arg(currentItem->text(0)));
+    dialog->setText(currentItem->data(2, BuildLogRole).toString());
+    dialog->show();
 }
 
 QtOptionsPageWidget::~QtOptionsPageWidget()
@@ -472,10 +511,11 @@ void QtOptionsPageWidget::updateState()
     m_ui->s60SDKPath->setEnabled(s60SDKPathEnabled);
     m_ui->gccePath->setEnabled(enabled);
 
-    const bool hasLog = enabled && !m_ui->qtdirList->currentItem()->data(2, Qt::UserRole).toString().isEmpty();
+    const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
+    const bool buildRunning = currentItem && currentItem->data(2, BuildRunningRole).toBool();
+    const bool hasLog = enabled && currentItem && !currentItem->data(2, Qt::UserRole).toString().isEmpty();
     m_ui->showLogButton->setEnabled(hasLog);
-
-    m_ui->rebuildButton->setEnabled(version && version->isValid());
+    m_ui->rebuildButton->setEnabled(version && version->isValid() && !buildRunning);
     updateDebuggingHelperStateLabel(version);
 }
 
@@ -638,6 +678,7 @@ void QtOptionsPageWidget::versionChanged(QTreeWidgetItem *item, QTreeWidgetItem
     } else {
         m_ui->nameEdit->clear();
         m_ui->qmakePath->setPath(QString()); // clear()
+
     }
     showEnvironmentPage(item);
     updateState();
diff --git a/src/plugins/qt4projectmanager/qtoptionspage.h b/src/plugins/qt4projectmanager/qtoptionspage.h
index 293dd323066..d13f6d0c42f 100644
--- a/src/plugins/qt4projectmanager/qtoptionspage.h
+++ b/src/plugins/qt4projectmanager/qtoptionspage.h
@@ -125,8 +125,11 @@ private slots:
     void updateCurrentGcceDirectory();
     void msvcVersionChanged();
     void buildDebuggingHelper();
-    void showDebuggingBuildLog();
+    void slotShowDebuggingBuildLog();
     void debuggingHelperBuildFinished(const QString &versionName, const QString &output);
+
+private:
+    void showDebuggingBuildLog(const QTreeWidgetItem *currentItem);
 };
 
 class QtOptionsPage : public Core::IOptionsPage
diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp
index 883b47e3507..5f96b94d847 100644
--- a/src/plugins/qt4projectmanager/qtversionmanager.cpp
+++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp
@@ -1757,66 +1757,70 @@ bool QtVersion::isQt64Bit() const
 #endif
 }
 
-QString QtVersion::buildDebuggingHelperLibrary(QFutureInterface<void> &future, bool onlyQmlDump)
-{
-    QString qtInstallHeaders = versionInfo().value("QT_INSTALL_HEADERS");
-    QString qtInstallData = versionInfo().value("QT_INSTALL_DATA");
-    if (qtInstallData.isEmpty())
-        return QString();
+bool QtVersion::buildDebuggingHelperLibrary(QFutureInterface<void> &future,
+                                            bool onlyQmlDump,
+                                            QString *output, QString *errorMessage)
+{
+    const QString qtInstallData = versionInfo().value("QT_INSTALL_DATA");
+    if (qtInstallData.isEmpty()) {
+        *errorMessage =
+                QCoreApplication::translate("QtVersion",
+                                            "Cannot determine the installation path for Qt version '%1'.").
+                                             arg(displayName());
+        return false;
+    }
     Utils::Environment env = Utils::Environment::systemEnvironment();
     addToEnvironment(env);
 
     // TODO: the debugging helper doesn't comply to actual tool chain yet
     QList<QSharedPointer<ProjectExplorer::ToolChain> > alltc = toolChains();
     ProjectExplorer::ToolChain *tc = alltc.isEmpty() ? 0 : alltc.first().data();
-    if (!tc)
-        return QCoreApplication::translate("QtVersion", "The Qt Version has no toolchain.");
+    if (!tc) {
+        *errorMessage = QCoreApplication::translate("QtVersion", "The Qt Version has no toolchain.");
+        return false;
+    }
     tc->addToEnvironment(env);
-    QString output;
+    const QString target = (tc->type() == ToolChain::GCC_MAEMO ? QLatin1String("-unix") : QLatin1String(""));
+
+    // invalidate cache
+    m_versionInfoUpToDate = false;
 
     if (!onlyQmlDump) {
-        QString gdbHelperDirectory = DebuggingHelperLibrary::copy(qtInstallData, &output);
-        if (!gdbHelperDirectory.isEmpty()) {
-            output += DebuggingHelperLibrary::build(gdbHelperDirectory, tc->makeCommand(),
-                                                    qmakeCommand(), mkspec(), env,
-                                                    (tc->type() == ToolChain::GCC_MAEMO ? QLatin1String("-unix") : QLatin1String("")));
-        }
+        const QString gdbHelperDirectory = DebuggingHelperLibrary::copy(qtInstallData, errorMessage);
+        if (gdbHelperDirectory.isEmpty())
+            return false;
+        if (!DebuggingHelperLibrary::build(gdbHelperDirectory, tc->makeCommand(),
+                                           qmakeCommand(), mkspec(), env,
+                                           target, output, errorMessage))
+            return false;
+
         future.setProgressValue(2);
 
         if (QmlObserverTool::canBuild(this)) {
-            QString toolDirectory = QmlObserverTool::copy(qtInstallData, &output);
-            if (!toolDirectory.isEmpty()) {
-                output += QmlObserverTool::build(toolDirectory, tc->makeCommand(),
-                    qmakeCommand(), mkspec(), env,
-                    (tc->type() == ToolChain::GCC_MAEMO ? QLatin1String("-unix") : QLatin1String("")));
-            }
+            const QString toolDirectory = QmlObserverTool::copy(qtInstallData, errorMessage);
+            if (toolDirectory.isEmpty())
+                return false;
+            if (!QmlObserverTool::build(toolDirectory, tc->makeCommand(),
+                                        qmakeCommand(), mkspec(), env, target, output, errorMessage))
+                return false;
         } else {
-            output += QCoreApplication::translate("Qt4ProjectManager::QtVersion", "Cannot build QMLObserver; Qt version must be 4.7.1 or higher.");
+            output->append(QCoreApplication::translate("Qt4ProjectManager::QtVersion", "Warning: Cannot build QMLObserver; Qt version must be 4.7.1 or higher."));
         }
         future.setProgressValue(3);
     }
 
     if (QmlDumpTool::canBuild(this)) {
-        QString toolDirectory = QmlDumpTool::copy(qtInstallData, &output);
-        if (!toolDirectory.isEmpty()) {
-            output += QmlDumpTool::build(toolDirectory, tc->makeCommand(),
-                qmakeCommand(), mkspec(), env,
-                (tc->type() == ToolChain::GCC_MAEMO ? QLatin1String("-unix") : QLatin1String("")));
-        }
+        const QString qmlDumpToolDirectory = QmlDumpTool::copy(qtInstallData, errorMessage);
+        if (qmlDumpToolDirectory.isEmpty())
+            return false;
+        if (!QmlDumpTool::build(qmlDumpToolDirectory, tc->makeCommand(),
+                                qmakeCommand(), mkspec(), env, target, output, errorMessage))
+            return false;
+
     } else {
-        output += QCoreApplication::translate("Qt4ProjectManager::QtVersion", "Cannot build qmldump; Qt version must be 4.7.1 or higher.");
+        output->append(QCoreApplication::translate("Qt4ProjectManager::QtVersion", "Warning: Cannot build qmldump; Qt version must be 4.7.1 or higher."));
     }
     future.setProgressValue(4);
 
-    // invalidate version before updating version info
-    m_versionInfoUpToDate = false;
-    updateVersionInfo();
-
-    if (!onlyQmlDump) {
-        m_hasDebuggingHelper = !debuggingHelperLibrary().isEmpty();
-        m_hasQmlObserver = !qmlObserverTool().isEmpty();
-    }
-    m_hasQmlDump = !qmlDumpTool().isEmpty();
-
-    return output;
+    return true;
 }
diff --git a/src/plugins/qt4projectmanager/qtversionmanager.h b/src/plugins/qt4projectmanager/qtversionmanager.h
index 1c90205f0e5..2d4000a2600 100644
--- a/src/plugins/qt4projectmanager/qtversionmanager.h
+++ b/src/plugins/qt4projectmanager/qtversionmanager.h
@@ -122,7 +122,8 @@ public:
 
     // Builds a debugging library
     // returns the output of the commands
-    QString buildDebuggingHelperLibrary(QFutureInterface<void> &future, bool onlyQmlDump = false);
+    bool buildDebuggingHelperLibrary(QFutureInterface<void> &future, bool onlyQmlDump,
+                                     QString *output, QString *errorMessage);
 
     bool hasExamples() const;
     QString examplesPath() const;
diff --git a/src/plugins/qt4projectmanager/showbuildlog.ui b/src/plugins/qt4projectmanager/showbuildlog.ui
index 5b31a76861c..e29e89494db 100644
--- a/src/plugins/qt4projectmanager/showbuildlog.ui
+++ b/src/plugins/qt4projectmanager/showbuildlog.ui
@@ -30,7 +30,7 @@
       <enum>Qt::Horizontal</enum>
      </property>
      <property name="standardButtons">
-      <set>QDialogButtonBox::Ok</set>
+      <set>QDialogButtonBox::Close</set>
      </property>
     </widget>
    </item>
-- 
GitLab