summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@digia.com>2013-03-19 22:02:56 +0100
committerFawzi Mohamed <fawzi.mohamed@digia.com>2013-04-02 17:51:08 +0200
commit3059ab7aeb2695d32c1a03455e376265e3af4c1c (patch)
tree5296ef63dd65b3ff2386ac410a8324c01fa07673
parent67365f0cc01233dab7ecffe17c128dd6e3e26a3d (diff)
downloadqbs-3059ab7aeb2695d32c1a03455e376265e3af4c1c.tar.gz
Add iOS module and move OS X/iOS common code to DarwinGCC
Change-Id: I2fea6a7eddd599c70336f351b6814bfe335edd79 Reviewed-by: Jake Petroules <jake.petroules@petroules.com> Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
-rw-r--r--share/qbs/modules/cpp/DarwinGCC.qbs69
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs3
-rw-r--r--share/qbs/modules/cpp/darwin-tools.js4
-rw-r--r--share/qbs/modules/cpp/ios-gcc.qbs193
-rw-r--r--share/qbs/modules/cpp/mac-gcc.qbs34
-rw-r--r--src/app/detect-toolchains/osxprobe.cpp420
6 files changed, 511 insertions, 212 deletions
diff --git a/share/qbs/modules/cpp/DarwinGCC.qbs b/share/qbs/modules/cpp/DarwinGCC.qbs
new file mode 100644
index 000000000..10dc2ae1d
--- /dev/null
+++ b/share/qbs/modules/cpp/DarwinGCC.qbs
@@ -0,0 +1,69 @@
+import qbs 1.0
+import '../utils.js' as ModUtils
+import 'darwin-tools.js' as Tools
+
+UnixGCC {
+ condition: false
+
+ compilerDefines: ["__GNUC__", "__APPLE__"]
+ dynamicLibrarySuffix: ".dylib"
+
+ property var defaultInfoPlist
+ property var infoPlist: defaultInfoPlist
+ property bool buildDsym: qbs.buildVariant === "release"
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs"]
+
+ Artifact {
+ fileName: product.targetName + ".app/" +
+ (product.moduleProperty("qbs", "targetOS") === "mac" ? "Contents/" : "") +
+ "PkgInfo"
+ fileTags: ["pkginfo"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating PkgInfo";
+ cmd.highlight = "codegen";
+ var pkgType = 'APPL';
+ var pkgSign = '????';
+ var infoPlist = product.moduleProperty("cpp", "infoPList");
+ if (infoPlist && infoPlist.hasOwnProperty('CFBundlePackageType'))
+ pkgType = infoPlist['CFBundlePackageType'];
+ if (infoPlist && infoPlist.hasOwnProperty('CFBundleSignature'))
+ pkgSign = infoPlist['CFBundleSignature'];
+ cmd.pkgInfo = pkgType + pkgSign;
+ cmd.sourceCode = function() {
+ var pkginfo = new TextFile(outputs.pkginfo[0].fileName, TextFile.WriteOnly);
+ pkginfo.write(pkgInfo);
+ pkginfo.close();
+ }
+ return cmd;
+ }
+ }
+
+ Rule {
+ inputs: ["application"]
+
+ Artifact {
+ fileName: input.fileName + ".app.dSYM"
+ fileTags: ["dsym"]
+ }
+
+ prepare: {
+ if (!product.moduleProperty("cpp", "buildDsym")) {
+ // to be removed when dynamic dependencies work
+ var cmd = new JavaScriptCommand();
+ cmd.description = "skipping dsym generation";
+ cmd.highlight = "codegen";
+ return cmd;
+ }
+ var cmd = new Command("dsymutil", ["--out=" + outputs.dsym[0].fileName, input.fileName]);
+ cmd.description = "generating dsym";
+ cmd.highlight = "codegen";
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
index 2b56d242f..2f2d101d0 100644
--- a/share/qbs/modules/cpp/GenericGCC.qbs
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -169,7 +169,8 @@ CppModule {
Artifact {
fileName: product.destinationDirectory + "/"
- + (product.type === "applicationbundle" ? product.targetName + ".app/Contents/MacOS/" : "")
+ + (product.type !== "applicationbundle" ? "" : product.targetName + ".app/" +
+ (product.moduleProperty("qbs", "targetOS") !== "mac" ? "" : "Contents/MacOS/"))
+ ModUtils.moduleProperty(product, "executablePrefix")
+ product.targetName + ModUtils.moduleProperty(product, "executableSuffix")
fileTags: ["application"]
diff --git a/share/qbs/modules/cpp/darwin-tools.js b/share/qbs/modules/cpp/darwin-tools.js
new file mode 100644
index 000000000..fd7fe83b3
--- /dev/null
+++ b/share/qbs/modules/cpp/darwin-tools.js
@@ -0,0 +1,4 @@
+function rfc1034(inStr)
+{
+ return inStr.replace(/[^-A-Za-z0-9.]/g,'-');
+}
diff --git a/share/qbs/modules/cpp/ios-gcc.qbs b/share/qbs/modules/cpp/ios-gcc.qbs
new file mode 100644
index 000000000..bba09d469
--- /dev/null
+++ b/share/qbs/modules/cpp/ios-gcc.qbs
@@ -0,0 +1,193 @@
+import qbs 1.0
+import '../utils.js' as ModUtils
+import 'darwin-tools.js' as Tools
+
+DarwinGCC {
+ condition: qbs.hostOS === 'mac' && qbs.targetOS === 'ios' && qbs.toolchain === 'gcc'
+
+ property string signingIdentity
+ property string provisionFile
+ property bool buildIpa: qbs.architecture.match("^arm") === "arm"
+
+ defaultInfoPlist: {
+ var baseName = String(product.targetName).substring(product.targetName.lastIndexOf('/') + 1);
+ var baseNameRfc1034 = Tools.rfc1034(baseName);
+ var defaultVal = {
+ CFBundleName: baseName,
+ CFBundleIdentifier: "org.example." + baseNameRfc1034,
+ CFBundleInfoDictionaryVersion : "6.0",
+ CFBundleVersion: "1.0", // version of the app
+ CFBundleShortVersionString: "1.0", // user visible version of the app
+ // this and the following MainStoryboard related keys are iOS 6 only, and are only to
+ // use "storyboards" for UI, which we most likely won't, so we can avoid using
+ // these keys (and stay compatible with previous iOS versions)
+ // "UIMainStoryboardFile" : "MainStoryboard_iPhone",
+ // "UIMainStoryboardFile~ipad" : "MainStoryboard_iPad",
+ CFBundleExecutable: baseName,
+ LSRequiresIPhoneOS: true,
+ UIRequiredDeviceCapabilities : [
+ // architectures supported, to support iPhone 3G for example one has to add
+ // armv6 to the list and also compile for it (with Xcode 4.4.1 or earlier)
+ "armv7"
+ ],
+ CFBundleDisplayName: baseName,
+ CFBundlePackageType: "APPL",
+ CFBundleSignature: "????", // legacy creator code in macOS Classic, can be ignored
+ CFBundleDevelopmentRegion: "en", // default localization
+ UISupportedInterfaceOrientations: [
+ "UIInterfaceOrientationPortrait",
+ "UIInterfaceOrientationLandscapeLeft",
+ "UIInterfaceOrientationLandscapeRight"
+ ],
+ "UISupportedInterfaceOrientations~ipad": [
+ "UIInterfaceOrientationPortrait",
+ "UIInterfaceOrientationPortraitUpsideDown",
+ "UIInterfaceOrientationLandscapeLeft",
+ "UIInterfaceOrientationLandscapeRight"
+ ]
+ }
+ return defaultVal
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs"]
+
+ Artifact {
+ fileName: product.targetName + ".app/Info.plist"
+ fileTags: ["infoplist"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating Info.plist";
+ cmd.highlight = "codegen";
+ cmd.infoPlist = ModUtils.moduleProperty(product, "infoPlist") || {};
+ cmd.platformPath = product.moduleProperty("cpp","platformPath");
+ cmd.sourceCode = function() {
+ var defaultValues = ModUtils.moduleProperty(product, "defaultInfoPlist");
+ var key;
+ for (key in defaultValues) {
+ if (defaultValues.hasOwnProperty(key) && !(key in infoPlist))
+ infoPlist[key] = defaultValues[key];
+ }
+
+ var process;
+ if (platformPath) {
+ process = new Process();
+ process.start("plutil", ["-convert", "json", "-o", "-",
+ platformPath + "/Info.plist"]);
+ process.waitForFinished();
+ platformInfo = JSON.parse(process.readAll());
+
+ var additionalProps = platformInfo["AdditionalInfo"];
+ for (key in additionalProps) {
+ if (additionalProps.hasOwnProperty(key) && !(key in infoPlist)) // override infoPlist?
+ infoPlist[key] = defaultValues[key];
+ }
+ key = "UIDeviceFamily";
+ if (key in platformInfo && !(key in infoPlist))
+ infoPlist[key] = platformInfo[key];
+ } else {
+ print("Missing platformPath property");
+ }
+
+ process = new Process();
+ process.start("sw_vers", ["-buildVersion"]);
+ process.waitForFinished();
+ infoPlist["BuildMachineOSBuild"] = process.readAll().trim();
+
+ var infoplist = new TextFile(outputs.infoplist[0].fileName, TextFile.WriteOnly);
+ infoplist.write(JSON.stringify(infoPlist));
+ infoplist.close();
+
+ process = new Process();
+ process.start("plutil", ["-convert", "binary1", outputs.infoplist[0].fileName]);
+ process.waitForFinished();
+ }
+ return cmd;
+ }
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs"]
+
+ Artifact {
+ fileName: product.targetName + ".app/ResourceRules.plist"
+ fileTags: ["resourcerules"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating ResourceRules";
+ cmd.highlight = "codegen";
+ cmd.sysroot = product.moduleProperty("qbs","sysroot");
+ cmd.sourceCode = function() {
+ File.copy(sysroot + "/ResourceRules.plist", outputs.resourcerules[0].fileName);
+ }
+ return cmd;
+ }
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["application", "infoplist", "pkginfo", "resourcerules"]
+
+ Artifact {
+ fileName: product.targetName + ".ipa"
+ fileTags: ["ipa"]
+ }
+
+ prepare: {
+ if (!(product.moduleProperty("qbs","architecture").match("^arm"))) {
+ // to be removed when dynamic dependencies work
+ var cmd = new JavaScriptCommand();
+ cmd.description = "skipping ipa for simulator on arch " +
+ product.moduleProperty("qbs", "architecture");
+ cmd.highlight = "codegen";
+ return cmd;
+ }
+ var signingIdentity = product.moduleProperty("cpp", "signingIdentity");
+ if (!signingIdentity)
+ throw "The name of a valid Signing identity should be stored in cpp.signingIdentity to build package.";
+ var provisionFile = product.moduleProperty("cpp", "provisionFile");
+ if (!provisionFile)
+ throw "The path to a provision file is required in key cpp.provisionFile to build package.";
+ args = ["-sdk", "iphoneos", "PackageApplication", "-v",
+ product.buildDirectory + "/" + product.targetName + ".app",
+ "-o", outputs.ipa[0].fileName, "--sign", signingIdentity,
+ "--embed", provisionFile]
+ var command = "/usr/bin/xcrun";
+ var cmd = new Command(command, args)
+ cmd.description = "creating ipa";
+ cmd.highlight = "codegen";
+ cmd.workingDirectory = product.buildDirectory;
+ return cmd;
+ }
+ }
+
+ Rule {
+ multiplex: true
+ inputs: {
+ var res = ["application", "infoplist", "pkginfo", "resourcerules"];
+ // if (product.moduleProperty("cpp", "buildDsym")) // should work like that in the future
+ res.push("dsym");
+ // if (ModUtils.moduleProperty(product, "buildIpa")) // ditto
+ res.push("ipa");
+ return res;
+ }
+
+ Artifact {
+ fileName: product.targetName + ".app"
+ fileTags: ["applicationbundle"]
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "creating app bundle";
+ cmd.highlight = "codegen";
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/mac-gcc.qbs b/share/qbs/modules/cpp/mac-gcc.qbs
index 455298534..89f239047 100644
--- a/share/qbs/modules/cpp/mac-gcc.qbs
+++ b/share/qbs/modules/cpp/mac-gcc.qbs
@@ -1,15 +1,10 @@
import qbs 1.0
import '../utils.js' as ModUtils
+import 'darwin-tools.js' as Tools
-UnixGCC {
+DarwinGCC {
condition: qbs.hostOS === 'mac' && qbs.targetOS === 'mac' && qbs.toolchain === 'gcc'
- compilerDefines: ["__GNUC__", "__APPLE__"]
- dynamicLibrarySuffix: ".dylib"
-
- property string infoPlist
- property string pkgInfo
-
Rule {
multiplex: true
inputs: ["qbs"]
@@ -76,30 +71,7 @@ UnixGCC {
Rule {
multiplex: true
- inputs: ["qbs"]
-
- Artifact {
- fileName: product.targetName + ".app/Contents/PkgInfo"
- fileTags: ["pkginfo"]
- }
-
- prepare: {
- var cmd = new JavaScriptCommand();
- cmd.description = "generating PkgInfo";
- cmd.highlight = "codegen";
- cmd.pkgInfo = ModUtils.moduleProperty(product, "pkgInfo") || "FOO";
- cmd.sourceCode = function() {
- var pkginfo = new TextFile(outputs.pkginfo[0].fileName, TextFile.WriteOnly);
- pkginfo.write(pkgInfo);
- pkginfo.close();
- }
- return cmd;
- }
- }
-
- Rule {
- multiplex: true
- inputs: ["application", "infoplist", "pkginfo"]
+ inputs: ["application", "infoplist", "pkginfo", "dsym"]
Artifact {
fileName: product.targetName + ".app"
diff --git a/src/app/detect-toolchains/osxprobe.cpp b/src/app/detect-toolchains/osxprobe.cpp
index b58ab9eae..f5508aafa 100644
--- a/src/app/detect-toolchains/osxprobe.cpp
+++ b/src/app/detect-toolchains/osxprobe.cpp
@@ -42,6 +42,7 @@
#include <QFileInfo>
#include <QDir>
#include <QSettings>
+#include <QRegExp>
using namespace qbs;
using Internal::Tr;
@@ -60,159 +61,236 @@ static QString qsystem(const QString &exe, const QStringList &args = QStringList
class OsxProbe
{
public:
- qbs::Settings *settings;
- QList<qbs::Profile> &profiles;
- QStringList developerPaths;
OsxProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles)
: settings(settings), profiles(profiles)
{ }
- bool addDeveloperPath(const QString &path)
- {
- if (path.isEmpty())
- return false;
- QFileInfo pInfo(path);
- if (!pInfo.exists() || !pInfo.isDir())
- return false;
- if (developerPaths.contains(path))
- return false;
- developerPaths.append(path);
- qbsInfo() << Tr::tr("Added developer path %1").arg(path);
- return true;
- }
+ static int compareVersions(const QString &v1, const QString &v2);
+ bool addDeveloperPath(const QString &path);
+ void detectDeveloperPaths();
+ void setArch(Profile *profile, const QString &pathToGcc, const QStringList &extraFlags);
+ void setupDefaultToolchains(const QString &devPath, const QString &xCodeName);
+ void detectAll();
+private:
+ qbs::Settings *settings;
+ QList<qbs::Profile> &profiles;
+ QStringList developerPaths;
+};
- void detectDeveloperPaths()
- {
- QProcess selectedXcode;
- QString program = "/usr/bin/xcode-select";
- QStringList arguments(QLatin1String("--print-path"));
- selectedXcode.start(program, arguments, QProcess::ReadOnly);
- if (!selectedXcode.waitForFinished() || selectedXcode.exitCode()) {
- qbsInfo() << Tr::tr("Could not detect selected xcode with /usr/bin/xcode-select");
- } else {
- QString path = QString::fromLocal8Bit(selectedXcode.readAllStandardOutput());
- addDeveloperPath(path);
+int OsxProbe::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)) {
+ qbsInfo() << Tr::tr("Failed to compare version %1 and %2").arg(v1,v2);
+ return 0;
}
- addDeveloperPath(QLatin1String("/Applications/Xcode.app/Contents/Developer"));
+ 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;
+}
- void setArch(Profile *profile, const QString &pathToGcc, const QStringList &extraFlags)
- {
- if (!extraFlags.isEmpty()) {
- profile->setValue("cpp.platformCFlags", extraFlags);
- profile->setValue("cpp.platformCxxFlags", extraFlags);
- profile->setValue("cpp.platformObjcFlags", extraFlags);
- profile->setValue("cpp.platformObjcxxFlags", extraFlags);
- profile->setValue("cpp.platformLinkerFlags", 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('-');
- if (compilerTripletl.count() < 2) {
- qbsError() << QString::fromLocal8Bit("Detected '%1', but I don't understand "
- "its architecture '%2'.")
- .arg(pathToGcc, compilerTriplet);
- return;
- }
-
- QString endianness, architecture;
- architecture = compilerTripletl.at(0);
- endianness = "little";
-
- qbsInfo() << Tr::tr("Toolchain %1 detected:\n"
- " binary: %2\n"
- " triplet: %3\n"
- " arch: %4").arg(profile->name(), pathToGcc, compilerTriplet,
- architecture);
+bool OsxProbe::addDeveloperPath(const QString &path)
+{
+ if (path.isEmpty())
+ return false;
+ QFileInfo pInfo(path);
+ if (!pInfo.exists() || !pInfo.isDir())
+ return false;
+ if (developerPaths.contains(path))
+ return false;
+ developerPaths.append(path);
+ qbsInfo() << Tr::tr("Added developer path %1").arg(path);
+ return true;
+}
- profile->setValue("qbs.endianness", endianness);
- profile->setValue("qbs.architecture", architecture);
+void OsxProbe::detectDeveloperPaths()
+{
+ QProcess selectedXcode;
+ QString program = "/usr/bin/xcode-select";
+ QStringList arguments(QLatin1String("--print-path"));
+ selectedXcode.start(program, arguments, QProcess::ReadOnly);
+ if (!selectedXcode.waitForFinished() || selectedXcode.exitCode()) {
+ qbsInfo() << Tr::tr("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 setupDefaultToolchains(const QString &devPath, const QString &xCodeName)
- {
- qbsInfo() << Tr::tr("Setting up profile '%1'.").arg(xCodeName);
- // default toolchain
- QString toolchainType = xCodeName + QLatin1String("-clang");
- QString pathToGcc;
- {
- QString path = devPath
- + QLatin1String("/Toolchains/XcodeDefault.xctoolchain/usr/bin");
- QString cc = path + QLatin1String("/clang");
- QString cxx = path + QLatin1String("/clang++");
-
-
- QString uname = qsystem("uname", QStringList() << "-m").simplified();
- //QSettings toolchainInfo(devPath
- // + QLatin1String("/Toolchains/XcodeDefault.xctoolchain/ToolchainInfo.plist")
- // , QSettings::NativeFormat);
+void OsxProbe::setArch(Profile *profile, const QString &pathToGcc, const QStringList &extraFlags)
+{
+ if (!extraFlags.isEmpty()) {
+ profile->setValue("cpp.platformCFlags", extraFlags);
+ profile->setValue("cpp.platformCxxFlags", extraFlags);
+ profile->setValue("cpp.platformObjcFlags", extraFlags);
+ profile->setValue("cpp.platformObjcxxFlags", extraFlags);
+ profile->setValue("cpp.platformLinkerFlags", 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('-');
+ if (compilerTripletl.count() < 2) {
+ qbsError() << QString::fromLocal8Bit("Detected '%1', but I don't understand "
+ "its architecture '%2'.")
+ .arg(pathToGcc, compilerTriplet);
+ return;
+ }
- pathToGcc = cxx;
+ QString endianness, architecture;
+ architecture = compilerTripletl.at(0);
+ endianness = "little";
- if (!QFileInfo(pathToGcc).exists()) {
- qbsInfo() << Tr::tr("%1 not found.").arg(cc);
- return;
- }
+ qbsInfo() << Tr::tr(" Toolchain %1 detected:\n"
+ " binary: %2\n"
+ " triplet: %3\n"
+ " arch: %4").arg(profile->name(), pathToGcc, compilerTriplet,
+ architecture);
- QStringList pathToGccL = pathToGcc.split('/');
- QString compilerName = pathToGccL.takeLast();
+ profile->setValue("qbs.endianness", endianness);
+ profile->setValue("qbs.architecture", architecture);
+}
- Profile profile(toolchainType, settings);
- profile.removeProfile();
+void OsxProbe::setupDefaultToolchains(const QString &devPath, const QString &xCodeName)
+{
+ qbsInfo() << Tr::tr("Setting up profile '%1'.").arg(xCodeName);
+ QString indent = QLatin1String(" ");
- // fixme should be cpp.toolchain
- // also there is no toolchain:clang
- profile.setValue("qbs.toolchain", "gcc");
+ // detect clang (default toolchain)
+ QFileInfo clangFileInfo(devPath
+ + QLatin1String("/Toolchains/XcodeDefault.xctoolchain/usr/bin")
+ + QLatin1String("/clang++"));
+ bool hasClang = clangFileInfo.exists();
+ if (!hasClang)
+ qbsInfo() << indent << Tr::tr("Default toolchain %1 not found.")
+ .arg(clangFileInfo.canonicalFilePath());
- if (compilerName.contains('-')) {
- QStringList nl = compilerName.split('-');
- profile.setValue("cpp.compilerName", nl.takeLast());
- profile.setValue("cpp.toolchainPrefix", nl.join("-") + '-');
+ // 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")) {
+ qbsInfo() << indent << Tr::tr("Setting up %1").arg(fInfo.fileName());
+ QSettings infoSettings(fInfo.absoluteFilePath() + QLatin1String("/Info.plist")
+ , QSettings::NativeFormat);
+ if (!infoSettings.contains(QLatin1String("Name"))) {
+ qbsInfo() << indent << Tr::tr("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")) {
+ targetOS = QLatin1String("mac");
+ } else if (name == QLatin1String("iphoneos")) {
+ targetOS = QLatin1String("ios");
+ } else if (name == QLatin1String("iphonesimulator")) {
+ targetOS = QLatin1String("ios");
} else {
- profile.setValue("cpp.compilerName", compilerName);
+ qbsInfo() << indent << Tr::tr("Skipping unknown platform %1").arg(name);
+ continue;
}
- profile.setValue("cpp.toolchainInstallPath", pathToGccL.join("/"));
- qbsInfo() << Tr::tr("Adding default toolchain %1").arg(toolchainType);
- profiles << profile;
- }
- // Platforms
- QDir platformsDir(devPath + QLatin1String("/Platforms"));
+ // 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();
+ }
- QFileInfoList platforms = platformsDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
- foreach (const QFileInfo &fInfo, platforms) {
- if (fInfo.isDir() && fInfo.suffix() == QLatin1String("platform")) {
- qbsInfo() << Tr::tr("Setting up %1").arg(fInfo.fileName());
- QSettings infoSettings(fInfo.absoluteFilePath() + QLatin1String("/Info.plist")
- , QSettings::NativeFormat);
- if (!infoSettings.contains(QLatin1String("Name"))) {
- qbsInfo() << Tr::tr("Missing platform name in Info.plist of %1")
- .arg(fInfo.absoluteFilePath());
- continue;
- }
- QString name = infoSettings.value(QLatin1String("Name")).toString();
- QString fullName = xCodeName + QLatin1Char('-') + name + QLatin1String("-clang");
+ QString clangFullName = xCodeName + QLatin1Char('-') + name + QLatin1String("-clang");
+ // detect gcc
+ QFileInfo gccFileInfo(fInfo.absoluteFilePath() + QLatin1String("/Developer/usr/bin/g++"));
+ QString gccFullName = xCodeName + QLatin1Char('-') + name + QLatin1String("-gcc");
+ if (!gccFileInfo.exists())
+ gccFileInfo = QFileInfo(devPath + QLatin1String("/usr/bin/g++"));
+ bool hasGcc = gccFileInfo.exists();
- Profile p(fullName, settings);
- p.removeProfile();
- if (name == QLatin1String("macosx")) {
- p.setValue("qbs.targetOS", QLatin1String("mac"));
- } else if (name == QLatin1String("iphoneos")
- || name == QLatin1String("iphonesimulator")) {
- p.setValue("qbs.targetOS", "ios");
- } else {
- qbsInfo() << Tr::tr("Skipping unknown platform %1").arg(name);
- continue;
+ // set SDKs/sysroot
+ QString sysRoot;
+ {
+ 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(" ");
+ QSettings sdkInfo(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) {
+ qbsInfo() << indent << Tr::tr("Skipping non base Sdk %1").arg(currentSdkName.toString());
+ continue;
+ }
+ QString safeName = currentSdkName.toString()
+ .replace(QRegExp(QLatin1String("[^-a-zA-Z0-9]")),QLatin1String("-"));
+ if (sdkName.isEmpty()) {
+ if (compareVersions(maxVersion,versionStr) > 0) {
+ maxVersion = versionStr;
+ sdkPath = sdkDirInfo.canonicalFilePath();
+ }
+ } else if (currentSdkName == sdkName) {
+ sdkPath = sdkDirInfo.canonicalFilePath();
+ }
+ if (hasClang){
+ Profile pSdk(xCodeName + QLatin1Char('-') + safeName
+ + QLatin1String("-clang"), settings);
+ pSdk.removeProfile();
+ pSdk.setBaseProfile(clangFullName);
+ pSdk.setValue("qbs.sysroot", sdkDirInfo.canonicalFilePath());
+ qbsInfo() << indent << Tr::tr("* adding profile %1").arg(pSdk.name());
+ profiles << pSdk;
+ }
+ if (hasGcc) {
+ Profile pSdk(xCodeName + QLatin1Char('-') + safeName
+ + QLatin1String("-gcc"), settings);
+ pSdk.removeProfile();
+ pSdk.setBaseProfile(gccFullName);
+ pSdk.setValue("qbs.sysroot", sdkDirInfo.canonicalFilePath());
+ qbsInfo() << indent << Tr::tr("* adding profile %1").arg(pSdk.name());
+ profiles << pSdk;
+ }
}
- p.setBaseProfile(toolchainType);
+ if (!sdkPath.isEmpty())
+ sysRoot = sdkPath;
+ else if (!sdkName.isEmpty())
+ qbsInfo() << indent << Tr::tr("Failed to find sysroot %1").arg(sdkName);
+ }
+ if (hasClang) {
+ Profile clangProfile(clangFullName, settings);
+ clangProfile.removeProfile();
+ clangProfile.setValue("qbs.targetOS", targetOS);
+ clangProfile.setValue("qbs.toolchain", "gcc");
QStringList extraFlags;
- QString sysRoot;
- // it seems that using group/key to access subvalues is broken, using explicit access...
- QVariantMap defaultProp = infoSettings.value(QLatin1String("DefaultProperties"))
- .toMap();
if (defaultProp.contains(QLatin1String("ARCHS"))) {
QString arch = defaultProp.value(QLatin1String("ARCHS")).toString();
if (arch == QLatin1String("$(NATIVE_ARCH_32_BIT)"))
@@ -221,65 +299,47 @@ public:
if (defaultProp.contains(QLatin1String("NATIVE_ARCH"))) {
QString arch = defaultProp.value("NATIVE_ARCH").toString();
if (!arch.startsWith(QLatin1String("arm")))
- qbsInfo() << Tr::tr("Expected arm architecture, not %1").arg(arch);
+ qbsInfo() << indent << Tr::tr("Expected arm architecture, not %1").arg(arch);
extraFlags << QLatin1String("-arch") << arch;
}
- if (defaultProp.contains(QLatin1String("SDKROOT"))) {
- QString sdkName = defaultProp.value(QLatin1String("SDKROOT")).toString();
- QString sdkPath;
- QDir sdks(fInfo.absoluteFilePath() + QLatin1String("/Developer/SDKs"));
- foreach (const QFileInfo &sdkDirInfo, sdks.entryInfoList(QDir::Dirs
- | QDir::NoDotAndDotDot)) {
- QSettings sdkInfo(sdkDirInfo.absoluteFilePath()
- + QLatin1String("/SDKSettings.plist")
- , QSettings::NativeFormat);
- if (sdkInfo.value(QLatin1String("CanonicalName")) == sdkName) {
- sdkPath = sdkDirInfo.canonicalFilePath();
- break;
- }
- }
- if (!sdkPath.isEmpty())
- sysRoot = sdkPath;
- else
- qbsInfo() << Tr::tr("Failed to find sysroot %1").arg(sdkName);
- }
if (!sysRoot.isEmpty())
- p.setValue("qbs.sysroot", sysRoot);
- p.setValue("cpp.platformPath", fInfo.canonicalFilePath());
- setArch(&p, pathToGcc, extraFlags);
- profiles << p;
-
- // add gcc
- QFileInfo specialGcc(fInfo.absoluteFilePath() + QLatin1String("/Developer/usr/bin/g++"));
- if (!specialGcc.exists())
- specialGcc = QFileInfo(devPath + QLatin1String("/usr/bin/g++"));
- if (specialGcc.exists()) {
- QString gccFullName = xCodeName + QLatin1Char('-') + name + QLatin1String("-gcc");
- Profile pGcc(gccFullName, settings);
- pGcc.removeProfile();
- // use the arm-apple-darwin10-llvm-* variant if available???
- if (!sysRoot.isEmpty())
- p.setValue("qbs.sysroot", sysRoot);
- p.setValue("cpp.platformPath",fInfo.canonicalFilePath());
- pGcc.setValue("cpp.compilerName", specialGcc.baseName());
- pGcc.setValue("cpp.toolchainInstallPath", specialGcc.canonicalPath());
- setArch(&pGcc, specialGcc.canonicalFilePath(), QStringList());
- profiles << pGcc;
- }
+ clangProfile.setValue("qbs.sysroot", sysRoot);
+ clangProfile.setValue("cpp.platformPath", fInfo.canonicalFilePath());
+ clangProfile.setValue("cpp.compilerName", clangFileInfo.fileName());
+ clangProfile.setValue("cpp.toolchainInstallPath", clangFileInfo.canonicalPath());
+ setArch(&clangProfile, clangFileInfo.canonicalFilePath(), extraFlags);
+ qbsInfo() << indent << Tr::tr("* adding profile %1").arg(clangProfile.name());
+ profiles << clangProfile;
+ }
+ if (hasGcc) {
+ Profile gccProfile(gccFullName, settings);
+ gccProfile.removeProfile();
+ // use the arm-apple-darwin10-llvm-* variant if available???
+ gccProfile.setValue("qbs.targetOS", targetOS);
+ gccProfile.setValue("qbs.toolchain", "gcc");
+ if (!sysRoot.isEmpty())
+ gccProfile.setValue("qbs.sysroot", sysRoot);
+ gccProfile.setValue("cpp.platformPath",fInfo.canonicalFilePath());
+ gccProfile.setValue("cpp.compilerName", gccFileInfo.fileName());
+ gccProfile.setValue("cpp.toolchainInstallPath", gccFileInfo.canonicalPath());
+ setArch(&gccProfile, gccFileInfo.canonicalFilePath(), QStringList());
+ qbsInfo() << indent << Tr::tr("* adding profile %1").arg(gccProfile.name());
+ profiles << gccProfile;
}
}
+ indent = QLatin1String(" ");
}
+}
- void detectAll()
- {
- detectDeveloperPaths();
- QString xcodeName = QLatin1String("xcode");
- for (int iXcode = 0; iXcode < developerPaths.count(); ++iXcode) {
- setupDefaultToolchains(developerPaths.value(iXcode), xcodeName);
- xcodeName = QString::fromLatin1("xcode%1").arg(iXcode + 1);
- }
+void OsxProbe::detectAll()
+{
+ detectDeveloperPaths();
+ QString xcodeName = QLatin1String("xcode");
+ for (int iXcode = 0; iXcode < developerPaths.count(); ++iXcode) {
+ setupDefaultToolchains(developerPaths.value(iXcode), xcodeName);
+ xcodeName = QString::fromLatin1("xcode%1").arg(iXcode + 2);
}
-};
+}
} // end anonymous namespace
void osxProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles)