summaryrefslogtreecommitdiff
path: root/src/plugins/ios/iosprobe.cpp
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@digia.com>2013-04-25 16:02:17 +0200
committerEike Ziller <eike.ziller@digia.com>2013-10-02 13:15:49 +0200
commit8d96ce557ef5b49d0cfea2b1633e09354948088c (patch)
tree8810583d9685f954b0d7ea6689b314fb2f2eb4bb /src/plugins/ios/iosprobe.cpp
parent3a7d91ca4404937889986c54b730d7b01208cc27 (diff)
downloadqt-creator-8d96ce557ef5b49d0cfea2b1633e09354948088c.tar.gz
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: Eike Ziller <eike.ziller@digia.com>
Diffstat (limited to 'src/plugins/ios/iosprobe.cpp')
-rw-r--r--src/plugins/ios/iosprobe.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp
new file mode 100644
index 0000000000..318220cb8d
--- /dev/null
+++ b/src/plugins/ios/iosprobe.cpp
@@ -0,0 +1,355 @@
+/****************************************************************************
+**
+** 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 "iosprobe.h"
+#include <QDebug>
+#include <QFileInfo>
+#include <QProcess>
+#include <QDir>
+#include <QFileInfoList>
+
+static const bool debugProbe = false;
+
+namespace Ios {
+
+static QString qsystem(const QString &exe, const QStringList &args = QStringList())
+{
+ QProcess p;
+ p.setProcessChannelMode(QProcess::MergedChannels);
+ p.start(exe, args);
+ p.waitForFinished();
+ return QString::fromLocal8Bit(p.readAll());
+}
+
+QMap<QString, Platform> IosProbe::detectPlatforms(const QString &devPath)
+{
+ IosProbe probe;
+ probe.addDeveloperPath(devPath);
+ probe.detectAll();
+ return probe.detectedPlatforms();
+}
+
+int IosProbe::compareVersions(const QString &v1, const QString &v2)
+{
+ QStringList v1L = v1.split(QLatin1Char('.'));
+ QStringList v2L = v2.split(QLatin1Char('.'));
+ int i = 0;
+ while (v1.length() > i && v1.length() > i) {
+ bool n1Ok, n2Ok;
+ int n1 = v1L.value(i).toInt(&n1Ok);
+ int n2 = v2L.value(i).toInt(&n2Ok);
+ if (!(n1Ok && n2Ok)) {
+ qDebug() << QString::fromLatin1("Failed to compare version %1 and %2").arg(v1,v2);
+ return 0;
+ }
+ if (n1 > n2)
+ return -1;
+ else if (n1 < n2)
+ return 1;
+ ++i;
+ }
+ if (v1.length() > v2.length())
+ return -1;
+ if (v1.length() < v2.length())
+ return 1;
+ return 0;
+}
+
+bool IosProbe::addDeveloperPath(const QString &path)
+{
+ if (path.isEmpty())
+ return false;
+ QFileInfo pInfo(path);
+ if (!pInfo.exists() || !pInfo.isDir())
+ return false;
+ if (m_developerPaths.contains(path))
+ return false;
+ m_developerPaths.append(path);
+ if (debugProbe)
+ qDebug() << QString::fromLatin1("Added developer path %1").arg(path);
+ return true;
+}
+
+void IosProbe::detectDeveloperPaths()
+{
+ QProcess selectedXcode;
+ QString program = QLatin1String("/usr/bin/xcode-select");
+ QStringList arguments(QLatin1String("--print-path"));
+ selectedXcode.start(program, arguments, QProcess::ReadOnly);
+ if (!selectedXcode.waitForFinished() || selectedXcode.exitCode()) {
+ qDebug() << QString::fromLatin1("Could not detect selected xcode with /usr/bin/xcode-select");
+ } else {
+ QString path = QString::fromLocal8Bit(selectedXcode.readAllStandardOutput());
+ addDeveloperPath(path);
+ }
+ addDeveloperPath(QLatin1String("/Applications/Xcode.app/Contents/Developer"));
+}
+
+void IosProbe::setArch(Platform *platform, const QString &pathToGcc, const QStringList &extraFlags)
+{
+ if (!extraFlags.isEmpty())
+ platform->backendFlags = extraFlags;
+ // setting architecture and endianness only here, bercause the same compiler
+ // can support several ones
+ QStringList flags(extraFlags);
+ flags << QLatin1String("-dumpmachine");
+ QString compilerTriplet = qsystem(pathToGcc, flags).simplified();
+ QStringList compilerTripletl = compilerTriplet.split(QLatin1Char('-'));
+ if (compilerTripletl.count() < 2) {
+ qDebug() << QString::fromLatin1("Detected '%1', but I don't understand "
+ "its architecture '%2'.")
+ .arg(pathToGcc, compilerTriplet);
+ return;
+ }
+
+ QString endianness, architecture;
+ architecture = compilerTripletl.at(0);
+ endianness = QLatin1String("little");
+
+ if (debugProbe)
+ qDebug() << QString::fromLatin1(" Toolchain %1 detected:\n"
+ " binary: %2\n"
+ " triplet: %3\n"
+ " arch: %4").arg(platform->name, pathToGcc,
+ compilerTriplet, architecture);
+
+ platform->architecture = architecture;
+}
+
+void IosProbe::setupDefaultToolchains(const QString &devPath, const QString &xCodeName)
+{
+ if (debugProbe)
+ qDebug() << QString::fromLatin1("Setting up platform '%1'.").arg(xCodeName);
+ QString indent = QLatin1String(" ");
+
+ // detect clang (default toolchain)
+ QFileInfo clangFileInfo(devPath
+ + QLatin1String("/Toolchains/XcodeDefault.xctoolchain/usr/bin")
+ + QLatin1String("/clang++"));
+ bool hasClang = clangFileInfo.exists();
+ QSettingsPtr toolchainInfo;
+ if (hasClang)
+ toolchainInfo = QSettingsPtr(new QSettings(
+ devPath + QLatin1String("/Toolchains/XcodeDefault.xctoolchain/ToolchainInfo.plist")
+ , QSettings::NativeFormat));
+ else
+ qDebug() << indent << QString::fromLatin1("Default toolchain %1 not found.")
+ .arg(clangFileInfo.canonicalFilePath());
+ // Platforms
+ QDir platformsDir(devPath + QLatin1String("/Platforms"));
+ QFileInfoList platforms = platformsDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ foreach (const QFileInfo &fInfo, platforms) {
+ if (fInfo.isDir() && fInfo.suffix() == QLatin1String("platform")) {
+ if (debugProbe)
+ qDebug() << indent << QString::fromLatin1("Setting up %1").arg(fInfo.fileName());
+ QSettingsPtr infoSettings(new QSettings(
+ fInfo.absoluteFilePath() + QLatin1String("/Info.plist")
+ , QSettings::NativeFormat));
+ if (!infoSettings->contains(QLatin1String("Name"))) {
+ qDebug() << indent << QString::fromLatin1("Missing platform name in Info.plist of %1")
+ .arg(fInfo.absoluteFilePath());
+ continue;
+ }
+ QString targetOS;
+ QString name = infoSettings->value(QLatin1String("Name")).toString();
+ if (name != QLatin1String("macosx") && name != QLatin1String("iphoneos")
+ && name != QLatin1String("iphonesimulator"))
+ {
+ qDebug() << indent << QString::fromLatin1("Skipping unknown platform %1").arg(name);
+ continue;
+ }
+
+ // prepare default platform properties
+ QVariantMap defaultProp = infoSettings->value(QLatin1String("DefaultProperties"))
+ .toMap();
+ QVariantMap overrideProp = infoSettings->value(QLatin1String("OverrideProperties"))
+ .toMap();
+ QMapIterator<QString, QVariant> i(overrideProp);
+ while (i.hasNext()) {
+ i.next();
+ // use unite? might lead to double insertions...
+ defaultProp[i.key()] = i.value();
+ }
+
+ QString clangFullName = name + QLatin1String("-clang") + xCodeName;
+ QString clang11FullName = name + QLatin1String("-clang11") + xCodeName;
+ // detect gcc
+ QFileInfo gccFileInfo(fInfo.absoluteFilePath() + QLatin1String("/Developer/usr/bin/g++"));
+ QString gccFullName = name + QLatin1String("-gcc") + xCodeName;
+ if (!gccFileInfo.exists())
+ gccFileInfo = QFileInfo(devPath + QLatin1String("/usr/bin/g++"));
+ bool hasGcc = gccFileInfo.exists();
+
+ QStringList extraFlags;
+ if (defaultProp.contains(QLatin1String("ARCHS"))) {
+ QString arch = defaultProp.value(QLatin1String("ARCHS")).toString();
+ if (arch == QLatin1String("$(NATIVE_ARCH_32_BIT)"))
+ extraFlags << QLatin1String("-arch") << QLatin1String("i386");
+ }
+ if (defaultProp.contains(QLatin1String("NATIVE_ARCH"))) {
+ QString arch = defaultProp.value(QLatin1String("NATIVE_ARCH")).toString();
+ if (!arch.startsWith(QLatin1String("arm")))
+ qDebug() << indent << QString::fromLatin1("Expected arm architecture, not %1").arg(arch);
+ extraFlags << QLatin1String("-arch") << arch;
+ }
+ if (hasClang) {
+ Platform clangProfile;
+ clangProfile.platformKind = 0;
+ clangProfile.name = clangFullName;
+ clangProfile.platformPath = Utils::FileName(fInfo);
+ clangProfile.platformInfo = infoSettings;
+ clangProfile.compilerPath = Utils::FileName(clangFileInfo);
+ setArch(&clangProfile, clangFileInfo.canonicalFilePath(), extraFlags);
+ if (debugProbe)
+ qDebug() << indent << QString::fromLatin1("* adding profile %1").arg(clangProfile.name);
+ this->m_platforms[clangProfile.name] = clangProfile;
+ clangProfile.platformKind |= Platform::Cxx11Support;
+ clangProfile.backendFlags.append(QLatin1String("-std=c++11"));
+ clangProfile.backendFlags.append(QLatin1String("-stdlib=libc++"));
+ clangProfile.name = clang11FullName;
+ this->m_platforms[clangProfile.name] = clangProfile;
+ }
+ if (hasGcc) {
+ Platform gccProfile;
+ gccProfile.name = gccFullName;
+ gccProfile.platformKind = 0;
+ // use the arm-apple-darwin10-llvm-* variant and avoid the extraFlags if available???
+ gccProfile.platformPath = Utils::FileName(fInfo);
+ gccProfile.platformInfo = infoSettings;
+ gccProfile.compilerPath = Utils::FileName(gccFileInfo);
+ setArch(&gccProfile, gccFileInfo.canonicalFilePath(), extraFlags);
+ if (debugProbe)
+ qDebug() << indent << QString::fromLatin1("* adding profile %1").arg(gccProfile.name);
+ this->m_platforms[gccProfile.name] = gccProfile;
+ }
+
+ // set SDKs/sysroot
+ QString sysRoot;
+ QSettingsPtr sdkSettings;
+ {
+ QString sdkName;
+ if (defaultProp.contains(QLatin1String("SDKROOT")))
+ sdkName = defaultProp.value(QLatin1String("SDKROOT")).toString();
+ QString sdkPath;
+ QDir sdks(fInfo.absoluteFilePath() + QLatin1String("/Developer/SDKs"));
+ QString maxVersion;
+ foreach (const QFileInfo &sdkDirInfo, sdks.entryInfoList(QDir::Dirs
+ | QDir::NoDotAndDotDot)) {
+ indent = QLatin1String(" ");
+ QSettingsPtr sdkInfo(new QSettings(sdkDirInfo.absoluteFilePath()
+ + QLatin1String("/SDKSettings.plist")
+ , QSettings::NativeFormat));
+ QString versionStr = sdkInfo->value(QLatin1String("Version")).toString();
+ QVariant currentSdkName = sdkInfo->value(QLatin1String("CanonicalName"));
+ bool isBaseSdk = sdkInfo->value((QLatin1String("isBaseSDK"))).toString()
+ .toLower() != QLatin1String("no");
+ if (!isBaseSdk) {
+ if (debugProbe)
+ qDebug() << indent << QString::fromLatin1("Skipping non base Sdk %1")
+ .arg(currentSdkName.toString());
+ continue;
+ }
+ QString safeName = currentSdkName.toString().replace(QLatin1Char('-'), QLatin1Char('_'))
+ .replace(QRegExp(QLatin1String("[^-a-zA-Z0-9]")),QLatin1String("-"));
+ if (sdkName.isEmpty()) {
+ if (compareVersions(maxVersion,versionStr) > 0) {
+ maxVersion = versionStr;
+ sdkPath = sdkDirInfo.canonicalFilePath();
+ sdkSettings = sdkInfo;
+ }
+ } else if (currentSdkName == sdkName) {
+ sdkPath = sdkDirInfo.canonicalFilePath();
+ sdkSettings = sdkInfo;
+ }
+ if (hasClang){
+ Platform pSdk;
+ pSdk = this->m_platforms[clangFullName];
+ pSdk.name = safeName + QLatin1String("-clang") + xCodeName;
+ pSdk.sdkPath = Utils::FileName(sdkDirInfo);
+ pSdk.sdkSettings = sdkInfo;
+ if (debugProbe)
+ qDebug() << indent << QString::fromLatin1("* adding profile %1").arg(pSdk.name);
+ this->m_platforms[pSdk.name] = pSdk;
+ pSdk.backendFlags.append(QLatin1String("-std=c++11"));
+ pSdk.backendFlags.append(QLatin1String("-stdlib=libc++"));
+ pSdk.name = safeName + QLatin1String("-clang11") + xCodeName;
+ this->m_platforms[pSdk.name] = pSdk;
+ }
+ if (hasGcc) {
+ Platform pSdk;
+ pSdk = this->m_platforms[gccFullName];
+ pSdk.name = safeName + QLatin1String("-gcc") + xCodeName;
+ pSdk.sdkPath = Utils::FileName(sdkDirInfo);
+ pSdk.sdkSettings = sdkInfo;
+ if (debugProbe)
+ qDebug() << indent << QString::fromLatin1("* adding profile %1").arg(pSdk.name);
+ this->m_platforms[pSdk.name] = pSdk;
+ }
+ }
+ if (!sdkPath.isEmpty())
+ sysRoot = sdkPath;
+ else if (!sdkName.isEmpty())
+ qDebug() << indent << QString::fromLatin1("Failed to find sysroot %1").arg(sdkName);
+ }
+ //this->m_platforms.remove(clangFullName);
+ if (hasClang && !sysRoot.isEmpty()) {
+ this->m_platforms[clangFullName].platformKind |= Platform::BasePlatform;
+ this->m_platforms[clangFullName].sdkPath = Utils::FileName::fromString(sysRoot);
+ this->m_platforms[clangFullName].sdkSettings = sdkSettings;
+ this->m_platforms[clang11FullName].platformKind |= Platform::BasePlatform;
+ this->m_platforms[clang11FullName].sdkPath = Utils::FileName::fromString(sysRoot);
+ this->m_platforms[clang11FullName].sdkSettings = sdkSettings;
+ }
+ //this->m_platforms.remove(gccFullName);
+ if (hasGcc && !sysRoot.isEmpty()) {
+ this->m_platforms[gccFullName].platformKind |= Platform::BasePlatform;
+ this->m_platforms[gccFullName].sdkPath = Utils::FileName::fromString(sysRoot);
+ this->m_platforms[gccFullName].sdkSettings = sdkSettings;
+ }
+ }
+ indent = QLatin1String(" ");
+ }
+}
+
+void IosProbe::detectAll()
+{
+ detectDeveloperPaths();
+ QString xcodeName = QLatin1String("");
+ for (int iXcode = 0; iXcode < m_developerPaths.count(); ++iXcode) {
+ setupDefaultToolchains(m_developerPaths.value(iXcode), xcodeName);
+ xcodeName = QString::fromLatin1("-%1").arg(iXcode + 2);
+ }
+}
+
+QMap<QString, Platform> IosProbe::detectedPlatforms()
+{
+ return m_platforms;
+}
+
+}