Commit 8d96ce55 authored by Fawzi Mohamed's avatar Fawzi Mohamed Committed by Eike Ziller
Browse files

ios: preliminary support for ios



first work in progress support for ios
* separate iosTool using xml communication used for device info and run
* iossim tool to handle the simulator
* debug prepared but not working
* separate gcc toolchain detection fix for simulator

1) add a QT built for ios
2) open a project, for example qtbase/examples/widgets/animation/animatedtiles/animatedtiles.pro
3) build/run...

Change-Id: I7e01604e416338cbe4692dfb34f5d3f31312702d
Reviewed-by: default avatarEike Ziller <eike.ziller@digia.com>
parent 3a7d91ca
<plugin name=\"Ios\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\" experimental=\"true\">
<vendor>Digia Plc</vendor>
<copyright>(C) 2013 Digia Plc</copyright>
<license>
Commercial Usage
Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and Digia.
GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. 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.
</license>
<description>Support for deployment to and execution on iOS Devices</description>
<category>Device Support</category>
<url>http://www.qt-project.org</url>
$$dependencyList
</plugin>
TEMPLATE = lib
TARGET = Ios
include(../../qtcreatorplugin.pri)
QT += xml network
HEADERS += \
iosconstants.h \
iosconfigurations.h \
iosmanager.h \
iosrunconfiguration.h \
iosruncontrol.h \
iosrunfactories.h \
iossettingspage.h \
iossettingswidget.h \
iosrunner.h \
iosdebugsupport.h \
iosqtversionfactory.h \
iosqtversion.h \
iosplugin.h \
iosdevicefactory.h \
iosdevice.h \
iossimulator.h \
iossimulatorfactory.h \
iosprobe.h \
iosbuildstep.h \
iostoolhandler.h \
iosdeployconfiguration.h \
iosdeploystep.h \
iosdeploystepfactory.h \
iosdeploystepwidget.h
SOURCES += \
iosconfigurations.cpp \
iosmanager.cpp \
iosrunconfiguration.cpp \
iosruncontrol.cpp \
iosrunfactories.cpp \
iossettingspage.cpp \
iossettingswidget.cpp \
iosrunner.cpp \
iosdebugsupport.cpp \
iosqtversionfactory.cpp \
iosqtversion.cpp \
iosplugin.cpp \
iosdevicefactory.cpp \
iosdevice.cpp \
iossimulator.cpp \
iossimulatorfactory.cpp \
iosprobe.cpp \
iosbuildstep.cpp \
iostoolhandler.cpp \
iosdeployconfiguration.cpp \
iosdeploystep.cpp \
iosdeploystepfactory.cpp \
iosdeploystepwidget.cpp
FORMS += \
iossettingswidget.ui \
iosbuildstep.ui \
iosrunconfiguration.ui \
iosdeploystepwidget.ui
DEFINES += IOS_LIBRARY
RESOURCES += ios.qrc
import qbs.base 1.0
import "../QtcPlugin.qbs" as QtcPlugin
QtcPlugin {
name: "Ios"
condition: qbs.targetOS.contains("osx")
Depends { name: "Core" }
Depends { name: "ProjectExplorer" }
Depends { name: "Qt4ProjectManager" }
Depends { name: "Debugger" }
Depends { name: "QtSupport" }
Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] }
cpp.includePaths: base.concat("../../shared")
cpp.frameworks: base.concat(["CoreFoundation", "IOKit"])
files: [
"ios.qrc",
"iosbuildstep.cpp",
"iosbuildstep.h",
"iosbuildstep.ui",
"iosconfigurations.cpp",
"iosconfigurations.h",
"iosconstants.h",
"iosdebugsupport.cpp",
"iosdebugsupport.h",
"iosdeployconfiguration.cpp",
"iosdeployconfiguration.h",
"iosdeploystep.cpp",
"iosdeploystep.h",
"iosdeploystepfactory.cpp",
"iosdeploystepfactory.h",
"iosdeploystepwidget.cpp",
"iosdeploystepwidget.h",
"iosdeploystepwidget.ui",
"iosdevice.cpp",
"iosdevice.h",
"iosdevicefactory.cpp",
"iosdevicefactory.h",
"iosmanager.cpp",
"iosmanager.h",
"iosplugin.cpp",
"iosplugin.h",
"iosprobe.cpp",
"iosprobe.h",
"iosqtversion.cpp",
"iosqtversion.h",
"iosqtversionfactory.cpp",
"iosqtversionfactory.h",
"iosrunconfiguration.cpp",
"iosrunconfiguration.h",
"iosrunconfiguration.ui",
"iosruncontrol.cpp",
"iosruncontrol.h",
"iosrunfactories.cpp",
"iosrunfactories.h",
"iosrunner.cpp",
"iosrunner.h",
"iossettingspage.cpp",
"iossettingspage.h",
"iossettingswidget.cpp",
"iossettingswidget.h",
"iossettingswidget.ui",
"iossimulator.cpp",
"iossimulator.h",
"iossimulatorfactory.cpp",
"iossimulatorfactory.h",
"iostoolhandler.cpp",
"iostoolhandler.h"
]
}
<RCC>
<qresource prefix="/ios">
<file>images/QtIos.png</file>
</qresource>
</RCC>
QTC_PLUGIN_NAME = Ios
QTC_LIB_DEPENDS += \
utils
QTC_PLUGIN_DEPENDS += \
coreplugin \
debugger \
projectexplorer \
qt4projectmanager
/****************************************************************************
**
** Copyright (C) 2013 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 "iosbuildstep.h"
#include "iosconstants.h"
#include "ui_iosbuildstep.h"
#include "iosmanager.h"
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/target.h>
#include <projectexplorer/project.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/gnumakeparser.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/gcctoolchain.h>
#include <qt4projectmanager/qt4buildconfiguration.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
#include <qt4projectmanager/qt4projectmanager.h>
#include <qt4projectmanager/qt4project.h>
#include <qt4projectmanager/qt4nodes.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>
using namespace Core;
using namespace ProjectExplorer;
using namespace Qt4ProjectManager;
namespace Ios {
namespace Internal {
const char IOS_BUILD_STEP_ID[] = "Ios.IosBuildStep";
const char IOS_BUILD_STEP_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("Ios::Internal::IosBuildStep",
"xcodebuild");
const char BUILD_USE_DEFAULT_ARGS_KEY[] = "Ios.IosBuildStep.XcodeArgumentsUseDefault";
const char BUILD_ARGUMENTS_KEY[] = "Ios.IosBuildStep.XcodeArguments";
const char CLEAN_KEY[] = "Ios.IosBuildStep.Clean";
IosBuildStep::IosBuildStep(BuildStepList *parent) :
AbstractProcessStep(parent, Id(IOS_BUILD_STEP_ID)),
m_useDefaultArguments(true),
m_clean(false)
{
ctor();
}
IosBuildStep::IosBuildStep(BuildStepList *parent, const Id id) :
AbstractProcessStep(parent, id),
m_useDefaultArguments(true),
m_clean(false)
{
ctor();
}
IosBuildStep::IosBuildStep(BuildStepList *parent, IosBuildStep *bs) :
AbstractProcessStep(parent, bs),
m_baseBuildArguments(bs->m_baseBuildArguments),
m_useDefaultArguments(bs->m_useDefaultArguments),
m_clean(bs->m_clean)
{
ctor();
}
void IosBuildStep::ctor()
{
setDefaultDisplayName(QCoreApplication::translate("GenericProjectManager::Internal::IosBuildStep",
IOS_BUILD_STEP_DISPLAY_NAME));
}
IosBuildStep::~IosBuildStep()
{
}
bool IosBuildStep::init()
{
BuildConfiguration *bc = buildConfiguration();
if (!bc)
bc = target()->activeBuildConfiguration();
m_tasks.clear();
ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit());
if (!tc) {
Task t = Task(Task::Error, tr("Qt Creator needs a compiler set up to build. Configure a compiler in the kit preferences."),
Utils::FileName(), -1,
Core::Id(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
m_tasks.append(t);
emit addTask(t);
return false;
}
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(buildCommand());
pp->setArguments(Utils::QtcProcess::joinArgs(allArguments()));
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(new GnuMakeParser());
IOutputParser *parser = target()->kit()->createOutputParser();
if (parser)
appendOutputParser(parser);
outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory());
return AbstractProcessStep::init();
}
void IosBuildStep::setClean(bool clean)
{
m_clean = clean;
}
bool IosBuildStep::isClean() const
{
return m_clean;
}
QVariantMap IosBuildStep::toMap() const
{
QVariantMap map(AbstractProcessStep::toMap());
map.insert(QLatin1String(BUILD_ARGUMENTS_KEY), m_baseBuildArguments);
map.insert(QLatin1String(BUILD_USE_DEFAULT_ARGS_KEY), m_useDefaultArguments);
map.insert(QLatin1String(CLEAN_KEY), m_clean);
return map;
}
bool IosBuildStep::fromMap(const QVariantMap &map)
{
QVariant bArgs = map.value(QLatin1String(BUILD_ARGUMENTS_KEY));
m_baseBuildArguments = bArgs.toStringList();
m_useDefaultArguments = map.value(QLatin1String(BUILD_USE_DEFAULT_ARGS_KEY)).toBool();
m_clean = map.value(QLatin1String(CLEAN_KEY)).toBool();
return BuildStep::fromMap(map);
}
QStringList IosBuildStep::allArguments() const
{
return baseArguments() + m_extraArguments;
}
QStringList IosBuildStep::defaultArguments() const
{
QStringList res;
Kit *kit = target()->kit();
ToolChain *tc = ToolChainKitInformation::toolChain(kit);
switch (target()->activeBuildConfiguration()->buildType()) {
case BuildConfiguration::Debug :
res << QLatin1String("-configuration") << QLatin1String("Debug");
break;
case BuildConfiguration::Release :
res << QLatin1String("-configuration") << QLatin1String("Release");
break;
case BuildConfiguration::Unknown :
break;
default:
qDebug() << "IosBuildStep had an unknown buildType "
<< target()->activeBuildConfiguration()->buildType();
}
if (tc->type() == QLatin1String("gcc") || tc->type() == QLatin1String("clang")) {
GccToolChain *gtc = static_cast<GccToolChain *>(tc);
res << gtc->platformCodeGenFlags();
}
if (!SysRootKitInformation::sysRoot(kit).isEmpty())
res << QLatin1String("-sdk") << SysRootKitInformation::sysRoot(kit).toString();
res << QLatin1String("SYMROOT=") + IosManager::resDirForTarget(target());
return res;
}
QString IosBuildStep::buildCommand() const
{
return QLatin1String("xcodebuild"); // add path?
}
void IosBuildStep::run(QFutureInterface<bool> &fi)
{
bool canContinue = true;
foreach (const Task &t, m_tasks) {
addTask(t);
canContinue = false;
}
if (!canContinue) {
emit addOutput(tr("Configuration is faulty. Check the Issues output pane for details."),
BuildStep::MessageOutput);
fi.reportResult(false);
emit finished();
return;
}
AbstractProcessStep::run(fi);
}
BuildStepConfigWidget *IosBuildStep::createConfigWidget()
{
return new IosBuildStepConfigWidget(this);
}
bool IosBuildStep::immutable() const
{
return false;
}
void IosBuildStep::setBaseArguments(const QStringList &args)
{
m_baseBuildArguments = args;
m_useDefaultArguments = (args == defaultArguments());
}
void IosBuildStep::setExtraArguments(const QStringList &extraArgs)
{
m_extraArguments = extraArgs;
}
QStringList IosBuildStep::baseArguments() const
{
if (m_useDefaultArguments)
return defaultArguments();
return m_baseBuildArguments;
}
//
// IosBuildStepConfigWidget
//
IosBuildStepConfigWidget::IosBuildStepConfigWidget(IosBuildStep *buildStep)
: m_buildStep(buildStep)
{
m_ui = new Ui::IosBuildStep;
m_ui->setupUi(this);
Project *pro = m_buildStep->target()->project();
m_ui->buildArgumentsTextEdit->setPlainText(Utils::QtcProcess::joinArgs(
m_buildStep->baseArguments()));
m_ui->extraArgumentsLineEdit->setText(Utils::QtcProcess::joinArgs(
m_buildStep->m_extraArguments));
m_ui->resetDefaultsButton->setEnabled(!m_buildStep->m_useDefaultArguments);
updateDetails();
connect(m_ui->buildArgumentsTextEdit, SIGNAL(textChanged()),
this, SLOT(buildArgumentsChanged()));
connect(m_ui->resetDefaultsButton, SIGNAL(clicked()),
this, SLOT(resetDefaultArguments()));
connect(m_ui->extraArgumentsLineEdit, SIGNAL(editingFinished()),
this, SLOT(extraArgumentsChanged()));
connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
this, SLOT(updateDetails()));
connect(m_buildStep->target(), SIGNAL(kitChanged()),
this, SLOT(updateDetails()));
connect(pro, SIGNAL(environmentChanged()),
this, SLOT(updateDetails()));
}
IosBuildStepConfigWidget::~IosBuildStepConfigWidget()
{
delete m_ui;
}
QString IosBuildStepConfigWidget::displayName() const
{
return tr("iOS build", "iOS BuildStep display name.");
}
void IosBuildStepConfigWidget::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->buildCommand());
param.setArguments(Utils::QtcProcess::joinArgs(m_buildStep->allArguments()));
m_summaryText = param.summary(displayName());
emit updateSummary();
}
QString IosBuildStepConfigWidget::summaryText() const
{
return m_summaryText;
}
void IosBuildStepConfigWidget::buildArgumentsChanged()
{
m_buildStep->setBaseArguments(Utils::QtcProcess::splitArgs(
m_ui->buildArgumentsTextEdit->toPlainText()));
m_ui->resetDefaultsButton->setEnabled(!m_buildStep->m_useDefaultArguments);
updateDetails();
}
void IosBuildStepConfigWidget::resetDefaultArguments()
{
m_buildStep->setBaseArguments(m_buildStep->defaultArguments());
m_ui->buildArgumentsTextEdit->setPlainText(Utils::QtcProcess::joinArgs(
m_buildStep->baseArguments()));
m_ui->resetDefaultsButton->setEnabled(!m_buildStep->m_useDefaultArguments);
}
void IosBuildStepConfigWidget::extraArgumentsChanged()
{
m_buildStep->setExtraArguments(Utils::QtcProcess::splitArgs(
m_ui->extraArgumentsLineEdit->text()));
}
//
// IosBuildStepFactory
//
IosBuildStepFactory::IosBuildStepFactory(QObject *parent) :
IBuildStepFactory(parent)
{
}
bool IosBuildStepFactory::canCreate(BuildStepList *parent, const Id) const
{
if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_CLEAN
&& parent->id() != ProjectExplorer::Constants::BUILDSTEPS_BUILD)
return false;
Kit *kit = parent->target()->kit();
Core::Id deviceType = DeviceTypeKitInformation::deviceTypeId(kit);
return (deviceType == Constants::IOS_DEVICE_TYPE
|| deviceType == Constants::IOS_SIMULATOR_TYPE);
}
BuildStep *IosBuildStepFactory::create(BuildStepList *parent, const Id id)
{
if (!canCreate(parent, id))
return 0;
IosBuildStep *step = new IosBuildStep(parent);
if (parent->id() == ProjectExplorer::Constants::BUILDSTEPS_CLEAN) {
step->setClean(true);
step->setExtraArguments(QStringList(QLatin1String("clean")));
} else if (parent->id() == ProjectExplorer::Constants::BUILDSTEPS_BUILD) {
// nomal setup
}
return step;
}
bool IosBuildStepFactory::canClone(BuildStepList *parent, BuildStep *source) const
{
return canCreate(parent, source->id());
}
BuildStep *IosBuildStepFactory::clone(BuildStepList *parent, BuildStep *source)
{
if (!canClone(parent, source))
return 0;
IosBuildStep *old(qobject_cast<IosBuildStep *>(source));
Q_ASSERT(old);
return new IosBuildStep(parent, old);
}
bool IosBuildStepFactory::canRestore(BuildStepList *parent, const QVariantMap &map) const
{
return canCreate(parent, idFromMap(map));
}
BuildStep *IosBuildStepFactory::restore(BuildStepList *parent, const QVariantMap &map)
{
if (!canRestore(parent, map))
return 0;
IosBuildStep *bs(new IosBuildStep(parent));
if (bs->fromMap(map))
return bs;
delete bs;
return 0;
}
QList<Id> IosBuildStepFactory::availableCreationIds(BuildStepList *parent) const
{
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(IOS_BUILD_STEP_ID);
return QList<Id>();
}
QString IosBuildStepFactory::displayNameForId(const Id id) const
{
if (id == IOS_BUILD_STEP_ID)
return QCoreApplication::translate("GenericProjectManager::Internal::IosBuildStep",
IOS_BUILD_STEP_DISPLAY_NAME);
return QString();