diff options
Diffstat (limited to 'src/tools')
20 files changed, 1395 insertions, 10 deletions
diff --git a/src/tools/QtcTool.qbs b/src/tools/QtcTool.qbs index 7669496dca..a8b4f4d522 100644 --- a/src/tools/QtcTool.qbs +++ b/src/tools/QtcTool.qbs @@ -1,8 +1,9 @@ import qbs.base 1.0 +import "../../qbs/defaults.js" as Defaults Application { Depends { name: "cpp" } - cpp.defines: project.additionalCppDefines + cpp.defines: Defaults.defines(qbs) cpp.linkerFlags: { if (qbs.buildVariant == "release" && (qbs.toolchain == "gcc" || qbs.toolchain == "mingw")) return ["-Wl,-s"] diff --git a/src/tools/qml2puppet/qml2puppet.pro b/src/tools/qml2puppet/qml2puppet.pro new file mode 100644 index 0000000000..b8e17814be --- /dev/null +++ b/src/tools/qml2puppet/qml2puppet.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs + +include(../../../qtcreator.pri) + +greaterThan(QT_MAJOR_VERSION, 4) { + QT += declarative-private core-private + SUBDIRS += qml2puppet +} + diff --git a/src/tools/qml2puppet/qml2puppet/qml2puppet.pro b/src/tools/qml2puppet/qml2puppet/qml2puppet.pro new file mode 100644 index 0000000000..f791416d76 --- /dev/null +++ b/src/tools/qml2puppet/qml2puppet/qml2puppet.pro @@ -0,0 +1,10 @@ +TARGET = qml2puppet + +TEMPLATE = app + +include(../../../../qtcreator.pri) + +DESTDIR = $$IDE_BIN_PATH +include(../../../rpath.pri) + +include(../../../../share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppet.pri) diff --git a/src/tools/qtcdebugger/qtcdebugger.qbs b/src/tools/qtcdebugger/qtcdebugger.qbs index bc416fb95b..5b86287746 100644 --- a/src/tools/qtcdebugger/qtcdebugger.qbs +++ b/src/tools/qtcdebugger/qtcdebugger.qbs @@ -21,6 +21,6 @@ QtcTool { files: [ "main.cpp", "../../shared/registryaccess/registryaccess.cpp", - "../../shared/registryaccess/registryaccess.h" + "../../shared/registryaccess/registryaccess.h", ] } diff --git a/src/tools/qtcreatorcrashhandler/backtracecollector.cpp b/src/tools/qtcreatorcrashhandler/backtracecollector.cpp new file mode 100644 index 0000000000..e62e2432c1 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/backtracecollector.cpp @@ -0,0 +1,128 @@ +/************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "backtracecollector.h" + +#include <QDebug> +#include <QScopedPointer> +#include <QTemporaryFile> + +const char GdbBatchCommands[] = + "set height 0\n" + "set width 0\n" + "thread\n" + "thread apply all backtrace full\n"; + +class BacktraceCollectorPrivate +{ +public: + BacktraceCollectorPrivate() : errorOccurred(false) {} + + bool errorOccurred; + QScopedPointer<QTemporaryFile> commandFile; + QProcess debugger; + QString output; +}; + +BacktraceCollector::BacktraceCollector(QObject *parent) : + QObject(parent), d(new BacktraceCollectorPrivate) +{ + connect(&d->debugger, SIGNAL(finished(int,QProcess::ExitStatus)), + SLOT(onDebuggerFinished(int,QProcess::ExitStatus))); + connect(&d->debugger, SIGNAL(error(QProcess::ProcessError)), + SLOT(onDebuggerError(QProcess::ProcessError))); + connect(&d->debugger, SIGNAL(readyRead()), SLOT(onDebuggerOutputAvailable())); + d->debugger.setProcessChannelMode(QProcess::MergedChannels); +} + +BacktraceCollector::~BacktraceCollector() +{ + delete d; +} + +void BacktraceCollector::run(Q_PID pid) +{ + d->debugger.start(QLatin1String("gdb"), QStringList() + << QLatin1String("--nw") // Do not use a window interface. + << QLatin1String("--nx") // Do not read .gdbinit file. + << QLatin1String("--batch") // Exit after processing options. + << QLatin1String("--command") << createTemporaryCommandFile() + << QLatin1String("--pid") << QString::number(pid) + ); +} + +bool BacktraceCollector::isRunning() const +{ + return d->debugger.state() == QProcess::Running; +} + +void BacktraceCollector::kill() +{ + d->debugger.kill(); +} + +void BacktraceCollector::onDebuggerFinished(int exitCode, QProcess::ExitStatus /*exitStatus*/) +{ + if (d->errorOccurred) { + emit error(QLatin1String("QProcess: ") + d->debugger.errorString()); + return; + } + if (exitCode != 0) { + emit error(QString::fromLatin1("Debugger exited with code %1.").arg(exitCode)); + return; + } + emit backtrace(d->output); +} + +void BacktraceCollector::onDebuggerError(QProcess::ProcessError /*error*/) +{ + d->errorOccurred = true; +} + +QString BacktraceCollector::createTemporaryCommandFile() +{ + d->commandFile.reset(new QTemporaryFile); + if (!d->commandFile->open()) { + emit error(QLatin1String("Error: Could not create temporary command file.")); + return QString(); + } + if (d->commandFile->write(GdbBatchCommands) == -1) { + emit error(QLatin1String("Error: Could not write temporary command file.")); + return QString(); + } + d->commandFile->close(); + return d->commandFile->fileName(); +} + +void BacktraceCollector::onDebuggerOutputAvailable() +{ + const QString newChunk = d->debugger.readAll(); + d->output.append(newChunk); + emit backtraceChunk(newChunk); +} diff --git a/src/tools/qtcreatorcrashhandler/backtracecollector.h b/src/tools/qtcreatorcrashhandler/backtracecollector.h new file mode 100644 index 0000000000..0fc14a4cd6 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/backtracecollector.h @@ -0,0 +1,64 @@ +/************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef BACKTRACECOLLECTOR_H +#define BACKTRACECOLLECTOR_H + +#include <QProcess> + +class BacktraceCollectorPrivate; + +class BacktraceCollector : public QObject +{ + Q_OBJECT +public: + explicit BacktraceCollector(QObject *parent = 0); + ~BacktraceCollector(); + + void run(Q_PID pid); + bool isRunning() const; + void kill(); + +signals: + void error(const QString &errorMessage); + void backtrace(const QString &backtrace); + void backtraceChunk(const QString &chunk); + +private slots: + void onDebuggerOutputAvailable(); + void onDebuggerFinished(int exitCode, QProcess::ExitStatus exitStatus); + void onDebuggerError(QProcess::ProcessError err); + +private: + QString createTemporaryCommandFile(); + + BacktraceCollectorPrivate *d; +}; + +#endif // BACKTRACECOLLECTOR_H diff --git a/src/tools/qtcreatorcrashhandler/crashhandler.cpp b/src/tools/qtcreatorcrashhandler/crashhandler.cpp new file mode 100644 index 0000000000..7521802716 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/crashhandler.cpp @@ -0,0 +1,313 @@ +/************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "crashhandler.h" +#include "crashhandlerdialog.h" +#include "backtracecollector.h" +#include "utils.h" + +#include <utils/environment.h> + +#include <QApplication> +#include <QDebug> +#include <QDesktopServices> +#include <QDir> +#include <QFile> +#include <QRegExp> +#include <QTextStream> +#include <QUrl> +#include <QVector> + +#include <stdio.h> +#include <stdlib.h> + +#include <errno.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/wait.h> + +static const char FileDistroInformation[] = "/etc/lsb-release"; +static const char FileKernelVersion[] = "/proc/version"; +static const char QtCreatorExecutable[] = "qtcreator"; + +static QString collectLinuxDistributionInfo() +{ + return QString::fromLatin1(fileContents(QLatin1String(FileDistroInformation))); +} + +static QString collectKernelVersionInfo() +{ + return QString::fromLatin1(fileContents(QLatin1String(FileKernelVersion))); +} + +// Convience class for interacting with exec() family of functions. +class CExecList : public QVector<char *> +{ +public: + CExecList(const QStringList &list) + { + foreach (const QString &item, list) + append(qstrdup(item.toLatin1().data())); + append(0); + } + + ~CExecList() + { + for (int i = 0; i < size(); ++i) + delete[] value(i); + } +}; + +class CrashHandlerPrivate +{ +public: + CrashHandlerPrivate(pid_t pid, const QString &signalName, CrashHandler *crashHandler) + : pid(pid), + creatorInPath(Utils::Environment::systemEnvironment().searchInPath(QtCreatorExecutable)), + dialog(crashHandler, signalName) {} + + const pid_t pid; + const QString creatorInPath; // Backup debugger. + + BacktraceCollector backtraceCollector; + CrashHandlerDialog dialog; + + QStringList restartAppCommandLine; + QStringList restartAppEnvironment; +}; + +CrashHandler::CrashHandler(pid_t pid, const QString &signalName, QObject *parent) + : QObject(parent), d(new CrashHandlerPrivate(pid, signalName, this)) +{ + connect(&d->backtraceCollector, SIGNAL(error(QString)), SLOT(onError(QString))); + connect(&d->backtraceCollector, SIGNAL(backtraceChunk(QString)), SLOT(onBacktraceChunk(QString))); + connect(&d->backtraceCollector, SIGNAL(backtrace(QString)), SLOT(onBacktraceFinished(QString))); + + d->dialog.appendDebugInfo(collectKernelVersionInfo()); + d->dialog.appendDebugInfo(collectLinuxDistributionInfo()); + + if (!collectRestartAppData()) { + d->dialog.disableRestartAppCheckBox(); + if (d->creatorInPath.isEmpty()) + d->dialog.disableDebugAppButton(); + } + + d->dialog.show(); +} + +CrashHandler::~CrashHandler() +{ + delete d; +} + +void CrashHandler::run() +{ + d->backtraceCollector.run(d->pid); +} + +void CrashHandler::onError(const QString &errorMessage) +{ + d->dialog.setToFinalState(); + + QTextStream(stderr) << errorMessage; + const QString text = QLatin1String("There occured a problem providing the backtrace. " + "Please make sure to have the debugger \"gdb\" installed.\n"); + d->dialog.appendDebugInfo(text); + d->dialog.appendDebugInfo(errorMessage); +} + +void CrashHandler::onBacktraceChunk(const QString &chunk) +{ + d->dialog.appendDebugInfo(chunk); + QTextStream(stdout) << chunk; +} + +void CrashHandler::onBacktraceFinished(const QString &backtrace) +{ + d->dialog.setToFinalState(); + + // Select first line of relevant thread. + + // Example debugger output: + // ... + // [Current thread is 1 (Thread 0x7f1c33c79780 (LWP 975))] + // ... + // Thread 1 (Thread 0x7f1c33c79780 (LWP 975)): + // ... + QRegExp rx("\\[Current thread is (\\d+)"); + const int pos = rx.indexIn(backtrace); + if (pos == -1) + return; + const QString threadNumber = rx.cap(1); + const QString textToSelect = QString::fromLatin1("Thread %1").arg(threadNumber); + d->dialog.selectLineWithContents(textToSelect); +} + +void CrashHandler::openBugTracker() +{ + QDesktopServices::openUrl(QUrl(URL_BUGTRACKER)); +} + +bool CrashHandler::collectRestartAppData() +{ + const QString procDir = QString::fromLatin1("/proc/%1").arg(d->pid); + + // Get command line. + // man 5 proc: /proc/[pid]/cmdline + // The command-line arguments appear in this file as a set of strings separated by + // null bytes ('\0'), with a further null byte after the last string. + const QString procCmdFileName = procDir + QLatin1String("/cmdline"); + QList<QByteArray> commandLine = fileContents(procCmdFileName).split('\0'); + if (commandLine.size() < 2) { + qWarning("%s: Unexpected format in file '%s'.\n", Q_FUNC_INFO, qPrintable(procCmdFileName)); + return false; + } + commandLine.removeLast(); + foreach (const QByteArray &item, commandLine) + d->restartAppCommandLine.append(QString::fromLatin1(item)); + + // Get environment. + // man 5 proc: /proc/[pid]/environ + // The entries are separated by null bytes ('\0'), and there may be a null byte at the end. + const QString procEnvFileName = procDir + QLatin1String("/environ"); + QList<QByteArray> environment = fileContents(procEnvFileName).split('\0'); + if (environment.isEmpty()) { + qWarning("%s: Unexpected format in file '%s'.\n", Q_FUNC_INFO, qPrintable(procEnvFileName)); + return false; + } + if (environment.last().isEmpty()) + environment.removeLast(); + foreach (const QByteArray &item, environment) + d->restartAppEnvironment.append(QString::fromLatin1(item)); + + return true; +} + +void CrashHandler::runCommand(QStringList commandLine, QStringList environment, WaitMode waitMode) +{ + // TODO: If QTBUG-2284 is resolved, use QProcess::startDetached() here. + // We can't use QProcess::startDetached because of bug + // + // QTBUG-2284 + // QProcess::startDetached does not support setting an environment for the new process + // + // therefore, we use fork-exec. + + pid_t pid = fork(); + switch (pid) { + case -1: // error + qFatal("%s: fork() failed.", Q_FUNC_INFO); + break; + case 0: { // child + CExecList argv(commandLine); + CExecList envp(environment); + qDebug("Running\n"); + for (int i = 0; argv[i]; ++i) + qDebug(" %s", argv[i]); + if (!environment.isEmpty()) { + qDebug("\nwith environment:\n"); + for (int i = 0; envp[i]; ++i) + qDebug(" %s", envp[i]); + } + + // The standards pipes must be open, otherwise the application will + // receive a SIGPIPE as soon as these are used. + if (freopen("/dev/null", "r", stdin) == 0) + qFatal("%s: freopen() failed for stdin: %s.\n", Q_FUNC_INFO, strerror(errno)); + if (freopen("/dev/null", "w", stdout) == 0) + qFatal("%s: freopen() failed for stdout: %s.\n", Q_FUNC_INFO, strerror(errno)); + if (freopen("/dev/null", "w", stderr) == 0) + qFatal("%s: freopen() failed for stderr: %s.\n.", Q_FUNC_INFO, strerror(errno)); + + if (environment.isEmpty()) + execv(argv[0], argv.data()); + else + execve(argv[0], argv.data(), envp.data()); + _exit(EXIT_FAILURE); + } default: // parent + if (waitMode == WaitForExit) { + while (true) { + int status; + if (waitpid(pid, &status, 0) == -1) { + if (errno == EINTR) // Signal handler of QProcess for SIGCHLD was triggered. + continue; + perror("waitpid() failed unexpectedly"); + } + if (WIFEXITED(status)) { + qDebug("Child exited with exit code %d.", WEXITSTATUS(status)); + break; + } else if (WIFSIGNALED(status)) { + qDebug("Child terminated by signal %d.", WTERMSIG(status)); + break; + } + } + } + break; + } +} + +void CrashHandler::restartApplication() +{ + runCommand(d->restartAppCommandLine, d->restartAppEnvironment, DontWaitForExit); +} + +void CrashHandler::debugApplication() +{ + // User requested to debug the app while our debugger is running. + if (d->backtraceCollector.isRunning()) { + if (!d->dialog.runDebuggerWhileBacktraceNotFinished()) + return; + if (d->backtraceCollector.isRunning()) { + d->backtraceCollector.disconnect(); + d->backtraceCollector.kill(); + d->dialog.setToFinalState(); + d->dialog.appendDebugInfo(tr("\n\nCollecting backtrace aborted by user.")); + QCoreApplication::processEvents(); // Show the last appended output immediately. + } + } + + // Prepare command. + QString executable = d->creatorInPath; + if (!d->restartAppCommandLine.isEmpty()) + executable = d->restartAppCommandLine.at(0); + const QStringList commandLine = QStringList() + << executable + << QLatin1String("-debug") + << QString::number(d->pid); + + QStringList environment; + if (!d->restartAppEnvironment.isEmpty()) + environment = d->restartAppEnvironment; + + // The UI is blocked/frozen anyway, so hide the dialog while debugging. + d->dialog.hide(); + runCommand(commandLine, environment, WaitForExit); + d->dialog.show(); +} diff --git a/src/tools/qtcreatorcrashhandler/crashhandler.h b/src/tools/qtcreatorcrashhandler/crashhandler.h new file mode 100644 index 0000000000..bf4c1991da --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/crashhandler.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CRASHHANDLER_H +#define CRASHHANDLER_H + +#include <QObject> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +class ApplicationInfo; +class CrashHandlerPrivate; + +class CrashHandler : public QObject +{ + Q_OBJECT +public: + explicit CrashHandler(pid_t pid, const QString &signalName, QObject *parent = 0); + ~CrashHandler(); + + void run(); + +public slots: + void onError(const QString &errorMessage); + void onBacktraceChunk(const QString &chunk); + void onBacktraceFinished(const QString &backtrace); + + void openBugTracker(); + void restartApplication(); + void debugApplication(); + +private: + bool collectRestartAppData(); + + enum WaitMode { WaitForExit, DontWaitForExit }; + static void runCommand(QStringList commandLine, QStringList environment, WaitMode waitMode); + + CrashHandlerPrivate *d; +}; + +#endif // CRASHHANDLER_H diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp new file mode 100644 index 0000000000..5d23255753 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp @@ -0,0 +1,180 @@ +/************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "crashhandler.h" +#include "crashhandlerdialog.h" +#include "ui_crashhandlerdialog.h" +#include "utils.h" + +#include <app/app_version.h> +#include <utils/checkablemessagebox.h> + +#include <QClipboard> +#include <QIcon> +#include <QSettings> + +static const char SettingsApplication[] = "QtCreator"; +static const char SettingsKeySkipWarningAbortingBacktrace[] + = "CrashHandler/SkipWarningAbortingBacktrace"; + +CrashHandlerDialog::CrashHandlerDialog(CrashHandler *handler, const QString &signalName, + QWidget *parent) : + QDialog(parent), + m_crashHandler(handler), + m_ui(new Ui::CrashHandlerDialog) +{ + m_ui->setupUi(this); + m_ui->introLabel->setTextFormat(Qt::RichText); + m_ui->introLabel->setOpenExternalLinks(true); + m_ui->debugInfoEdit->setReadOnly(true); + m_ui->progressBar->setMinimum(0); + m_ui->progressBar->setMaximum(0); + + const QStyle * const style = QApplication::style(); + m_ui->closeButton->setIcon(style->standardIcon(QStyle::SP_DialogCloseButton)); + + const int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, 0); + QIcon icon = style->standardIcon(QStyle::SP_MessageBoxCritical); + m_ui->iconLabel->setPixmap(icon.pixmap(iconSize, iconSize)); + + connect(m_ui->copyToClipBoardButton, SIGNAL(clicked()), this, SLOT(copyToClipboardClicked())); + connect(m_ui->reportBugButton, SIGNAL(clicked()), m_crashHandler, SLOT(openBugTracker())); + connect(m_ui->debugAppButton, SIGNAL(clicked()), m_crashHandler, SLOT(debugApplication())); + connect(m_ui->closeButton, SIGNAL(clicked()), this, SLOT(close())); + + setApplicationInfo(signalName); +} + +CrashHandlerDialog::~CrashHandlerDialog() +{ + delete m_ui; +} + +bool CrashHandlerDialog::runDebuggerWhileBacktraceNotFinished() +{ + // Check settings. + QSettings settings(QSettings::IniFormat, QSettings::UserScope, + QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR), + QLatin1String(SettingsApplication)); + if (settings.value(QLatin1String(SettingsKeySkipWarningAbortingBacktrace), false).toBool()) + return true; + + // Ask user. + const QString title = tr("Run Debugger And Abort Collecting Backtrace?"); + const QString message = tr( + "<html><head/><body>" + "<p><b>Run the debugger and abort collecting backtrace?</b></p>" + "<p>You have requested to run the debugger while collecting the backtrace was not " + "finished.</p>" + "</body></html>"); + const QString checkBoxText = tr("Do not &ask again."); + bool checkBoxSetting = false; + const QDialogButtonBox::StandardButton button = Utils::CheckableMessageBox::question(this, + title, message, checkBoxText, &checkBoxSetting, + QDialogButtonBox::Yes|QDialogButtonBox::No, QDialogButtonBox::No); + if (checkBoxSetting) + settings.setValue(QLatin1String(SettingsKeySkipWarningAbortingBacktrace), checkBoxSetting); + + return button == QDialogButtonBox::Yes; +} + +void CrashHandlerDialog::setToFinalState() +{ + m_ui->progressBar->hide(); + m_ui->copyToClipBoardButton->setEnabled(true); + m_ui->reportBugButton->setEnabled(true); +} + +void CrashHandlerDialog::disableRestartAppCheckBox() +{ + m_ui->restartAppCheckBox->setDisabled(true); +} + +void CrashHandlerDialog::disableDebugAppButton() +{ + m_ui->debugAppButton->setDisabled(true); +} + +void CrashHandlerDialog::setApplicationInfo(const QString &signalName) +{ + const QString ideName = QLatin1String("Qt Creator"); + const QString title = tr("%1 has closed unexpectedly (Signal \"%2\")").arg(ideName, signalName); + const QString introLabelContents = tr( + "<p><b>%1.</b></p>" + "<p>Please file a <a href='%2'>bug report</a> with the debug information provided below.</p>") + .arg(title, QLatin1String(URL_BUGTRACKER)); + m_ui->introLabel->setText(introLabelContents); + setWindowTitle(title); + + QString revision; +#ifdef IDE_REVISION + revision = tr(" from revision %1").arg(QString::fromLatin1(Core::Constants::IDE_REVISION_STR).left(10)); +#endif + const QString versionInformation = tr( + "%1 %2%3, built on %4 at %5, based on Qt %6 (%7 bit)\n") + .arg(ideName, QLatin1String(Core::Constants::IDE_VERSION_LONG), revision, + QLatin1String(__DATE__), QLatin1String(__TIME__), QLatin1String(QT_VERSION_STR), + QString::number(QSysInfo::WordSize)); + m_ui->debugInfoEdit->append(versionInformation); +} + +void CrashHandlerDialog::appendDebugInfo(const QString &chunk) +{ + m_ui->debugInfoEdit->append(chunk); +} + +void CrashHandlerDialog::selectLineWithContents(const QString &text) +{ + // The selected line will be the first line visible. + + // Go to end. + QTextCursor cursor = m_ui->debugInfoEdit->textCursor(); + cursor.movePosition(QTextCursor::End); + m_ui->debugInfoEdit->setTextCursor(cursor); + + // Find text by searching backwards. + m_ui->debugInfoEdit->find(text, QTextDocument::FindCaseSensitively | QTextDocument::FindBackward); + + // Highlight whole line. + cursor = m_ui->debugInfoEdit->textCursor(); + cursor.select(QTextCursor::LineUnderCursor); + m_ui->debugInfoEdit->setTextCursor(cursor); +} + +void CrashHandlerDialog::copyToClipboardClicked() +{ + QApplication::clipboard()->setText(m_ui->debugInfoEdit->toPlainText()); +} + +void CrashHandlerDialog::close() +{ + if (m_ui->restartAppCheckBox->isEnabled() && m_ui->restartAppCheckBox->isChecked()) + m_crashHandler->restartApplication(); + qApp->quit(); +} diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.h b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.h new file mode 100644 index 0000000000..fc9ff7921a --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.h @@ -0,0 +1,71 @@ +/************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CRASHHANDLERDIALOG_H +#define CRASHHANDLERDIALOG_H + +#include <QDialog> + +QT_BEGIN_NAMESPACE +class QString; +namespace Ui { +class CrashHandlerDialog; +} +QT_END_NAMESPACE + +class CrashHandler; + +class CrashHandlerDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CrashHandlerDialog(CrashHandler *handler, const QString &signalName, + QWidget *parent = 0); + ~CrashHandlerDialog(); + +public: + void setApplicationInfo(const QString &signalName); + void appendDebugInfo(const QString &chunk); + void selectLineWithContents(const QString &text); + void setToFinalState(); + void disableRestartAppCheckBox(); + void disableDebugAppButton(); + bool runDebuggerWhileBacktraceNotFinished(); + +private slots: + void copyToClipboardClicked(); + void close(); + +private: + CrashHandler *m_crashHandler; + Ui::CrashHandlerDialog *m_ui; +}; + +#endif // CRASHHANDLERDIALOG_H diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.ui b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.ui new file mode 100644 index 0000000000..9a7b67a003 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.ui @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CrashHandlerDialog</class> + <widget class="QDialog" name="CrashHandlerDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>800</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>300</height> + </size> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <widget class="QLabel" name="iconLabel"> + <property name="text"> + <string>Icon</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="introLabel"> + <property name="text"> + <string>Some useful information here...</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="value"> + <number>24</number> + </property> + </widget> + </item> + <item> + <widget class="QTextEdit" name="debugInfoEdit"/> + </item> + <item alignment="Qt::AlignRight"> + <widget class="QCheckBox" name="restartAppCheckBox"> + <property name="text"> + <string>&Restart Qt Creator on close</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="copyToClipBoardButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Copy the whole contents to clipboard.</string> + </property> + <property name="text"> + <string>C&opy to clipboard</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="reportBugButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Open the bug tracker web site.</string> + </property> + <property name="text"> + <string>Report this &bug</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="debugAppButton"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="toolTip"> + <string>Debug the application with a new instance of Qt Creator. During debugging the crash handler will be hidden.</string> + </property> + <property name="text"> + <string>Attach and &Debug</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="closeButton"> + <property name="toolTip"> + <string>Quit the handler and the crashed application.</string> + </property> + <property name="text"> + <string>&Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/tools/qtcreatorcrashhandler/crashhandlersetup.cpp b/src/tools/qtcreatorcrashhandler/crashhandlersetup.cpp new file mode 100644 index 0000000000..cc48afa731 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/crashhandlersetup.cpp @@ -0,0 +1,134 @@ +/************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "crashhandlersetup.h" + +#include <QtGlobal> + +#if !defined(QT_NO_DEBUG) && defined(Q_OS_LINUX) +#define BUILD_CRASH_HANDLER +#endif + +#ifdef BUILD_CRASH_HANDLER + +#include <QApplication> +#include <QDebug> +#include <QString> + +#include <stdlib.h> + +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#ifdef Q_WS_X11 +#include <qx11info_x11.h> +#include <X11/Xlib.h> +#endif + +static const char *crashHandlerPathC; +static void *signalHandlerStack; + +extern "C" void signalHandler(int signal) +{ +#ifdef Q_WS_X11 + // Kill window since it's frozen anyway. + if (QX11Info::display()) + close(ConnectionNumber(QX11Info::display())); +#endif + pid_t pid = fork(); + switch (pid) { + case -1: // error + break; + case 0: // child + execl(crashHandlerPathC, crashHandlerPathC, strsignal(signal), (char *) 0); + _exit(EXIT_FAILURE); + default: // parent + waitpid(pid, 0, 0); + _exit(EXIT_FAILURE); + break; + } +} +#endif // BUILD_CRASH_HANDLER + +void setupCrashHandler() +{ +#ifdef BUILD_CRASH_HANDLER + const QString crashHandlerPath = qApp->applicationDirPath() + + QLatin1String("/qtcreator_crash_handler"); + crashHandlerPathC = qstrdup(qPrintable(crashHandlerPath)); + + // Setup an alternative stack for the signal handler. This way we are able to handle SIGSEGV + // even if the normal process stack is exhausted. + stack_t ss; + ss.ss_sp = signalHandlerStack = malloc(SIGSTKSZ); // Usual requirements for alternative signal stack. + if (ss.ss_sp == 0) { + qWarning("Warning: Could not allocate space for alternative signal stack (%s).", Q_FUNC_INFO); + return; + } + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; + if (sigaltstack(&ss, 0) == -1) { + qWarning("Warning: Failed to set alternative signal stack (%s).", Q_FUNC_INFO); + return; + } + + // Install signal handler for calling the crash handler. + struct sigaction sa; + if (sigemptyset(&sa.sa_mask) == -1) { + qWarning("Warning: Failed to empty signal set (%s).", Q_FUNC_INFO); + return; + } + sa.sa_handler = &signalHandler; + // SA_RESETHAND - Restore signal action to default after signal handler has been called. + // SA_NODEFER - Don't block the signal after it was triggered (otherwise blocked signals get + // inherited via fork() and execve()). Without this the signal will not be delivered to the + // restarted Qt Creator. + // SA_ONSTACK - Use alternative stack. + sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_ONSTACK; + const int signalsToHandle[] = { SIGILL, SIGFPE, SIGSEGV, SIGBUS, 0 }; + for (int i = 0; signalsToHandle[i]; ++i) { + if (sigaction(signalsToHandle[i], &sa, 0) == -1 ) { + qWarning("Warning: Failed to install signal handler for signal \"%s\" (%s).", + strsignal(signalsToHandle[i]), Q_FUNC_INFO); + } + } +#endif // BUILD_CRASH_HANDLER +} + +void cleanupCrashHandler() +{ +#ifdef BUILD_CRASH_HANDLER + delete[] crashHandlerPathC; + free(signalHandlerStack); +#endif +} diff --git a/src/tools/qtcreatorcrashhandler/crashhandlersetup.h b/src/tools/qtcreatorcrashhandler/crashhandlersetup.h new file mode 100644 index 0000000000..02c50ef230 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/crashhandlersetup.h @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CRASHHANDLERSETUP_H +#define CRASHHANDLERSETUP_H + +void setupCrashHandler(); +void cleanupCrashHandler(); + +#endif // CRASHHANDLERSETUP_H diff --git a/src/tools/qtcreatorcrashhandler/main.cpp b/src/tools/qtcreatorcrashhandler/main.cpp new file mode 100644 index 0000000000..623520cf22 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/main.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "crashhandler.h" +#include "utils.h" + +#include <QApplication> +#include <QFile> +#include <QProcess> +#include <QString> +#include <QStyle> +#include <QTextStream> + +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> + +// Called by signal handler of qtcreator. +// Usage: $0 <name of signal causing the crash> +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + app.setApplicationName(QLatin1String(APPLICATION_NAME)); + app.setWindowIcon(QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical)); + + // Check usage. + Q_PID parentPid = getppid(); + QString parentExecutable = QFile::symLinkTarget(QString::fromLatin1("/proc/%1/exe") + .arg(QString::number(parentPid))); + if (argc > 2 || !parentExecutable.contains("qtcreator")) { + QTextStream err(stderr); + err << QString::fromLatin1("This crash handler will be called by Qt Creator itself. " + "Do not call this manually.\n"); + return EXIT_FAILURE; + } + + // Run. + CrashHandler *crashHandler = new CrashHandler(parentPid, app.arguments().at(1)); + crashHandler->run(); + + return app.exec(); +} diff --git a/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.pro b/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.pro new file mode 100644 index 0000000000..bfcb41e303 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.pro @@ -0,0 +1,31 @@ +include(../../../qtcreator.pri) + +TARGET = qtcreator_crash_handler +DESTDIR = $$IDE_BIN_PATH + +CONFIG -= app_bundle +TEMPLATE = app + +SOURCES += \ + main.cpp \ + backtracecollector.cpp \ + crashhandlerdialog.cpp \ + crashhandler.cpp \ + utils.cpp \ + ../../libs/utils/checkablemessagebox.cpp \ + ../../libs/utils/environment.cpp + + +HEADERS += \ + backtracecollector.h \ + crashhandlerdialog.h \ + crashhandler.h \ + utils.h \ + ../../libs/utils/checkablemessagebox.h \ + ../../libs/utils/environment.h + +FORMS += \ + crashhandlerdialog.ui + +target.path = /bin +INSTALLS += target diff --git a/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.qbs b/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.qbs new file mode 100644 index 0000000000..35d6187d56 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.qbs @@ -0,0 +1,33 @@ +import qbs.base 1.0 +import "../QtcTool.qbs" as QtcTool + +QtcTool { + name: "qtcreator_crash_handler" + condition: qbs.targetOS == "linux" && qbs.buildVariant == "debug" + + cpp.includePaths: [ + buildDirectory, + "../../libs" + ] + + Depends { name: "cpp" } + Depends { name: "Qt.widgets" } + Depends { name: "app_version_header" } + + files: [ + "../../libs/utils/checkablemessagebox.cpp", + "../../libs/utils/checkablemessagebox.h", + "../../libs/utils/environment.cpp", + "../../libs/utils/environment.h", + "backtracecollector.cpp", + "backtracecollector.h", + "crashhandler.cpp", + "crashhandler.h", + "crashhandlerdialog.cpp", + "crashhandlerdialog.h", + "crashhandlerdialog.ui", + "main.cpp", + "utils.cpp", + "utils.h" + ] +} diff --git a/src/tools/qtcreatorcrashhandler/utils.cpp b/src/tools/qtcreatorcrashhandler/utils.cpp new file mode 100644 index 0000000000..2fe505b1f8 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/utils.cpp @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "utils.h" + +#include <QDebug> +#include <QFile> + +QByteArray fileContents(const QString &filePath) +{ + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning("Warning: Could not open '%s'.", qPrintable(filePath)); + return QByteArray(); + } + return file.readAll(); +} diff --git a/src/tools/qtcreatorcrashhandler/utils.h b/src/tools/qtcreatorcrashhandler/utils.h new file mode 100644 index 0000000000..0232db5ca1 --- /dev/null +++ b/src/tools/qtcreatorcrashhandler/utils.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef UTILS_H +#define UTILS_H + +#include <QByteArray> +#include <QString> + +const char APPLICATION_NAME[] = "Qt Creator Crash Handler"; +const char URL_BUGTRACKER[] = "https://bugreports.qt-project.org/"; + +QByteArray fileContents(const QString &filePath); + +#endif // UTILS_H diff --git a/src/tools/sdktool/sdktool.qbs b/src/tools/sdktool/sdktool.qbs index 1ecea9e4c1..7d8e571a90 100644 --- a/src/tools/sdktool/sdktool.qbs +++ b/src/tools/sdktool/sdktool.qbs @@ -4,17 +4,16 @@ import "../QtcTool.qbs" as QtcTool QtcTool { name: "sdktool" - cpp.includePaths: [buildDirectory] - cpp.defines: base.concat([qbs.targetOS === "mac" - ? 'DATA_PATH="."' : 'DATA_PATH="../share/qtcreator"']) - Depends { name: "cpp" } Depends { name: "Qt.core" } Depends { name: "Utils" } Depends { name: "app_version_header" } + cpp.includePaths: "../../libs" + cpp.defines: base.concat([qbs.targetOS === "mac" + ? 'DATA_PATH="."' : 'DATA_PATH="../share/qtcreator"']) + files: [ - "main.cpp", "addkeysoperation.cpp", "addkeysoperation.h", "addkitoperation.cpp", @@ -29,8 +28,9 @@ QtcTool { "findvalueoperation.h", "getoperation.cpp", "getoperation.h", - "operation.h", + "main.cpp", "operation.cpp", + "operation.h", "rmkeysoperation.cpp", "rmkeysoperation.h", "rmkitoperation.cpp", @@ -40,6 +40,6 @@ QtcTool { "rmtoolchainoperation.cpp", "rmtoolchainoperation.h", "settings.cpp", - "settings.h" + "settings.h", ] } diff --git a/src/tools/tools.pro b/src/tools/tools.pro index 1f499584d5..3a48a7918f 100644 --- a/src/tools/tools.pro +++ b/src/tools/tools.pro @@ -2,6 +2,7 @@ TEMPLATE = subdirs SUBDIRS = qtpromaker \ qmlpuppet \ + ../plugins/cpaster/frontend \ sdktool win32 { @@ -21,5 +22,11 @@ win32 { QT_BREAKPAD_ROOT_PATH = $$(QT_BREAKPAD_ROOT_PATH) !isEmpty(QT_BREAKPAD_ROOT_PATH) { SUBDIRS += qtcrashhandler +} else { + linux-* { + # Build only in debug mode. + debug_and_release|CONFIG(debug, debug|release) { + SUBDIRS += qtcreatorcrashhandler + } + } } - |