diff options
| author | Fawzi Mohamed <fawzi.mohamed@digia.com> | 2013-03-19 22:02:56 +0100 |
|---|---|---|
| committer | Fawzi Mohamed <fawzi.mohamed@digia.com> | 2013-04-02 17:51:08 +0200 |
| commit | 3059ab7aeb2695d32c1a03455e376265e3af4c1c (patch) | |
| tree | 5296ef63dd65b3ff2386ac410a8324c01fa07673 | |
| parent | 67365f0cc01233dab7ecffe17c128dd6e3e26a3d (diff) | |
| download | qbs-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.qbs | 69 | ||||
| -rw-r--r-- | share/qbs/modules/cpp/GenericGCC.qbs | 3 | ||||
| -rw-r--r-- | share/qbs/modules/cpp/darwin-tools.js | 4 | ||||
| -rw-r--r-- | share/qbs/modules/cpp/ios-gcc.qbs | 193 | ||||
| -rw-r--r-- | share/qbs/modules/cpp/mac-gcc.qbs | 34 | ||||
| -rw-r--r-- | src/app/detect-toolchains/osxprobe.cpp | 420 |
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) |
