aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/ios/iosdsymbuildstep.cpp
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@digia.com>2014-03-12 21:25:28 +0100
committerFawzi Mohamed <fawzi.mohamed@digia.com>2014-03-27 11:13:57 +0100
commitcbe8740a8f92765059a8dbbfedae2e593ba1a8e5 (patch)
tree56f7433d810b5886f574f92f4f697a61d8966c7a /src/plugins/ios/iosdsymbuildstep.cpp
parent12730f8444f5bedde4d44288744864ff9838021c (diff)
ios: adding dsymutil build step
The lldb debugger sometime returns misleading debug information unless a dsym has been created. This creates a build step to do it. Task-number: QTCREATORBUG-11580 Change-Id: I7acf2e539cf189d0237e1d502fab2837f17aa489 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@digia.com>
Diffstat (limited to 'src/plugins/ios/iosdsymbuildstep.cpp')
-rw-r--r--src/plugins/ios/iosdsymbuildstep.cpp470
1 files changed, 470 insertions, 0 deletions
diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp
new file mode 100644
index 0000000000..15d7c2fc7b
--- /dev/null
+++ b/src/plugins/ios/iosdsymbuildstep.cpp
@@ -0,0 +1,470 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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 "iosdsymbuildstep.h"
+
+#include "iosconstants.h"
+#include "ui_iospresetbuildstep.h"
+#include "iosmanager.h"
+#include "iosconfigurations.h"
+#include "iosrunconfiguration.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <projectexplorer/target.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/buildsteplist.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <qtsupport/qtkitinformation.h>
+#include <qtsupport/qtparser.h>
+#include <coreplugin/variablemanager.h>
+#include <utils/stringutils.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+#include <utils/qtcassert.h>
+
+using namespace Core;
+using namespace ProjectExplorer;
+
+namespace Ios {
+namespace Internal {
+
+static const char USE_DEFAULT_ARGS_PARTIAL_KEY[] = ".ArgumentsUseDefault";
+static const char COMMAND_PARTIAL_KEY[] = ".Command";
+static const char ARGUMENTS_PARTIAL_KEY[] = ".Arguments";
+static const char CLEAN_PARTIAL_KEY[] = ".Clean";
+
+IosPresetBuildStep::IosPresetBuildStep(BuildStepList *parent, const Id id) :
+ AbstractProcessStep(parent, id),
+ m_clean(parent->id() == ProjectExplorer::Constants::BUILDSTEPS_CLEAN)
+{
+}
+
+bool IosPresetBuildStep::completeSetup()
+{
+ m_command = defaultCommand();
+ m_arguments = defaultArguments();
+ return true;
+}
+
+bool IosPresetBuildStep::completeSetupWithStep(BuildStep *bs)
+{
+ IosPresetBuildStep *o = qobject_cast<IosPresetBuildStep *>(bs);
+ if (!o)
+ return false;
+ m_arguments = o->m_arguments;
+ m_clean = o->m_clean;
+ m_command = o->m_command;
+ return true;
+}
+
+IosPresetBuildStep::~IosPresetBuildStep()
+{
+}
+
+bool IosPresetBuildStep::init()
+{
+ BuildConfiguration *bc = buildConfiguration();
+ if (!bc)
+ bc = target()->activeBuildConfiguration();
+
+ ProcessParameters *pp = processParameters();
+ pp->setMacroExpander(bc->macroExpander());
+ pp->setWorkingDirectory(bc->buildDirectory().toString());
+ Utils::Environment env = bc->environment();
+ // Force output to english for the parsers. Do this here and not in the toolchain's
+ // addToEnvironment() to not screw up the users run environment.
+ env.set(QLatin1String("LC_ALL"), QLatin1String("C"));
+ pp->setEnvironment(env);
+ pp->setCommand(command());
+ pp->setArguments(Utils::QtcProcess::joinArgs(arguments()));
+ pp->resolveAll();
+
+ // If we are cleaning, then build can fail with an error code, but that doesn't mean
+ // we should stop the clean queue
+ // That is mostly so that rebuild works on an already clean project
+ setIgnoreReturnValue(m_clean);
+
+ setOutputParser(target()->kit()->createOutputParser());
+ if (outputParser())
+ outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
+
+ return AbstractProcessStep::init();
+}
+
+QVariantMap IosPresetBuildStep::toMap() const
+{
+ QVariantMap map(AbstractProcessStep::toMap());
+
+ map.insert(id().withSuffix(QLatin1String(ARGUMENTS_PARTIAL_KEY)).toString(),
+ arguments());
+ map.insert(id().withSuffix(QLatin1String(USE_DEFAULT_ARGS_PARTIAL_KEY)).toString(),
+ isDefault());
+ map.insert(id().withSuffix(QLatin1String(CLEAN_PARTIAL_KEY)).toString(), m_clean);
+ map.insert(id().withSuffix(QLatin1String(COMMAND_PARTIAL_KEY)).toString(), command());
+ return map;
+}
+
+bool IosPresetBuildStep::fromMap(const QVariantMap &map)
+{
+ QVariant bArgs = map.value(id().withSuffix(QLatin1String(ARGUMENTS_PARTIAL_KEY)).toString());
+ m_arguments = bArgs.toStringList();
+ bool useDefaultArguments = map.value(
+ id().withSuffix(QLatin1String(USE_DEFAULT_ARGS_PARTIAL_KEY)).toString()).toBool();
+ m_clean = map.value(id().withSuffix(QLatin1String(CLEAN_PARTIAL_KEY)).toString(), m_clean).toBool();
+ m_command = map.value(id().withSuffix(QLatin1String(COMMAND_PARTIAL_KEY)).toString(), m_command)
+ .toString();
+ if (useDefaultArguments) {
+ m_command = defaultCommand();
+ m_arguments = defaultArguments();
+ }
+
+ return BuildStep::fromMap(map);
+}
+
+QStringList IosPresetBuildStep::defaultArguments() const
+{
+ if (m_clean)
+ return defaultCleanCmdList().mid(1);
+ return defaultCmdList().mid(1);
+}
+
+QString IosPresetBuildStep::defaultCommand() const
+{
+ if (m_clean)
+ return defaultCleanCmdList().at(0);
+ else
+ return defaultCmdList().at(0);
+}
+
+QString IosPresetBuildStep::command() const
+{
+ if (m_command.isEmpty())
+ return defaultCommand();
+ return m_command;
+}
+
+void IosPresetBuildStep::setCommand(const QString &command)
+{
+ if (command == m_command)
+ return;
+ if (command.isEmpty() || command == defaultCommand()) {
+ if (arguments() == defaultArguments())
+ m_command.clear();
+ else
+ m_command = defaultCommand();
+ } else if (m_command.isEmpty()) {
+ m_arguments = defaultArguments();
+ m_command = command;
+ } else {
+ m_command = command;
+ }
+}
+
+bool IosPresetBuildStep::clean() const
+{
+ return m_clean;
+}
+
+void IosPresetBuildStep::setClean(bool clean)
+{
+ if (m_clean != clean) {
+ m_clean = clean;
+ m_arguments = defaultArguments();
+ m_command = defaultCommand();
+ }
+}
+
+bool IosPresetBuildStep::isDefault() const
+{
+ return arguments() == defaultArguments() && command() == defaultCommand();
+}
+
+void IosPresetBuildStep::run(QFutureInterface<bool> &fi)
+{
+ AbstractProcessStep::run(fi);
+}
+
+BuildStepConfigWidget *IosPresetBuildStep::createConfigWidget()
+{
+ return new IosPresetBuildStepConfigWidget(this);
+}
+
+bool IosPresetBuildStep::immutable() const
+{
+ return false;
+}
+
+void IosPresetBuildStep::setArguments(const QStringList &args)
+{
+ if (arguments() == args)
+ return;
+ if (args == defaultArguments() && command() == defaultCommand())
+ m_command.clear();
+ else {
+ if (m_command.isEmpty())
+ m_command = defaultCommand();
+ m_arguments = args;
+ }
+}
+
+QStringList IosPresetBuildStep::arguments() const
+{
+ if (m_command.isEmpty())
+ return defaultArguments();
+ return m_arguments;
+}
+
+//
+// IosPresetBuildStepConfigWidget
+//
+
+IosPresetBuildStepConfigWidget::IosPresetBuildStepConfigWidget(IosPresetBuildStep *buildStep)
+ : m_buildStep(buildStep)
+{
+ m_ui = new Ui::IosPresetBuildStep;
+ m_ui->setupUi(this);
+
+ Project *pro = m_buildStep->target()->project();
+
+ m_ui->commandLineEdit->setText(m_buildStep->command());
+ m_ui->argumentsTextEdit->setPlainText(Utils::QtcProcess::joinArgs(
+ m_buildStep->arguments()));
+ m_ui->resetDefaultsButton->setEnabled(!m_buildStep->isDefault());
+ updateDetails();
+
+ connect(m_ui->argumentsTextEdit, SIGNAL(textChanged()),
+ SLOT(argumentsChanged()));
+ connect(m_ui->commandLineEdit, SIGNAL(editingFinished()),
+ SLOT(commandChanged()));
+ connect(m_ui->resetDefaultsButton, SIGNAL(clicked()),
+ SLOT(resetDefaults()));
+
+ connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
+ SLOT(updateDetails()));
+ connect(m_buildStep->target(), SIGNAL(kitChanged()),
+ SLOT(updateDetails()));
+ connect(pro, SIGNAL(environmentChanged()),
+ SLOT(updateDetails()));
+}
+
+IosPresetBuildStepConfigWidget::~IosPresetBuildStepConfigWidget()
+{
+ delete m_ui;
+}
+
+QString IosPresetBuildStepConfigWidget::displayName() const
+{
+ return m_buildStep->displayName();
+}
+
+void IosPresetBuildStepConfigWidget::updateDetails()
+{
+ BuildConfiguration *bc = m_buildStep->buildConfiguration();
+ if (!bc)
+ bc = m_buildStep->target()->activeBuildConfiguration();
+
+ ProcessParameters param;
+ param.setMacroExpander(bc->macroExpander());
+ param.setWorkingDirectory(bc->buildDirectory().toString());
+ param.setEnvironment(bc->environment());
+ param.setCommand(m_buildStep->command());
+ param.setArguments(Utils::QtcProcess::joinArgs(m_buildStep->arguments()));
+ m_summaryText = param.summary(displayName());
+ emit updateSummary();
+}
+
+QString IosPresetBuildStepConfigWidget::summaryText() const
+{
+ return m_summaryText;
+}
+
+void IosPresetBuildStepConfigWidget::commandChanged()
+{
+ m_buildStep->setCommand(m_ui->commandLineEdit->text());
+ m_ui->resetDefaultsButton->setEnabled(!m_buildStep->isDefault());
+ updateDetails();
+}
+
+void IosPresetBuildStepConfigWidget::argumentsChanged()
+{
+ m_buildStep->setArguments(Utils::QtcProcess::splitArgs(
+ m_ui->argumentsTextEdit->toPlainText()));
+ m_ui->resetDefaultsButton->setEnabled(!m_buildStep->isDefault());
+ updateDetails();
+}
+
+void IosPresetBuildStepConfigWidget::resetDefaults()
+{
+ m_buildStep->setCommand(m_buildStep->defaultCommand());
+ m_buildStep->setArguments(m_buildStep->defaultArguments());
+ m_ui->commandLineEdit->setText(m_buildStep->command());
+ m_ui->argumentsTextEdit->setPlainText(Utils::QtcProcess::joinArgs(
+ m_buildStep->arguments()));
+ m_ui->resetDefaultsButton->setEnabled(!m_buildStep->isDefault());
+ updateDetails();
+}
+
+//
+// IosPresetBuildStepFactory
+//
+
+IosPresetBuildStepFactory::IosPresetBuildStepFactory(QObject *parent) :
+ IBuildStepFactory(parent)
+{
+}
+
+BuildStep *IosPresetBuildStepFactory::create(BuildStepList *parent, const Id id)
+{
+ if (!canCreate(parent, id))
+ return 0;
+ IosPresetBuildStep *step = createPresetStep(parent, id);
+ if (step->completeSetup())
+ return step;
+ delete step;
+ return 0;
+}
+
+bool IosPresetBuildStepFactory::canClone(BuildStepList *parent, BuildStep *source) const
+{
+ return canCreate(parent, source->id());
+}
+
+BuildStep *IosPresetBuildStepFactory::clone(BuildStepList *parent, BuildStep *source)
+{
+ if (!canClone(parent, source))
+ return 0;
+ IosPresetBuildStep *old = qobject_cast<IosPresetBuildStep *>(source);
+ Q_ASSERT(old);
+ IosPresetBuildStep *res = createPresetStep(parent, old->id());
+ if (res->completeSetupWithStep(old))
+ return res;
+ delete res;
+ return 0;
+}
+
+bool IosPresetBuildStepFactory::canRestore(BuildStepList *parent, const QVariantMap &map) const
+{
+ return canCreate(parent, idFromMap(map));
+}
+
+BuildStep *IosPresetBuildStepFactory::restore(BuildStepList *parent, const QVariantMap &map)
+{
+ if (!canRestore(parent, map))
+ return 0;
+ IosPresetBuildStep *bs = createPresetStep(parent, idFromMap(map));
+ if (bs->fromMap(map))
+ return bs;
+ delete bs;
+ return 0;
+}
+
+QString IosDsymBuildStepFactory::displayNameForId(const Id id) const
+{
+ if (id == Constants::IOS_DSYM_BUILD_STEP_ID)
+ return QLatin1String("dsymutil");
+ return QString();
+}
+
+QList<Id> IosDsymBuildStepFactory::availableCreationIds(BuildStepList *parent) const
+{
+ if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_CLEAN
+ && parent->id() != ProjectExplorer::Constants::BUILDSTEPS_BUILD
+ && parent->id() != ProjectExplorer::Constants::BUILDSTEPS_DEPLOY)
+ return QList<Id>();
+ Kit *kit = parent->target()->kit();
+ Core::Id deviceType = DeviceTypeKitInformation::deviceTypeId(kit);
+ if (deviceType == Constants::IOS_DEVICE_TYPE
+ || deviceType == Constants::IOS_SIMULATOR_TYPE)
+ return QList<Id>() << Id(Constants::IOS_DSYM_BUILD_STEP_ID);
+ return QList<Id>();
+}
+
+bool IosDsymBuildStepFactory::canCreate(BuildStepList *parent, const Id id) const
+{
+ if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_CLEAN
+ && parent->id() != ProjectExplorer::Constants::BUILDSTEPS_BUILD
+ && parent->id() != ProjectExplorer::Constants::BUILDSTEPS_DEPLOY)
+ return false;
+ Kit *kit = parent->target()->kit();
+ Core::Id deviceType = DeviceTypeKitInformation::deviceTypeId(kit);
+ return ((deviceType == Constants::IOS_DEVICE_TYPE
+ || deviceType == Constants::IOS_SIMULATOR_TYPE)
+ && id == Constants::IOS_DSYM_BUILD_STEP_ID);
+}
+
+IosPresetBuildStep *IosDsymBuildStepFactory::createPresetStep(BuildStepList *parent, const Id id) const
+{
+ return new IosDsymBuildStep(parent, id);
+}
+
+IosDsymBuildStep::IosDsymBuildStep(BuildStepList *parent, const Id id)
+ : IosPresetBuildStep(parent, id)
+{
+ setDefaultDisplayName(QLatin1String("dsymutil"));
+}
+
+QStringList IosDsymBuildStep::defaultCleanCmdList() const
+{
+ IosRunConfiguration *runConf =
+ qobject_cast<IosRunConfiguration *>(target()->activeRunConfiguration());
+ QTC_ASSERT(runConf, return QStringList(QLatin1String("echo")));
+ QString dsymPath = runConf->bundleDir().toUserOutput();
+ dsymPath.chop(4);
+ dsymPath.append(QLatin1String(".dSYM"));
+ return QStringList()
+ << QLatin1String("rm")
+ << QLatin1String("-rf")
+ << dsymPath;
+}
+
+QStringList IosDsymBuildStep::defaultCmdList() const
+{
+ QString dsymutilCmd = QLatin1String("dsymutil");
+ Utils::FileName dsymUtilPath = IosConfigurations::developerPath()
+ .appendPath(QLatin1String("Toolchains/XcodeDefault.xctoolchain/usr/bin/dsymutil"));
+ if (dsymUtilPath.toFileInfo().exists())
+ dsymutilCmd = dsymUtilPath.toUserOutput();
+ IosRunConfiguration *runConf =
+ qobject_cast<IosRunConfiguration *>(target()->activeRunConfiguration());
+ QTC_ASSERT(runConf, return QStringList(QLatin1String("echo")));
+ QString dsymPath = runConf->bundleDir().toUserOutput();
+ dsymPath.chop(4);
+ dsymPath.append(QLatin1String(".dSYM"));
+ return QStringList()
+ << dsymutilCmd
+ << QLatin1String("-o")
+ << dsymPath
+ << runConf->exePath().toUserOutput();
+}
+
+
+} // namespace Internal
+} // namespace Ios