diff options
Diffstat (limited to 'share/qbs')
36 files changed, 1225 insertions, 582 deletions
diff --git a/share/qbs/imports/qbs/DarwinTools/darwin-tools.js b/share/qbs/imports/qbs/DarwinTools/darwin-tools.js index 9b81310f0..0a944802d 100644 --- a/share/qbs/imports/qbs/DarwinTools/darwin-tools.js +++ b/share/qbs/imports/qbs/DarwinTools/darwin-tools.js @@ -260,19 +260,3 @@ function cleanPropertyList(plist) { cleanPropertyList(plist[key]); } } - -function _codeSignTimestampFlags(product) { - // If signingTimestamp is undefined, do not specify the flag at all - - // this uses the system-specific default behavior - var signingTimestamp = product.moduleProperty("xcode", "signingTimestamp"); - if (signingTimestamp !== undefined) { - // If signingTimestamp is an empty string, specify the flag but do - // not specify a value - this uses a default Apple-provided server - var flag = "--timestamp"; - if (signingTimestamp) - flag += "=" + signingTimestamp; - return [flag]; - } - - return []; -} diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js index 586564d73..0433fa46e 100644 --- a/share/qbs/imports/qbs/ModUtils/utils.js +++ b/share/qbs/imports/qbs/ModUtils/utils.js @@ -48,7 +48,7 @@ function mergeCFiles(inputs, outputFilePath) } function sanitizedList(list, product, fullPropertyName) { - if (!Array.isArray(list)) + if (!(list instanceof Array)) return list; var filterFunc = function(elem) { if (typeof elem === "string" && elem.length === 0) { @@ -588,6 +588,8 @@ function guessArchitecture(m) { architecture = "sh"; } else if (hasAnyOf(m, ["__CR16__"])) { architecture = "cr16"; + } else if (hasAnyOf(m, ["__mc68hc1x__", "__mc68hc1x"])) { + architecture = "hcs12"; } } diff --git a/share/qbs/imports/qbs/Probes/XcodeProbe.qbs b/share/qbs/imports/qbs/Probes/XcodeProbe.qbs index e0ed99346..edd67433b 100644 --- a/share/qbs/imports/qbs/Probes/XcodeProbe.qbs +++ b/share/qbs/imports/qbs/Probes/XcodeProbe.qbs @@ -48,6 +48,7 @@ Probe { // Outputs property var architectureSettings property var availableSdks + property var platformSettings property string xcodeVersion configure: { @@ -97,6 +98,8 @@ Probe { }); availableSdks = Xcode.sdkInfoList(sdksPath); + var platformInfoPlist = FileInfo.joinPaths(platformPath, "Info.plist"); + platformSettings = Xcode.platformInfo(platformInfoPlist); found = !!xcodeVersion; } } diff --git a/share/qbs/imports/qbs/Probes/path-probe.js b/share/qbs/imports/qbs/Probes/path-probe.js index b1bdf9930..1f55dcf32 100644 --- a/share/qbs/imports/qbs/Probes/path-probe.js +++ b/share/qbs/imports/qbs/Probes/path-probe.js @@ -36,7 +36,7 @@ var ModUtils = require("qbs.ModUtils"); function asStringList(key, value) { if (typeof(value) === "string") return [value]; - if (Array.isArray(value)) + if (value instanceof Array) return value; throw key + " must be a string or a stringList"; } @@ -45,7 +45,7 @@ function canonicalSelectors(selectors, nameSuffixes) { var mapper = function(selector) { if (typeof(selector) === "string") return {names : [selector]}; - if (Array.isArray(selector)) + if (selector instanceof Array) return {names : selector}; // dict if (!selector.names) diff --git a/share/qbs/module-providers/Qt/templates/android_support.qbs b/share/qbs/module-providers/Qt/templates/android_support.qbs index 3790037f3..87c980448 100644 --- a/share/qbs/module-providers/Qt/templates/android_support.qbs +++ b/share/qbs/module-providers/Qt/templates/android_support.qbs @@ -38,7 +38,7 @@ Module { Depends { name: "Android.sdk"; condition: _enableSdkSupport } Depends { name: "Android.ndk"; condition: _enableNdkSupport } Depends { name: "java"; condition: _enableSdkSupport } - Depends { name: "cpp" } + Depends { name: "cpp"; condition: _enableNdkSupport } Properties { condition: _enableNdkSupport && qbs.toolchain.contains("clang") @@ -62,8 +62,10 @@ Module { condition: _enableSdkSupport && Utilities.versionCompare(version, "6.0") >= 0 java.additionalClassPaths: [FileInfo.joinPaths(_qtInstallDir, "jar", "Qt6Android.jar")] } + // "ANDROID_HAS_WSTRING" was removed from qtcore qstring.h in Qt 5.14.0 Properties { - condition: _enableNdkSupport && (Android.ndk.abi === "armeabi-v7a" || Android.ndk.abi === "x86") + condition: _enableNdkSupport && Utilities.versionCompare(version, "5.14.0") < 0 && + (Android.ndk.abi === "armeabi-v7a" || Android.ndk.abi === "x86") cpp.defines: "ANDROID_HAS_WSTRING" } Properties { @@ -78,7 +80,11 @@ Module { condition: _enableSdkSupport && Utilities.versionCompare(version, "6.0") >= 0 Android.sdk.minimumVersion: "23" } - cpp.archSuffix: _multiAbi ? "_" + Android.ndk.abi : "" + + Properties { + condition: _enableNdkSupport + cpp.archSuffix: _multiAbi ? "_" + Android.ndk.abi : "" + } Rule { condition: _enableSdkSupport @@ -191,7 +197,7 @@ Module { var prefixDirs = product.Qt.android_support.extraPrefixDirs; if (prefixDirs && prefixDirs.length > 0) f.writeLine('"extraPrefixDirs": ' + JSON.stringify(prefixDirs) + ','); - if (Array.isArray(product.qmlImportPaths) && product.qmlImportPaths.length > 0) + if ((product.qmlImportPaths instanceof Array) && product.qmlImportPaths.length > 0) f.writeLine('"qml-import-paths": "' + product.qmlImportPaths.join(',') + '",'); if (Utilities.versionCompare(product.Qt.android_support.version, "6.0") >= 0) { diff --git a/share/qbs/module-providers/Qt/templates/dbus.js b/share/qbs/module-providers/Qt/templates/dbus.js index 0674bf684..3cdd6fb90 100644 --- a/share/qbs/module-providers/Qt/templates/dbus.js +++ b/share/qbs/module-providers/Qt/templates/dbus.js @@ -29,6 +29,7 @@ ****************************************************************************/ var FileInfo = require("qbs.FileInfo"); +var ModUtils = require("qbs.ModUtils"); function outputFileName(input, suffix) { diff --git a/share/qbs/module-providers/Qt/templates/plugin_support.qbs b/share/qbs/module-providers/Qt/templates/plugin_support.qbs index 1de923f17..19a739589 100644 --- a/share/qbs/module-providers/Qt/templates/plugin_support.qbs +++ b/share/qbs/module-providers/Qt/templates/plugin_support.qbs @@ -32,7 +32,7 @@ Module { newValue = []; else if (typeof newValue == "string") newValue = [newValue]; - if (!Array.isArray(newValue)) + if (!newValue instanceof Array) throw "Invalid value '" + newValue + "' in Qt.plugin_support.pluginsByType"; eppt[pluginType] = (eppt[pluginType] || []).uniqueConcat(newValue); } diff --git a/share/qbs/module-providers/Qt/templates/quick.js b/share/qbs/module-providers/Qt/templates/quick.js index 4f3da2fb0..76f2e9e53 100644 --- a/share/qbs/module-providers/Qt/templates/quick.js +++ b/share/qbs/module-providers/Qt/templates/quick.js @@ -31,7 +31,7 @@ var FileInfo = require("qbs.FileInfo"); var Process = require("qbs.Process"); -function scanQrc(qrcFilePath) { +function scanQrc(product, qrcFilePath) { var absInputDir = FileInfo.path(qrcFilePath); var result = []; var process = new Process(); @@ -65,8 +65,8 @@ function qtQuickResourceFileOutputName(fileName) { return fileName.replace(/\.qrc$/, "_qtquickcompiler.qrc"); } -function contentFromQrc(qrcFilePath) { - var filesInQrc = scanQrc(qrcFilePath); +function contentFromQrc(product, qrcFilePath) { + var filesInQrc = scanQrc(product, qrcFilePath); var qmlJsFiles = filesInQrc.filter(function (filePath) { return (/\.(js|qml)$/).test(filePath); } ); diff --git a/share/qbs/module-providers/Qt/templates/quick.qbs b/share/qbs/module-providers/Qt/templates/quick.qbs index bf04fe869..ac3ab5b26 100644 --- a/share/qbs/module-providers/Qt/templates/quick.qbs +++ b/share/qbs/module-providers/Qt/templates/quick.qbs @@ -79,7 +79,7 @@ QtModule { condition: useCompiler inputs: 'qt.quick.qrc' searchPaths: [FileInfo.path(input.filePath)] - scan: QC.scanQrc(input.filePath) + scan: QC.scanQrc(product, input.filePath) } FileTagger { @@ -100,7 +100,7 @@ QtModule { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { - var content = QC.contentFromQrc(input.filePath); + var content = QC.contentFromQrc(product, input.filePath); content.qrcFilePath = input.filePath; var tf = new TextFile(output.filePath, TextFile.WriteOnly); diff --git a/share/qbs/modules/Android/sdk/sdk.qbs b/share/qbs/modules/Android/sdk/sdk.qbs index f0e727caf..0e40d059b 100644 --- a/share/qbs/modules/Android/sdk/sdk.qbs +++ b/share/qbs/modules/Android/sdk/sdk.qbs @@ -273,7 +273,7 @@ Module { for (var i = 0; i < (aidlSearchPaths ? aidlSearchPaths.length : 0); ++i) args.push("-I" + aidlSearchPaths[i]); args.push(input.filePath, output.filePath); - cmd = new Command(aidl, args); + var cmd = new Command(aidl, args); cmd.description = "Processing " + input.fileName; return [cmd]; } @@ -498,7 +498,7 @@ Module { outputArtifacts: { var deploymentData = SdkUtils.stlDeploymentData(product, inputs, "stl"); var outputs = []; - for (i = 0; i < deploymentData.outputFilePaths.length; ++i) { + for (var i = 0; i < deploymentData.outputFilePaths.length; ++i) { outputs.push({filePath: deploymentData.outputFilePaths[i], fileTags: "android.stl_deployed"}); } diff --git a/share/qbs/modules/Android/sdk/utils.js b/share/qbs/modules/Android/sdk/utils.js index 63bf1f5c4..6fa200822 100644 --- a/share/qbs/modules/Android/sdk/utils.js +++ b/share/qbs/modules/Android/sdk/utils.js @@ -30,9 +30,11 @@ var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); +var ModUtils = require("qbs.ModUtils"); var Process = require("qbs.Process"); var TextFile = require("qbs.TextFile"); var Utilities = require("qbs.Utilities"); +var Xml = require("qbs.Xml"); function availableBuildToolsVersions(sdkDir) { var re = /^([0-9]+)\.([0-9]+)\.([0-9]+)$/; diff --git a/share/qbs/modules/Exporter/pkgconfig/pkgconfig.js b/share/qbs/modules/Exporter/pkgconfig/pkgconfig.js index a3109d61d..52b4dffe3 100644 --- a/share/qbs/modules/Exporter/pkgconfig/pkgconfig.js +++ b/share/qbs/modules/Exporter/pkgconfig/pkgconfig.js @@ -44,9 +44,9 @@ function writeEntry(product, file, key, propertyName, required, additionalValues var value = product.Exporter.pkgconfig[propertyName]; if (additionalValues && additionalValues.length > 0) value = (value || []).concat(additionalValues); - var valueIsNotEmpty = value && (!Array.isArray(value) || value.length > 0); + var valueIsNotEmpty = value && (!(value instanceof Array) || value.length > 0); if (valueIsNotEmpty) { - if (Array.isArray(value)) + if (value instanceof Array) value = value.join(' '); file.writeLine(key + ": " + value); } else if (required) { @@ -83,7 +83,7 @@ function collectAutodetectedData(topLevelProduct) || (value.length > installPrefix.length && value[installPrefix.length] !== '/')) { return quotedValue; } - return quotedValue.replace(product.qbs.installPrefix, "${prefix}"); + return quotedValue.replace(topLevelProduct.qbs.installPrefix, "${prefix}"); } function transformedValue(product, moduleName, propertyName) @@ -92,7 +92,7 @@ function collectAutodetectedData(topLevelProduct) var value = transformFunc ? eval("(" + transformFunc + ")(product, moduleName, propertyName, originalValue)") : originalValue; - if (Array.isArray(value)) + if (value instanceof Array) value.forEach(function(v, i, a) { a[i] = quoteAndPrefixify(v); }); else if (value) value = quoteAndPrefixify(value); diff --git a/share/qbs/modules/Exporter/qbs/qbsexporter.js b/share/qbs/modules/Exporter/qbs/qbsexporter.js index 015ed4418..be46372c3 100644 --- a/share/qbs/modules/Exporter/qbs/qbsexporter.js +++ b/share/qbs/modules/Exporter/qbs/qbsexporter.js @@ -113,7 +113,7 @@ function checkValuePrefix(name, value, forbiddenPrefix, prefixDescription) function stringifyValue(project, product, moduleInstallDir, prop, value) { - if (Array.isArray(value)) { + if (value instanceof Array) { var repr = "["; for (var i = 0; i < value.length; ++i) { repr += stringifyValue(project, product, moduleInstallDir, prop, value[i]) + ", "; @@ -267,6 +267,6 @@ function writeImportStatements(product, moduleFile) if (!imports.contains("import qbs.FileInfo")) imports.push("import qbs.FileInfo"); - for (var i = 0; i < product.exports.imports.length; ++i) - moduleFile.writeLine(product.exports.imports[i]); + for (var i = 0; i < imports.length; ++i) + moduleFile.writeLine(imports[i]); } diff --git a/share/qbs/modules/bundle/BundleModule.qbs b/share/qbs/modules/bundle/BundleModule.qbs index 05e77c81b..63f12db07 100644 --- a/share/qbs/modules/bundle/BundleModule.qbs +++ b/share/qbs/modules/bundle/BundleModule.qbs @@ -38,9 +38,11 @@ import qbs.PropertyList import qbs.TextFile import qbs.Utilities import "bundle.js" as Bundle +import "../codesign/codesign.js" as Codesign Module { Depends { name: "xcode"; required: false; } + Depends { name: "codesign"; required: false; } Probe { id: bundleSettingsProbe @@ -510,9 +512,9 @@ Module { multiplex: true inputs: ["bundle.input", "aggregate_infoplist", "pkginfo", "hpp", - "icns", "xcent", + "icns", "codesign.xcent", "compiled_ibdoc", "compiled_assetcatalog", - "xcode.provisioningprofile.main"] + "codesign.embedded_provisioningprofile"] // Make sure the inputs of this rule are only those rules which produce outputs compatible // with the type of the bundle being produced. @@ -540,13 +542,13 @@ Module { }); } - for (i in inputs["xcode.provisioningprofile.main"]) { - var ext = inputs["xcode.provisioningprofile.main"][i].fileName.split('.')[1]; + var provprofiles = inputs["codesign.embedded_provisioningprofile"]; + for (i in provprofiles) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, ModUtils.moduleProperty(product, "contentsFolderPath"), - "embedded." + ext), + provprofiles[i].fileName), fileTags: ["bundle.provisioningprofile", "bundle.content"] }); } @@ -613,8 +615,8 @@ Module { for (var i = 0; i < artifacts.length; ++i) artifacts[i].bundle = { wrapperPath: wrapperPath }; - if (product.qbs.hostOS.contains("darwin") && product.xcode - && product.xcode.signingIdentity) { + if (product.qbs.hostOS.contains("darwin") && product.codesign + && product.codesign.enableCodeSigning) { artifacts.push({ filePath: FileInfo.joinPaths(product.bundle.contentsFolderPath, "_CodeSignature/CodeResources"), fileTags: ["bundle.code-signature", "bundle.content"] @@ -706,18 +708,21 @@ Module { commands.push(cmd); } - var provisioningProfiles = outputs["bundle.provisioningprofile"]; - for (i in provisioningProfiles) { - cmd = new JavaScriptCommand(); - cmd.description = "copying provisioning profile"; - cmd.highlight = "filegen"; - cmd.source = inputs["xcode.provisioningprofile.main"][i].filePath; - cmd.destination = provisioningProfiles[i].filePath; - cmd.sourceCode = function() { - File.copy(source, destination); - }; + cmd = new JavaScriptCommand(); + cmd.description = "copying provisioning profile"; + cmd.highlight = "filegen"; + cmd.sources = (inputs["codesign.embedded_provisioningprofile"] || []) + .map(function(artifact) { return artifact.filePath; }); + cmd.destination = (outputs["bundle.provisioningprofile"] || []) + .map(function(artifact) { return artifact.filePath; }); + cmd.sourceCode = function() { + var i; + for (var i in sources) { + File.copy(sources[i], destination[i]); + } + }; + if (cmd.sources && cmd.sources.length) commands.push(cmd); - } cmd = new JavaScriptCommand(); cmd.description = "copying public headers"; @@ -762,34 +767,8 @@ Module { commands.push(cmd); if (product.moduleProperty("qbs", "hostOS").contains("darwin")) { - var actualSigningIdentity = product.moduleProperty("xcode", "actualSigningIdentity"); - var codesignDisplayName = product.moduleProperty("xcode", "actualSigningIdentityDisplayName"); - if (actualSigningIdentity) { - var args = product.moduleProperty("xcode", "codesignFlags") || []; - args.push("--force"); - args.push("--sign", actualSigningIdentity); - args = args.concat(DarwinTools._codeSignTimestampFlags(product)); - - for (var j in inputs.xcent) { - args.push("--entitlements", inputs.xcent[j].filePath); - break; // there should only be one - } - - // If this is a framework, we need to sign its versioned directory - if (bundleType === "framework") { - args.push(product.bundle.contentsFolderPath); - } else { - args.push(product.bundle.bundleName); - } - - cmd = new Command(product.moduleProperty("xcode", "codesignPath"), args); - cmd.workingDirectory = product.destinationDirectory; - cmd.description = "codesign " - + ModUtils.moduleProperty(product, "bundleName") - + " using " + codesignDisplayName - + " (" + actualSigningIdentity + ")"; - commands.push(cmd); - } + Array.prototype.push.apply(commands, Codesign.prepareSign( + project, product, inputs, outputs, input, output)); if (bundleType === "application" && product.moduleProperty("qbs", "targetOS").contains("macos")) { diff --git a/share/qbs/modules/bundle/bundle.js b/share/qbs/modules/bundle/bundle.js index 6d9305702..6bb43ecdc 100644 --- a/share/qbs/modules/bundle/bundle.js +++ b/share/qbs/modules/bundle/bundle.js @@ -89,7 +89,7 @@ function productTypeIdentifier(productType) { } function excludedAuxiliaryInputs(project, product) { - var chain = product.moduleProperty("bundle", "_productTypeIdentifierChain"); + var chain = product.bundle._productTypeIdentifierChain; var bestPossibleType; for (var i = chain.length - 1; i >= 0; --i) { switch (chain[i]) { diff --git a/share/qbs/modules/codesign/CodeSignModule.qbs b/share/qbs/modules/codesign/CodeSignModule.qbs new file mode 100644 index 000000000..caa9e2e60 --- /dev/null +++ b/share/qbs/modules/codesign/CodeSignModule.qbs @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** 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 The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +import qbs +import qbs.File +import qbs.FileInfo +import "codesign.js" as CodeSign + +Module { + condition: false + + property bool enableCodeSigning: false + + property string codesignName + property string codesignPath: codesignName + property stringList codesignFlags +} diff --git a/share/qbs/modules/codesign/apple.qbs b/share/qbs/modules/codesign/apple.qbs new file mode 100644 index 000000000..dbcd0a215 --- /dev/null +++ b/share/qbs/modules/codesign/apple.qbs @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** 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 The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +import qbs +import qbs.BundleTools +import qbs.DarwinTools +import qbs.Environment +import qbs.File +import qbs.FileInfo +import qbs.ModUtils +import qbs.PropertyList +import qbs.Probes +import qbs.Utilities +import "codesign.js" as CodeSign +import "../xcode/xcode.js" as XcodeUtils + +CodeSignModule { + Depends { name: "xcode"; required: qbs.toolchain && qbs.toolchain.contains("xcode") } + + Probes.BinaryProbe { + id: codesignProbe + names: [codesignName] + } + + condition: qbs.hostOS.contains("macos") && qbs.targetOS.contains("darwin") + priority: 0 + + enableCodeSigning: _codeSigningRequired + + codesignName: "codesign" + codesignPath: codesignProbe.filePath + + property string signingType: { + if (_adHocCodeSigningAllowed) + return "ad-hoc"; + if (_codeSigningAllowed) + return "app-store"; + } + + PropertyOptions { + name: "signingType" + allowedValues: ["app-store", "apple-id", "ad-hoc"] + } + + property string signingIdentity: { + if (signingType === "ad-hoc") // only useful on macOS + return "-"; + + var isDebug = qbs.buildVariant !== "release"; + + if (qbs.targetOS.contains("ios") || qbs.targetOS.contains("tvos") + || qbs.targetOS.contains("watchos")) { + switch (signingType) { + case "app-store": + return isDebug ? "iPhone Developer" : "iPhone Distribution"; + } + } + + if (qbs.targetOS.contains("macos")) { + switch (signingType) { + case "app-store": + return isDebug ? "Mac Developer" : "3rd Party Mac Developer Application"; + case "apple-id": + return "Developer ID Application"; + } + } + } + + property string signingTimestamp: "none" + + property string provisioningProfile + PropertyOptions { + name: "provisioningProfile" + description: "Name or UUID of the provisioning profile to embed in the application; " + + "typically left blank to allow automatic provisioning" + } + + property string teamIdentifier + PropertyOptions { + name: "teamIdentifier" + description: "Name or identifier of the development team whose identities will be used; " + + "typically left blank unless signed into multiple development teams" + } + + property path provisioningProfilesPath: "~/Library/MobileDevice/Provisioning Profiles" + + readonly property var _actualSigningIdentity: { + if (signingIdentity === "-") { + return { + SHA1: signingIdentity, + subjectInfo: { CN: "ad hoc" } + } + } + + var identities = CodeSign.findSigningIdentities(signingIdentity, teamIdentifier); + if (identities && Object.keys(identities).length > 1) { + throw "Multiple codesigning identities (i.e. certificate and private key pairs) " + + "matching “" + signingIdentity + "” were found." + + CodeSign.humanReadableIdentitySummary(identities); + } + + for (var i in identities) + return identities[i]; + } + + // Allowed for macOS + readonly property bool _adHocCodeSigningAllowed: + XcodeUtils.boolFromSdkOrPlatform("AD_HOC_CODE_SIGNING_ALLOWED", + xcode._sdkProps, xcode._platformProps, true) + + // Allowed for all device platforms (not simulators) + readonly property bool _codeSigningAllowed: + XcodeUtils.boolFromSdkOrPlatform("CODE_SIGNING_ALLOWED", + xcode._sdkProps, xcode._platformProps, true) + + // Required for tvOS, iOS, and watchOS (not simulators) + property bool _codeSigningRequired: { + // allow to override value from Xcode so tests do not require signing + var envRequired = Environment.getEnv("QBS_AUTOTEST_CODE_SIGNING_REQUIRED"); + if (envRequired) + return envRequired === "1"; + return XcodeUtils.boolFromSdkOrPlatform("CODE_SIGNING_REQUIRED", + xcode._sdkProps, xcode._platformProps, false) + } + + // Required for tvOS, iOS, and watchOS (not simulators) + readonly property bool _entitlementsRequired: + XcodeUtils.boolFromSdkOrPlatform("ENTITLEMENTS_REQUIRED", + xcode._sdkProps, xcode._platformProps, false) + + readonly property bool _provisioningProfileAllowed: + product.bundle + && product.bundle.isBundle + && product.type.contains("application") + && xcode.platformType !== "simulator" + + // Required for tvOS, iOS, and watchOS (not simulators) + // PROVISIONING_PROFILE_REQUIRED is specified only in Embedded-Device.xcspec in the + // IDEiOSSupportCore IDE plugin, so we'll just write out the logic here manually + readonly property bool _provisioningProfileRequired: + _provisioningProfileAllowed && !qbs.targetOS.contains("macos") + + // Not used on simulator platforms either but provisioning profiles aren't used there anyways + readonly property string _provisioningProfilePlatform: { + if (qbs.targetOS.contains("macos")) + return "OSX"; + if (qbs.targetOS.contains("ios") || qbs.targetOS.contains("watchos")) + return "iOS"; + if (qbs.targetOS.contains("tvos")) + return "tvOS"; + } + + readonly property string _embeddedProfileName: + (xcode._platformProps || {})["EMBEDDED_PROFILE_NAME"] + + setupBuildEnvironment: { + var prefixes = product.xcode ? [ + product.xcode.platformPath + "/Developer", + product.xcode.toolchainPath, + product.xcode.developerPath + ] : []; + for (var i = 0; i < prefixes.length; ++i) { + var codesign_allocate = prefixes[i] + "/usr/bin/codesign_allocate"; + if (File.exists(codesign_allocate)) { + var v = new ModUtils.EnvironmentVariable("CODESIGN_ALLOCATE"); + v.value = codesign_allocate; + v.set(); + break; + } + } + } + + Group { + name: "Provisioning Profiles" + prefix: codesign.provisioningProfilesPath + "/" + files: ["*.mobileprovision", "*.provisionprofile"] + } + + FileTagger { + fileTags: ["codesign.entitlements"] + patterns: ["*.entitlements"] + } + + FileTagger { + fileTags: ["codesign.provisioningprofile"] + patterns: ["*.mobileprovision", "*.provisionprofile"] + } + + Rule { + multiplex: true + condition: product.codesign.enableCodeSigning && + product.codesign._provisioningProfileAllowed + inputs: ["codesign.provisioningprofile"] + + outputFileTags: ["codesign.embedded_provisioningprofile"] + outputArtifacts: { + var artifacts = []; + var provisioningProfiles = (inputs["codesign.provisioningprofile"] || []) + .map(function (a) { return a.filePath; }); + var bestProfile = CodeSign.findBestProvisioningProfile(product, provisioningProfiles); + var uuid = product.provisioningProfile; + if (bestProfile) { + artifacts.push({ + filePath: FileInfo.joinPaths(product.destinationDirectory, + product.codesign._embeddedProfileName), + fileTags: ["codesign.embedded_provisioningprofile"], + codesign: { + _provisioningProfileFilePath: bestProfile.filePath, + _provisioningProfileData: JSON.stringify(bestProfile.data), + } + }); + } else if (uuid) { + throw "Your build settings specify a provisioning profile with the UUID “" + + uuid + "”, however, no such provisioning profile was found."; + } else if (product._provisioningProfileRequired) { + var hasProfiles = !!((inputs["codesign.provisioningprofile"] || []).length); + var teamIdentifier = product.teamIdentifier; + var codeSignIdentity = product.signingIdentity; + if (hasProfiles) { + if (codeSignIdentity) { + console.warn("No provisioning profiles matching the bundle identifier “" + + product.bundle.identifier + + "” were found."); + } else { + console.warn("No provisioning profiles matching an applicable signing " + + "identity were found."); + } + } else { + if (codeSignIdentity) { + if (teamIdentifier) { + console.warn("No provisioning profiles with a valid signing identity " + + "(i.e. certificate and private key pair) matching the " + + "team ID “" + teamIdentifier + "” were found.") + } else { + console.warn("No provisioning profiles with a valid signing identity " + + "(i.e. certificate and private key pair) were found."); + } + } else { + console.warn("No non–expired provisioning profiles were found."); + } + } + } + return artifacts; + } + + prepare: { + var cmd = new JavaScriptCommand(); + var data = JSON.parse(output.codesign._provisioningProfileData); + cmd.source = output.codesign._provisioningProfileFilePath; + cmd.destination = output.filePath; + cmd.description = "using provisioning profile " + data.Name + " (" + data.UUID + ")"; + cmd.highlight = "filegen"; + cmd.sourceCode = function() { + File.copy(source, destination); + }; + return [cmd]; + } + } + + Rule { + multiplex: true + condition: product.codesign.enableCodeSigning + inputs: ["codesign.entitlements", "codesign.embedded_provisioningprofile"] + + Artifact { + filePath: FileInfo.joinPaths(product.destinationDirectory, + product.targetName + ".xcent") + fileTags: ["codesign.xcent"] + } + + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating entitlements"; + cmd.highlight = "codegen"; + cmd.bundleIdentifier = product.bundle.identifier; + cmd.signingEntitlements = (inputs["codesign.entitlements"] || []) + .map(function (a) { return a.filePath; }); + cmd.provisioningProfiles = (inputs["codesign.embedded_provisioningprofile"] || []) + .map(function (a) { return a.filePath; }); + cmd.platformPath = product.xcode ? product.xcode.platformPath : undefined; + cmd.sdkPath = product.xcode ? product.xcode.sdkPath : undefined; + cmd.sourceCode = function() { + var i; + var provData = {}; + var provisionProfiles = inputs["codesign.embedded_provisioningprofile"]; + for (i in provisionProfiles) { + var plist = new PropertyList(); + try { + plist.readFromData(Utilities.smimeMessageContent( + provisionProfiles[i].filePath)); + provData = plist.toObject(); + } finally { + plist.clear(); + } + } + + var aggregateEntitlements = {}; + + // Start building up an aggregate entitlements plist from the files in the SDKs, + // which contain placeholders in the same manner as Info.plist + function entitlementsFileContents(path) { + return File.exists(path) ? BundleTools.infoPlistContents(path) : undefined; + } + var entitlementsSources = []; + if (platformPath) { + entitlementsSources.push( + entitlementsFileContents( + FileInfo.joinPaths(platformPath, "Entitlements.plist"))); + } + if (sdkPath) { + entitlementsSources.push( + entitlementsFileContents( + FileInfo.joinPaths(sdkPath, "Entitlements.plist"))); + } + + for (i = 0; i < signingEntitlements.length; ++i) { + entitlementsSources.push(entitlementsFileContents(signingEntitlements[i])); + } + + for (i = 0; i < entitlementsSources.length; ++i) { + var contents = entitlementsSources[i]; + for (var key in contents) { + if (contents.hasOwnProperty(key)) + aggregateEntitlements[key] = contents[key]; + } + } + + contents = provData["Entitlements"]; + for (key in contents) { + if (contents.hasOwnProperty(key) && !aggregateEntitlements.hasOwnProperty(key)) + aggregateEntitlements[key] = contents[key]; + } + + // Expand entitlements variables with data from the provisioning profile + var env = { + "AppIdentifierPrefix": (provData["ApplicationIdentifierPrefix"] || "") + ".", + "CFBundleIdentifier": bundleIdentifier + }; + DarwinTools.expandPlistEnvironmentVariables(aggregateEntitlements, env, true); + + // Anything with an undefined or otherwise empty value should be removed + // Only JSON-formatted plists can have null values, other formats error out + // This also follows Xcode behavior + DarwinTools.cleanPropertyList(aggregateEntitlements); + + var plist = new PropertyList(); + try { + plist.readFromObject(aggregateEntitlements); + plist.writeToFile(outputs["codesign.xcent"][0].filePath, "xml1"); + } finally { + plist.clear(); + } + }; + return [cmd]; + } + } +} diff --git a/share/qbs/modules/codesign/codesign.js b/share/qbs/modules/codesign/codesign.js new file mode 100644 index 000000000..1d039e7ca --- /dev/null +++ b/share/qbs/modules/codesign/codesign.js @@ -0,0 +1,279 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** 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 The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +var File = require("qbs.File"); +var FileInfo = require("qbs.FileInfo"); +var PathTools = require("qbs.PathTools"); +var PropertyList = require("qbs.PropertyList"); +var Utilities = require("qbs.Utilities"); + +function findSigningIdentities(searchString, team) { + if (!searchString) + return {}; + var identities = Utilities.signingIdentities(); + var matchedIdentities = {}; + for (var key in identities) { + var identity = identities[key]; + if (team && ![identity.subjectInfo.O, identity.subjectInfo.OU].contains(team)) + continue; + if (searchString === key || identity.subjectInfo.CN.startsWith(searchString)) + matchedIdentities[key] = identity; + } + return matchedIdentities; +} + +function humanReadableIdentitySummary(identities) { + return "\n\t" + Object.keys(identities).map(function (key) { + return identities[key].subjectInfo.CN + + " in team " + + identities[key].subjectInfo.O + + " (" + identities[key].subjectInfo.OU + ")"; + }).join("\n\t"); +} + +/** + * Returns the best provisioning profile for code signing a binary with the given parameters. + * Ideally, this should behave identically as Xcode but the algorithm is not documented + * \l{https://developer.apple.com/library/ios/qa/qa1814/_index.html}{Automatic Provisioning} + */ +function findBestProvisioningProfile(product, files) { + var actualSigningIdentity = product.codesign._actualSigningIdentity || {}; + var teamIdentifier = product.codesign.teamIdentifier; + var bundleIdentifier = product.bundle.identifier; + var targetOS = product.qbs.targetOS; + var buildVariant = product.qbs.buildVariant; + var query = product.codesign.provisioningProfile; + var profilePlatform = product.codesign._provisioningProfilePlatform; + + // Read all provisioning profiles on disk into plist objects in memory + var profiles = files.map(function(filePath) { + var plist = new PropertyList(); + try { + plist.readFromData(Utilities.smimeMessageContent(filePath)); + return { + data: plist.toObject(), + filePath: filePath + }; + } finally { + plist.clear(); + } + }); + + // Do a simple search by matching UUID or Name + if (query) { + for (var i = 0; i < profiles.length; ++i) { + var obj = profiles[i]; + if (obj.data && (obj.data.UUID === query || obj.data.Name === query)) + return obj; + } + + // If we asked for a specific provisioning profile, don't select one automatically + return undefined; + } + + // Provisioning profiles are not normally used with ad-hoc code signing or non-apps + // We do these checks down here only for the automatic selection but not above because + // if the user explicitly selects a provisioning profile it should be used no matter what + if (actualSigningIdentity.SHA1 === "-" || !product.type.contains("application")) + return undefined; + + // Filter out any provisioning profiles we know to be unsuitable from the start + profiles = profiles.filter(function (profile) { + var data = profile.data; + + if (actualSigningIdentity.subjectInfo) { + var certCommonNames = (data["DeveloperCertificates"] || []).map(function (cert) { + return Utilities.certificateInfo(cert).subjectInfo.CN; + }); + if (!certCommonNames.contains(actualSigningIdentity.subjectInfo.CN)) { + console.log("Skipping provisioning profile with no matching certificate names for '" + + actualSigningIdentity.subjectInfo.CN + + "' (found " + certCommonNames.join(", ") + "): " + + profile.filePath); + return false; + } + } + + var platforms = data["Platform"] || []; + if (platforms.length > 0 && profilePlatform && !platforms.contains(profilePlatform)) { + console.log("Skipping provisioning profile for platform " + platforms.join(", ") + + " (current platform " + profilePlatform + ")" + + ": " + profile.filePath); + return false; + } + + if (teamIdentifier + && !data["TeamIdentifier"].contains(teamIdentifier) + && data["TeamName"] !== teamIdentifier) { + console.log("Skipping provisioning profile for team " + data["TeamIdentifier"] + + " (" + data["TeamName"] + ") (current team " + teamIdentifier + ")" + + ": " + profile.filePath); + return false; + } + + if (Date.parse(data["ExpirationDate"]) <= Date.now()) { + console.log("Skipping expired provisioning profile: " + profile.filePath); + return false; + } + + // Filter development vs distribution profiles; + // though the certificate common names check should have been sufficient + var isDebug = buildVariant === "debug"; + if (data["Entitlements"]["get-task-allow"] !== isDebug) { + console.log("Skipping provisioning profile for wrong debug mode: " + profile.filePath); + return false; + } + + var prefix = data["ApplicationIdentifierPrefix"]; + var fullAppId = data["Entitlements"]["application-identifier"]; + if ([prefix, bundleIdentifier].join(".") !== fullAppId + && [prefix, "*"].join(".") !== fullAppId) { + console.log("Skipping provisioning profile not matching full (" + + [prefix, bundleIdentifier].join(".") + ") or wildcard (" + + [prefix, "*"].join(".") + ") app ID (found " + fullAppId + "): " + + profile.filePath); + return false; + } + + return true; + }); + + // Sort by expiration date - sooner expiration dates come last + profiles.sort(function(profileA, profileB) { + var expA = Date.parse(profileA.data["ExpirationDate"]); + var expB = Date.parse(profileB.data["ExpirationDate"]); + if (expA < expB) + return -1; + if (expA > expB) + return 1; + return 0; + }); + + // Sort by application identifier - wildcard profiles come last + profiles.sort(function(profileA, profileB) { + var idA = profileA.data["Entitlements"]["application-identifier"]; + var idB = profileB.data["Entitlements"]["application-identifier"]; + if (!idA.endsWith(".*") && idB.endsWith(".*")) + return -1; + if (idA.endsWith(".*") && !idB.endsWith(".*")) + return 1; + return 0; + }); + + if (profiles.length) { + console.log("Automatic provisioning using profile " + + profiles[0].data.UUID + + " (" + + profiles[0].data.TeamName + + " - " + + profiles[0].data.Name + + ") in product " + + product.name); + return profiles[0]; + } +} + +function prepareSign(project, product, inputs, outputs, input, output) { + var cmd, cmds = []; + + if (!product.codesign.enableCodeSigning) + return cmds; + + var isBundle = "bundle.content" in outputs; + var outputFilePath = isBundle + ? FileInfo.joinPaths(product.destinationDirectory, product.bundle.bundleName) + : outputs["codesign.signed_artifact"][0].filePath; + var outputFileName = isBundle + ? product.bundle.bundleName + : outputs["codesign.signed_artifact"][0].fileName; + var isProductBundle = product.bundle && product.bundle.isBundle; + + // If the product is a bundle, just sign the bundle + // instead of signing the bundle and executable separately + var shouldSignArtifact = !isProductBundle || isBundle; + + var enableCodeSigning = product.codesign.enableCodeSigning; + if (enableCodeSigning && shouldSignArtifact) { + var actualSigningIdentity = product.codesign._actualSigningIdentity; + if (!actualSigningIdentity) { + throw "No codesigning identities (i.e. certificate and private key pairs) matching “" + + product.codesign.signingIdentity + "” were found."; + } + + // If this is a framework, we need to sign its versioned directory + var subpath = ""; + if (isBundle) { + var frameworkVersion = product.bundle.frameworkVersion; + if (frameworkVersion) { + subpath = product.bundle.contentsFolderPath; + subpath = subpath.substring(product.bundle.bundleName.length); + } + } + + var args = product.codesign.codesignFlags || []; + args.push("--force"); + args.push("--sign", actualSigningIdentity.SHA1); + + // If signingTimestamp is undefined, do not specify the flag at all - + // this uses the system-specific default behavior + var signingTimestamp = product.codesign.signingTimestamp; + if (signingTimestamp !== undefined) { + // If signingTimestamp is an empty string, specify the flag but do + // not specify a value - this uses a default Apple-provided server + var flag = "--timestamp"; + if (signingTimestamp) + flag += "=" + signingTimestamp; + args.push(flag); + } + + for (var j in inputs["codesign.xcent"]) { + args.push("--entitlements", inputs["codesign.xcent"][j].filePath); + break; // there should only be one + } + args.push(outputFilePath + subpath); + cmd = new Command(product.codesign.codesignPath, args); + cmd.description = "codesign " + outputFileName + + " (" + actualSigningIdentity.subjectInfo.CN + ")"; + cmd.outputFilePath = outputFilePath; + cmd.stderrFilterFunction = function(stderr) { + return stderr.replace(outputFilePath + ": replacing existing signature\n", ""); + }; + cmds.push(cmd); + } + + if (isBundle) { + cmd = new Command("touch", ["-c", outputFilePath]); + cmd.silent = true; + cmds.push(cmd); + } + + return cmds; +} diff --git a/share/qbs/modules/codesign/noop.qbs b/share/qbs/modules/codesign/noop.qbs new file mode 100644 index 000000000..3234d7476 --- /dev/null +++ b/share/qbs/modules/codesign/noop.qbs @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** 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 The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +import qbs + +CodeSignModule { + condition: true + priority: -100 +} diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs index 9f4e6be99..ca89bbd63 100644 --- a/share/qbs/modules/cpp/CppModule.qbs +++ b/share/qbs/modules/cpp/CppModule.qbs @@ -145,6 +145,12 @@ Module { be set." } + property string toolchainInstallPath + PropertyOptions { + name: "toolchainInstallPath" + description: "a path to the directory where the toolchain executable files are located." + } + property pathList includePaths property pathList systemIncludePaths property pathList distributionIncludePaths diff --git a/share/qbs/modules/cpp/DarwinGCC.qbs b/share/qbs/modules/cpp/DarwinGCC.qbs index 9332603ec..efdd97f1d 100644 --- a/share/qbs/modules/cpp/DarwinGCC.qbs +++ b/share/qbs/modules/cpp/DarwinGCC.qbs @@ -98,7 +98,7 @@ UnixGCC { setupBuildEnvironment: { for (var key in product.cpp.buildEnv) { - v = new ModUtils.EnvironmentVariable(key); + var v = new ModUtils.EnvironmentVariable(key); v.value = product.cpp.buildEnv[key]; v.set(); } diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs index b69f26739..34a0b47de 100644 --- a/share/qbs/modules/cpp/GenericGCC.qbs +++ b/share/qbs/modules/cpp/GenericGCC.qbs @@ -44,6 +44,8 @@ CppModule { condition: qbs.toolchain && qbs.toolchain.contains("gcc") priority: -100 + Depends { name: "codesign" } + Probes.GccBinaryProbe { id: compilerPathProbe condition: !toolchainInstallPath && !_skipAllChecks @@ -134,8 +136,7 @@ CppModule { property string toolchainPrefix: compilerPathProbe.found ? compilerPathProbe.tcPrefix : undefined - property string toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path - : undefined + toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined property string binutilsPath: binutilsProbe.found ? binutilsProbe.path : toolchainInstallPath assemblerName: 'as' + compilerExtension @@ -401,12 +402,15 @@ CppModule { "bundle.input", "dynamiclibrary", "dynamiclibrary_symlink", "dynamiclibrary_symbols", "debuginfo_dll", "debuginfo_bundle","dynamiclibrary_import", "debuginfo_plist", + "codesign.signed_artifact", ] outputArtifacts: { var artifacts = [{ filePath: product.destinationDirectory + "/" + PathTools.dynamicLibraryFilePath(product), - fileTags: ["bundle.input", "dynamiclibrary"], + fileTags: ["bundle.input", "dynamiclibrary"] + .concat(product.codesign.enableCodeSigning + ? ["codesign.signed_artifact"] : []), bundle: { _bundleFilePath: product.destinationDirectory + "/" + PathTools.bundleExecutableFilePath(product) @@ -511,12 +515,14 @@ CppModule { inputsFromDependencies: ["dynamiclibrary_symbols", "dynamiclibrary_import", "staticlibrary"] outputFileTags: ["bundle.input", "loadablemodule", "debuginfo_loadablemodule", - "debuginfo_bundle","debuginfo_plist"] + "debuginfo_bundle", "debuginfo_plist", "codesign.signed_artifact"] outputArtifacts: { var app = { filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.loadableModuleFilePath(product)), - fileTags: ["bundle.input", "loadablemodule"], + fileTags: ["bundle.input", "loadablemodule"] + .concat(product.codesign.enableCodeSigning + ? ["codesign.signed_artifact"] : []), bundle: { _bundleFilePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.bundleExecutableFilePath(product)) @@ -548,13 +554,14 @@ CppModule { } inputsFromDependencies: ["dynamiclibrary_symbols", "dynamiclibrary_import", "staticlibrary"] - outputFileTags: ["bundle.input", "application", "debuginfo_app","debuginfo_bundle", - "debuginfo_plist", "mem_map"] + outputFileTags: ["bundle.input", "application", "debuginfo_app", "debuginfo_bundle", + "debuginfo_plist", "mem_map", "codesign.signed_artifact"] outputArtifacts: { var app = { filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.applicationFilePath(product)), - fileTags: ["bundle.input", "application"], + fileTags: ["bundle.input", "application"].concat( + product.codesign.enableCodeSigning ? ["codesign.signed_artifact"] : []), bundle: { _bundleFilePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.bundleExecutableFilePath(product)) diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js index 9b6a074d2..99452b6da 100644 --- a/share/qbs/modules/cpp/gcc.js +++ b/share/qbs/modules/cpp/gcc.js @@ -28,6 +28,7 @@ ** ****************************************************************************/ +var Codesign = require("../codesign/codesign.js"); var Cpp = require("cpp.js"); var File = require("qbs.File"); var FileInfo = require("qbs.FileInfo"); @@ -132,7 +133,7 @@ function collectLibraryDependencies(product, isDarwin) { if (!obj.cpp) return; function ensureArray(a) { - return Array.isArray(a) ? a : []; + return (a instanceof Array) ? a : []; } function sanitizedModuleListProperty(obj, moduleName, propertyName) { return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName)); @@ -355,11 +356,12 @@ function linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPat return rpath; } + function isNotSystemRunPath(p) { + return !FileInfo.isAbsolutePath(p) || (!systemRunPaths.contains(p) + && !canonicalSystemRunPaths.contains(File.canonicalFilePath(p))); + }; + if (!product.qbs.targetOS.contains("windows")) { - function isNotSystemRunPath(p) { - return !FileInfo.isAbsolutePath(p) || (!systemRunPaths.contains(p) - && !canonicalSystemRunPaths.contains(File.canonicalFilePath(p))); - }; for (i in rpaths) { if (isNotSystemRunPath(rpaths[i])) escapableLinkerFlags.push("-rpath", fixupRPath(rpaths[i])); @@ -1383,28 +1385,8 @@ function prepareLinker(project, product, inputs, outputs, input, output) { } } - if (product.xcode && product.bundle) { - var actualSigningIdentity = product.xcode.actualSigningIdentity; - var codesignDisplayName = product.xcode.actualSigningIdentityDisplayName; - if (actualSigningIdentity && !product.bundle.isBundle) { - args = product.xcode.codesignFlags || []; - args.push("--force"); - args.push("--sign", actualSigningIdentity); - args = args.concat(DarwinTools._codeSignTimestampFlags(product)); - - for (var j in inputs.xcent) { - args.push("--entitlements", inputs.xcent[j].filePath); - break; // there should only be one - } - args.push(primaryOutput.filePath); - cmd = new Command(product.xcode.codesignPath, args); - cmd.description = "codesign " - + primaryOutput.fileName - + " using " + codesignDisplayName - + " (" + actualSigningIdentity + ")"; - commands.push(cmd); - } - } + Array.prototype.push.apply( + commands, Codesign.prepareSign(project, product, inputs, outputs, input, output)); return commands; } diff --git a/share/qbs/modules/cpp/iar.js b/share/qbs/modules/cpp/iar.js index f1c41fe64..d25b74324 100644 --- a/share/qbs/modules/cpp/iar.js +++ b/share/qbs/modules/cpp/iar.js @@ -38,35 +38,138 @@ var TemporaryDir = require("qbs.TemporaryDir"); var TextFile = require("qbs.TextFile"); function supportXLinker(architecture) { - return architecture === "78k" || architecture === "avr" - || architecture === "avr32" || architecture === "mcs51" - || architecture === "msp430" || architecture === "v850" - || architecture === "m68k" || architecture === "m32c" - || architecture === "r32c" || architecture === "m16c" - || architecture === "cr16"; + return architecture === "78k" + || architecture === "avr" + || architecture === "avr32" + || architecture === "cr16" + || architecture === "hcs12" + || architecture === "hcs8" + || architecture === "m16c" + || architecture === "m32c" + || architecture === "m68k" + || architecture === "mcs51" + || architecture === "msp430" + || architecture === "r32c" + || architecture === "v850"; } function supportILinker(architecture) { return architecture.startsWith("arm") - || architecture === "rh850" || architecture === "rl78" - || architecture === "rx" || architecture === "stm8" - || architecture === "sh" || architecture === "riscv"; + || architecture === "rh850" + || architecture === "riscv" + || architecture === "rl78" + || architecture === "rx" + || architecture === "sh" + || architecture === "stm8"; } function supportXArchiver(architecture) { - return architecture === "mcs51" || architecture === "avr" - || architecture === "msp430" || architecture === "v850" - || architecture === "78k" || architecture === "avr32" - || architecture === "m68k" || architecture === "m32c" - || architecture === "r32c" || architecture === "m16c" - || architecture === "cr16"; + return architecture === "78k" + || architecture === "avr" + || architecture === "avr32" + || architecture === "cr16" + || architecture === "hcs12" + || architecture === "hcs8" + || architecture === "m16c" + || architecture === "m32c" + || architecture === "m68k" + || architecture === "mcs51" + || architecture === "msp430" + || architecture === "r32c" + || architecture === "v850"; } function supportIArchiver(architecture) { return architecture.startsWith("arm") - || architecture === "stm8" || architecture === "rl78" - || architecture === "rx" || architecture === "rh850" - || architecture === "sh" || architecture === "riscv"; + || architecture === "rh850" + || architecture === "riscv" + || architecture === "rl78" + || architecture === "rx" + || architecture === "sh" + || architecture === "stm8"; +} + +function supportXAssembler(architecture) { + return architecture.startsWith("arm") + || architecture === "78k" + || architecture === "avr" + || architecture === "hcs12" + || architecture === "m16c" + || architecture === "mcs51" + || architecture === "msp430" + || architecture === "m32c" + || architecture === "v850"; +} + +function supportIAssembler(architecture) { + return architecture === "avr32" + || architecture === "cr16" + || architecture === "hcs8" + || architecture === "r32c" + || architecture === "rh850" + || architecture === "riscv" + || architecture === "rl78" + || architecture === "rx" + || architecture === "sh" + || architecture === "stm8" + || architecture === "m68k"; +} + +function supportEndianness(architecture) { + return architecture.startsWith("arm") + || architecture === "rx"; +} + +function supportCppExceptions(architecture) { + return architecture.startsWith("arm") + || architecture === "rh850" + || architecture === "riscv" + || architecture === "rl78" + || architecture === "rx"; +} + +function supportCppRtti(architecture) { + return architecture.startsWith("arm") + || architecture === "rh850" + || architecture === "riscv" + || architecture === "rl78" + || architecture === "rx"; +} + +function supportCppWarningAboutCStyleCast(architecture) { + return architecture.startsWith("arm") + || architecture === "avr" + || architecture === "avr32" + || architecture === "cr16" + || architecture === "mcs51" + || architecture === "msp430" + || architecture === "rh850" + || architecture === "rl78" + || architecture === "rx" + || architecture === "stm8" + || architecture === "v850"; +} + +function supportDeprecatedFeatureWarnings(architecture) { + return architecture.startsWith("arm") + || architecture === "avr" + || architecture === "cr16" + || architecture === "mcs51" + || architecture === "msp430" + || architecture === "rh850" + || architecture === "rl78" + || architecture === "rx" + || architecture === "stm8" + || architecture === "v850"; +} + +function supportCLanguageVersion(architecture) { + return architecture !== "78k"; +} + +function supportCppLanguage(compilerFilePath) { + var baseName = FileInfo.baseName(compilerFilePath); + return baseName !== "iccs08"; } // It is a 'magic' IAR-specific target architecture code. @@ -94,7 +197,11 @@ function architectureCode(architecture) { return "34"; case "cr16": return "45"; - case "rh850": case "rl78": case "rx": case "stm8": case "sh": case "riscv": + case "hcs12": + return "12"; + case "hcs8": + return "78"; + case "rh850": case "riscv": case "rl78": case "rx": case "sh": case "stm8": return ""; default: if (architecture.startsWith("arm")) @@ -107,40 +214,44 @@ function compilerName(qbs) { var architecture = qbs.architecture; if (architecture.startsWith("arm")) return "iccarm"; - else if (architecture === "mcs51") - return "icc8051"; + else if (architecture === "78k") + return "icc78k"; else if (architecture === "avr") return "iccavr"; - else if (architecture === "stm8") - return "iccstm8"; + else if (architecture === "avr32") + return "iccavr32"; + else if (architecture === "cr16") + return "icccr16c"; + else if (architecture === "hcs12") + return "icchcs12"; + else if (architecture === "hcs8") + return "iccs08"; + else if (architecture === "m16c") + return "iccm16c"; + else if (architecture === "m32c") + return "iccm32c"; + else if (architecture === "m68k") + return "icccf"; + else if (architecture === "mcs51") + return "icc8051"; else if (architecture === "msp430") return "icc430"; - else if (architecture === "v850") - return "iccv850"; - else if (architecture === "78k") - return "icc78k"; + else if (architecture === "r32c") + return "iccr32c"; + else if (architecture === "rh850") + return "iccrh850"; + else if (architecture === "riscv") + return "iccriscv"; else if (architecture === "rl78") return "iccrl78"; else if (architecture === "rx") return "iccrx"; - else if (architecture === "rh850") - return "iccrh850"; - else if (architecture === "avr32") - return "iccavr32"; else if (architecture === "sh") return "iccsh"; - else if (architecture === "riscv") - return "iccriscv"; - else if (architecture === "m68k") - return "icccf"; - else if (architecture === "m32c") - return "iccm32c"; - else if (architecture === "r32c") - return "iccr32c"; - else if (architecture === "m16c") - return "iccm16c"; - else if (architecture === "cr16") - return "icccr16c"; + else if (architecture === "stm8") + return "iccstm8"; + else if (architecture === "v850") + return "iccv850"; throw "Unable to deduce compiler name for unsupported architecture: '" + architecture + "'"; } @@ -149,40 +260,44 @@ function assemblerName(qbs) { var architecture = qbs.architecture; if (architecture.startsWith("arm")) return "iasmarm"; - else if (architecture === "rl78") - return "iasmrl78"; - else if (architecture === "rx") - return "iasmrx"; - else if (architecture === "rh850") - return "iasmrh850"; - else if (architecture === "mcs51") - return "a8051"; - else if (architecture === "avr") - return "aavr"; - else if (architecture === "stm8") - return "iasmstm8"; - else if (architecture === "msp430") - return "a430"; - else if (architecture === "v850") - return "av850"; else if (architecture === "78k") return "a78k"; + else if (architecture === "avr") + return "aavr"; else if (architecture === "avr32") return "aavr32"; - else if (architecture === "sh") - return "iasmsh"; - else if (architecture === "riscv") - return "iasmriscv"; - else if (architecture === "m68k") - return "acf"; + else if (architecture === "cr16") + return "acr16c"; + else if (architecture === "hcs12") + return "ahcs12"; + else if (architecture === "hcs8") + return "as08"; + else if (architecture === "m16c") + return "am16c"; else if (architecture === "m32c") return "am32c"; + else if (architecture === "m68k") + return "acf"; + else if (architecture === "mcs51") + return "a8051"; + else if (architecture === "msp430") + return "a430"; else if (architecture === "r32c") return "ar32c"; - else if (architecture === "m16c") - return "am16c"; - else if (architecture === "cr16") - return "acr16c"; + else if (architecture === "rh850") + return "iasmrh850"; + else if (architecture === "riscv") + return "iasmriscv"; + else if (architecture === "rl78") + return "iasmrl78"; + else if (architecture === "rx") + return "iasmrx"; + else if (architecture === "sh") + return "iasmsh"; + else if (architecture === "stm8") + return "iasmstm8"; + else if (architecture === "v850") + return "av850"; throw "Unable to deduce assembler name for unsupported architecture: '" + architecture + "'"; } @@ -253,16 +368,16 @@ function guessArmArchitecture(core) { arch += "v4m"; else if (core === "__ARM4TM__") arch += "v4tm"; - else if (core === "__ARM5__") - arch += "v5"; else if (core === "__ARM5E__") arch += "v5e"; - else if (core === "__ARM6__") - arch += "v6"; + else if (core === "__ARM5__") + arch += "v5"; else if (core === "__ARM6M__") arch += "v6m"; else if (core === "__ARM6SM__") arch += "v6sm"; + else if (core === "__ARM6__") + arch += "v6"; else if (core === "__ARM7M__") arch += "v7m"; else if (core === "__ARM7R__") @@ -271,42 +386,46 @@ function guessArmArchitecture(core) { } function guessArchitecture(macros) { - if (macros["__ICCARM__"] === "1") - return guessArmArchitecture(macros["__CORE__"]); - else if (macros["__ICC8051__"] === "1") - return "mcs51"; - else if (macros["__ICCAVR__"] === "1") - return "avr"; - else if (macros["__ICCSTM8__"] === "1") - return "stm8"; - else if (macros["__ICC430__"] === "1") + if (macros["__ICC430__"] === "1") return "msp430"; - else if (macros["__ICCRL78__"] === "1") - return "rl78"; - else if (macros["__ICCRX__"] === "1") - return "rx"; - else if (macros["__ICCRH850__"] === "1") - return "rh850"; - else if (macros["__ICCV850__"] === "1") - return "v850"; else if (macros["__ICC78K__"] === "1") return "78k"; + else if (macros["__ICC8051__"] === "1") + return "mcs51"; + else if (macros["__ICCARM__"] === "1") + return guessArmArchitecture(macros["__CORE__"]); else if (macros["__ICCAVR32__"] === "1") return "avr32"; - else if (macros["__ICCSH__"] === "1") - return "sh"; - else if (macros["__ICCRISCV__"] === "1") - return "riscv"; + else if (macros["__ICCAVR__"] === "1") + return "avr"; else if (macros["__ICCCF__"] === "1") return "m68k"; + else if (macros["__ICCCR16C__"] === "1") + return "cr16"; + else if (macros["__ICCHCS12__"] === "1") + return "hcs12"; + else if (macros["__ICCM16C__"] === "1") + return "m16c"; else if (macros["__ICCM32C__"] === "1") return "m32c"; else if (macros["__ICCR32C__"] === "1") return "r32c"; - else if (macros["__ICCM16C__"] === "1") - return "m16c"; - else if (macros["__ICCCR16C__"] === "1") - return "cr16"; + else if (macros["__ICCRH850__"] === "1") + return "rh850"; + else if (macros["__ICCRISCV__"] === "1") + return "riscv"; + else if (macros["__ICCRL78__"] === "1") + return "rl78"; + else if (macros["__ICCRX__"] === "1") + return "rx"; + else if (macros["__ICCS08__"] === "1") + return "hcs8"; + else if (macros["__ICCSH__"] === "1") + return "sh"; + else if (macros["__ICCSTM8__"] === "1") + return "stm8"; + else if (macros["__ICCV850__"] === "1") + return "v850"; } function guessEndianness(macros) { @@ -315,19 +434,31 @@ function guessEndianness(macros) { return "big" } -function guessVersion(macros, architecture) -{ +function guessVersion(macros, architecture) { var version = parseInt(macros["__VER__"], 10); if (architecture.startsWith("arm")) { return { major: parseInt(version / 1000000), minor: parseInt(version / 1000) % 1000, patch: parseInt(version) % 1000 } - } else if (architecture === "mcs51" || architecture === "avr" || architecture === "stm8" - || architecture === "msp430" || architecture === "rl78" || architecture === "rx" - || architecture === "rh850" || architecture === "v850" || architecture === "78k" - || architecture === "avr32" || architecture === "sh" || architecture === "riscv" - || architecture === "m68k" || architecture === "m32c" || architecture === "r32c" - || architecture === "m16c" || architecture === "cr16") { + } else if (architecture === "78k" + || architecture === "avr" + || architecture === "avr32" + || architecture === "cr16" + || architecture === "hcs12" + || architecture === "hcs8" + || architecture === "m16c" + || architecture === "m32c" + || architecture === "m68k" + || architecture === "mcs51" + || architecture === "msp430" + || architecture === "r32c" + || architecture === "rh850" + || architecture === "riscv" + || architecture === "rl78" + || architecture === "rx" + || architecture === "sh" + || architecture === "stm8" + || architecture === "v850") { return { major: parseInt(version / 100), minor: parseInt(version % 100), patch: 0 } @@ -338,24 +469,25 @@ function cppLanguageOption(compilerFilePath) { var baseName = FileInfo.baseName(compilerFilePath); switch (baseName) { case "iccarm": - case "iccrl78": - case "iccrx": case "iccrh850": case "iccriscv": + case "iccrl78": + case "iccrx": return "--c++"; - case "icc8051": - case "iccavr": - case "iccstm8": case "icc430": - case "iccv850": case "icc78k": + case "icc8051": + case "iccavr": case "iccavr32": - case "iccsh": case "icccf": + case "icccr16c": + case "icchcs12": + case "iccm16c": case "iccm32c": case "iccr32c": - case "iccm16c": - case "icccr16c": + case "iccsh": + case "iccstm8": + case "iccv850": return "--ec++"; } throw "Unable to deduce C++ language option for unsupported compiler: '" @@ -369,7 +501,7 @@ function dumpMacros(compilerFilePath, tag) { var outFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/iar-macros.predef"); var args = [ inFilePath, "--predef_macros", outFilePath ]; - if (tag && tag === "cpp") + if (tag === "cpp" && supportCppLanguage(compilerFilePath)) args.push(cppLanguageOption(compilerFilePath)); var p = new Process(); @@ -378,45 +510,47 @@ function dumpMacros(compilerFilePath, tag) { return ModUtils.extractMacros(outFile.readAll()); } -function dumpDefaultPaths(compilerFilePath, tag) { +function dumpCompilerIncludePaths(compilerFilePath, tag) { + // We can dump the compiler include paths using the undocumented `--IDE3` flag, + // e.g. which also is used in the IAR extension for the VSCode. In this case the + // compiler procuces the console output in the following format: + // `$$TOOL_BEGIN $$VERSION "3" $$INC_BEGIN $$FILEPATH "<path\\to\\directory>" $$TOOL_END` + var tempDir = new TemporaryDir(); var inFilePath = FileInfo.fromNativeSeparators(tempDir.path() + "/empty-source.c"); var inFile = new TextFile(inFilePath, TextFile.WriteOnly); - var args = [ inFilePath, "--preinclude", "." ]; - if (tag === "cpp") + var args = ["--IDE3", inFilePath]; + if (tag === "cpp" && supportCppLanguage(compilerFilePath)) args.push(cppLanguageOption(compilerFilePath)); + var includePaths = []; var p = new Process(); - // This process should return an error, don't throw - // an error in this case. + // It is possible that the process can return an error code in case the + // compiler does not support the `--IDE3` flag. So, don't throw an error in this case. p.exec(compilerFilePath, args, false); - var output = p.readStdErr(); - - var includePaths = []; - var pass = 0; - for (var pos = 0; pos < output.length; ++pos) { - var searchIndex = output.indexOf("searched:", pos); - if (searchIndex === -1) - break; - var startQuoteIndex = output.indexOf('"', searchIndex + 1); - if (startQuoteIndex === -1) - break; - var endQuoteIndex = output.indexOf('"', startQuoteIndex + 1); - if (endQuoteIndex === -1) - break; - pos = endQuoteIndex + 1; - - // Ignore the first path as it is not a compiler include path. - ++pass; - if (pass === 1) - continue; + p.readStdOut().trim().split(/\r?\n/g).map(function(line) { + var m = line.match(/\$\$INC_BEGIN\s\$\$FILEPATH\s\"([^"]*)/); + if (m) { + var includePath = m[1].replace(/\\\\/g, '/'); + if (includePath) + includePaths.push(includePath); + } + }); - var path = output.substring(startQuoteIndex + 1, endQuoteIndex) - .replace(/[\s]{2,}/g, ' '); - includePaths.push(path); + if (includePaths.length === 0) { + // This can happen if the compiler does not support the `--IDE3` flag, + // e.g. IAR for S08 architecture. In this case we use fallback to the + // detection of the `inc` directory. + var includePath = FileInfo.joinPaths(FileInfo.path(compilerFilePath), "../inc/"); + includePaths.push(includePath); } + return includePaths; +} + +function dumpDefaultPaths(compilerFilePath, tag) { + var includePaths = dumpCompilerIncludePaths(compilerFilePath, tag); return { "includePaths": includePaths }; @@ -441,7 +575,7 @@ function collectLibraryDependencies(product) { if (!obj.cpp) return; function ensureArray(a) { - return Array.isArray(a) ? a : []; + return (a instanceof Array) ? a : []; } function sanitizedModuleListProperty(obj, moduleName, propertyName) { return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName)); @@ -521,9 +655,6 @@ function staticLibraryLinkerOutputArtifacts(product) { } function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { - // Determine which C-language we're compiling. - var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); - var args = []; // Input. @@ -580,6 +711,7 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { } var architecture = input.qbs.architecture; + var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags)); // Warning level flags. switch (input.cpp.warningLevel) { @@ -587,24 +719,21 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { args.push("--no_warnings"); break; case "all": - if (architecture !== "78k") { - if (architecture !== "avr32" && architecture !== "r32c" - && architecture !== "sh" && architecture !== "m16c") { + if (supportDeprecatedFeatureWarnings(architecture)) { args.push("--deprecated_feature_warnings=" +"+attribute_syntax," +"+preprocessor_extensions," +"+segment_pragmas"); } - if (tag === "cpp") + if (tag === "cpp" && supportCppWarningAboutCStyleCast(architecture)) args.push("--warn_about_c_style_casts"); - } break; } if (input.cpp.treatWarningsAsErrors) args.push("--warnings_are_errors"); // C language version flags. - if (tag === "c" && (architecture !== "78k")) { + if (tag === "c" && supportCLanguageVersion(architecture)) { var knownValues = ["c89"]; var cLanguageVersion = Cpp.languageVersion( input.cpp.cLanguageVersion, knownValues, "C"); @@ -620,35 +749,27 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) { } // C++ language version flags. - if (tag === "cpp") { - if (architecture.startsWith("arm") - || architecture === "rl78" || architecture === "rx" - || architecture === "rh850" || architecture === "riscv") { - // Enable C++ language flags. - args.push("--c++"); - // Exceptions flags. - if (!input.cpp.enableExceptions) - args.push("--no_exceptions"); - // RTTI flags. - if (!input.cpp.enableRtti) - args.push("--no_rtti"); - } else if (architecture === "stm8" || architecture === "mcs51" - || architecture === "avr" || architecture === "msp430" - || architecture === "v850" || architecture === "78k" - || architecture === "avr32" || architecture === "sh" - || architecture === "m68k" || architecture === "m32c" - || architecture === "r32c" || architecture === "m16c" - || architecture === "cr16") { - args.push("--ec++"); - } + var compilerFilePath = input.cpp.compilerPath; + if (tag === "cpp" && supportCppLanguage(compilerFilePath)) { + // C++ language flag. + var cppOption = cppLanguageOption(compilerFilePath); + args.push(cppOption); + + // Exceptions flag. + var enableExceptions = input.cpp.enableExceptions; + if (!enableExceptions && supportCppExceptions(architecture)) + args.push("--no_exceptions"); + + // RTTI flag. + var enableRtti = input.cpp.enableRtti; + if (!enableRtti && supportCppRtti(architecture)) + args.push("--no_rtti"); } // Byte order flags. - if (architecture.startsWith("arm") || architecture === "rx") { - var endianness = input.cpp.endianness; - if (endianness) - args.push("--endian=" + endianness); - } + var endianness = input.cpp.endianness; + if (endianness && supportEndianness(architecture)) + args.push("--endian=" + endianness); // Listing files generation flag. if (input.cpp.generateCompilerListingFiles) @@ -675,6 +796,16 @@ function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { // Output. args.push("-o", outputs.obj[0].filePath); + var architecture = input.qbs.architecture; + + // The `--preinclude` flag is only supported for a certain + // set of assemblers, not for all. + if (supportIAssembler(architecture)) { + var prefixHeaders = input.cpp.prefixHeaders; + for (var i in prefixHeaders) + args.push("--preinclude", prefixHeaders[i]); + } + // Includes. var allIncludePaths = []; var systemIncludePaths = input.cpp.systemIncludePaths; @@ -690,12 +821,7 @@ function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { args.push("-r"); // Architecture specific flags. - var architecture = input.qbs.architecture; - if (architecture === "stm8" || architecture === "rl78" - || architecture === "rx" || architecture === "rh850" - || architecture === "avr32" || architecture === "sh" - || architecture === "riscv" || architecture === "m68k" - || architecture === "r32c" || architecture === "cr16") { + if (supportIAssembler(architecture)) { // Silent output generation flag. args.push("--silent"); // Warning level flags. @@ -703,13 +829,18 @@ function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) { args.push("--no_warnings"); if (input.cpp.treatWarningsAsErrors) args.push("--warnings_are_errors"); - } else { + } else if (supportXAssembler(architecture)){ // Silent output generation flag. args.push("-S"); // Warning level flags. args.push("-w" + (input.cpp.warningLevel === "none" ? "-" : "+")); } + // Byte order flags. + var endianness = input.cpp.endianness; + if (endianness && supportEndianness(architecture)) + args.push("--endian=" + endianness); + // Listing files generation flag. if (input.cpp.generateAssemblerListingFiles) args.push("-l", outputs.lst[0].filePath); diff --git a/share/qbs/modules/cpp/iar.qbs b/share/qbs/modules/cpp/iar.qbs index 519d30f2a..26f7b96f3 100644 --- a/share/qbs/modules/cpp/iar.qbs +++ b/share/qbs/modules/cpp/iar.qbs @@ -64,8 +64,7 @@ CppModule { compilerDefinesByLanguage: iarProbe.compilerDefinesByLanguage compilerIncludePaths: iarProbe.includePaths - property string toolchainInstallPath: compilerPathProbe.found - ? compilerPathProbe.path : undefined + toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined property string compilerExtension: qbs.hostOS.contains("windows") ? ".exe" : "" diff --git a/share/qbs/modules/cpp/keil.js b/share/qbs/modules/cpp/keil.js index 1e8169853..7303a5453 100644 --- a/share/qbs/modules/cpp/keil.js +++ b/share/qbs/modules/cpp/keil.js @@ -534,7 +534,7 @@ function collectLibraryDependencies(product) { if (!obj.cpp) return; function ensureArray(a) { - return Array.isArray(a) ? a : []; + return (a instanceof Array) ? a : []; } function sanitizedModuleListProperty(obj, moduleName, propertyName) { return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName)); diff --git a/share/qbs/modules/cpp/keil.qbs b/share/qbs/modules/cpp/keil.qbs index eba52adff..66233fc84 100644 --- a/share/qbs/modules/cpp/keil.qbs +++ b/share/qbs/modules/cpp/keil.qbs @@ -62,8 +62,7 @@ CppModule { compilerDefinesByLanguage: keilProbe.compilerDefinesByLanguage compilerIncludePaths: keilProbe.includePaths - property string toolchainInstallPath: compilerPathProbe.found - ? compilerPathProbe.path : undefined + toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined property string compilerExtension: qbs.hostOS.contains("windows") ? ".exe" : "" diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js index df1f5eb5b..566059610 100644 --- a/share/qbs/modules/cpp/msvc.js +++ b/share/qbs/modules/cpp/msvc.js @@ -354,7 +354,7 @@ function collectLibraryDependencies(product) { if (!obj.cpp) return; function ensureArray(a) { - return Array.isArray(a) ? a : []; + return (a instanceof Array) ? a : []; } function sanitizedModuleListProperty(obj, moduleName, propertyName) { return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName)); diff --git a/share/qbs/modules/cpp/sdcc.js b/share/qbs/modules/cpp/sdcc.js index 36454031e..6f5fcc3d6 100644 --- a/share/qbs/modules/cpp/sdcc.js +++ b/share/qbs/modules/cpp/sdcc.js @@ -50,6 +50,8 @@ function assemblerName(qbs) { return "sdas8051"; case "stm8": return "sdasstm8"; + case "hcs8": + return "sdas6808"; } throw "Unable to deduce assembler name for unsupported architecture: '" + qbs.architecture + "'"; @@ -61,6 +63,8 @@ function linkerName(qbs) { return "sdld"; case "stm8": return "sdldstm8"; + case "hcs8": + return "sdld6808"; } throw "Unable to deduce linker name for unsupported architecture: '" + qbs.architecture + "'"; @@ -75,6 +79,8 @@ function targetArchitectureFlag(architecture) { return "-mmcs51"; if (architecture === "stm8") return "-mstm8"; + if (architecture === "hcs8") + return "-mhc08"; } function guessArchitecture(macros) { @@ -82,6 +88,8 @@ function guessArchitecture(macros) { return "mcs51"; if (macros["__SDCC_stm8"] === "1") return "stm8"; + if (macros["__SDCC_hc08"] === "1") + return "hcs8"; } function guessEndianness(macros) { @@ -142,7 +150,8 @@ function dumpDefaultPaths(compilerFilePath, architecture) { || line.startsWith("libpath:")) { addIncludePaths = false; } else if (addIncludePaths) { - includePaths.push(line); + if (File.exists(line)) + includePaths.push(line); } } @@ -193,7 +202,7 @@ function collectLibraryDependencies(product) { if (!obj.cpp) return; function ensureArray(a) { - return Array.isArray(a) ? a : []; + return (a instanceof Array) ? a : []; } function sanitizedModuleListProperty(obj, moduleName, propertyName) { return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName)); diff --git a/share/qbs/modules/cpp/sdcc.qbs b/share/qbs/modules/cpp/sdcc.qbs index da1b89402..a44cee808 100644 --- a/share/qbs/modules/cpp/sdcc.qbs +++ b/share/qbs/modules/cpp/sdcc.qbs @@ -63,8 +63,7 @@ CppModule { compilerDefinesByLanguage: sdccProbe.compilerDefinesByLanguage compilerIncludePaths: sdccProbe.includePaths - property string toolchainInstallPath: compilerPathProbe.found - ? compilerPathProbe.path : undefined + toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined property string compilerExtension: qbs.hostOS.contains("windows") ? ".exe" : "" diff --git a/share/qbs/modules/cpp/windows-msvc-base.qbs b/share/qbs/modules/cpp/windows-msvc-base.qbs index e88c3f15f..c103ee691 100644 --- a/share/qbs/modules/cpp/windows-msvc-base.qbs +++ b/share/qbs/modules/cpp/windows-msvc-base.qbs @@ -81,7 +81,6 @@ CppModule { separateDebugInformation: true property bool generateManifestFile: true - property string toolchainInstallPath architecture: qbs.architecture endianness: "little" diff --git a/share/qbs/modules/ico/ico.js b/share/qbs/modules/ico/ico.js index 997a6dc23..a61d585ab 100644 --- a/share/qbs/modules/ico/ico.js +++ b/share/qbs/modules/ico/ico.js @@ -29,6 +29,7 @@ ****************************************************************************/ var File = require("qbs.File"); +var FileInfo = require("qbs.FileInfo"); var Process = require("qbs.Process"); function prepareIconset(project, product, inputs, outputs, input, output) { diff --git a/share/qbs/modules/java/JavaModule.qbs b/share/qbs/modules/java/JavaModule.qbs index ad055fe34..ceb29f36f 100644 --- a/share/qbs/modules/java/JavaModule.qbs +++ b/share/qbs/modules/java/JavaModule.qbs @@ -240,7 +240,7 @@ Module { if (!product.java._tagJniHeaders) { for (var i = 0; i < artifacts.length; ++i) { var a = artifacts[i]; - if (Array.isArray(a.fileTags)) + if (a.fileTags instanceof Array) a.fileTags = a.fileTags.map(function(tag) { if (tag === "hpp") return "java.jni-hpp"; diff --git a/share/qbs/modules/protobuf/cpp/protobufcpp.qbs b/share/qbs/modules/protobuf/cpp/protobufcpp.qbs index 47d1a60c1..12d4e159f 100644 --- a/share/qbs/modules/protobuf/cpp/protobufcpp.qbs +++ b/share/qbs/modules/protobuf/cpp/protobufcpp.qbs @@ -12,6 +12,8 @@ ProtobufBase { property bool useGrpc: false + property bool _linkLibraries: true + property string grpcIncludePath: grpcIncludeProbe.path property string grpcLibraryPath: grpcLibraryProbe.path @@ -33,6 +35,9 @@ ProtobufBase { } cpp.libraryPaths: { + if (!_linkLibraries) + return []; + var result = []; if (libraryPath) result.push(libraryPath); @@ -41,6 +46,9 @@ ProtobufBase { return result; } cpp.dynamicLibraries: { + if (!_linkLibraries) + return []; + var result = []; if (_libraryName) result.push(_libraryName) @@ -51,6 +59,9 @@ ProtobufBase { return result; } cpp.includePaths: { + if (!_linkLibraries) + return [outputDir]; + var result = [outputDir]; if (includePath) result.push(includePath); @@ -118,17 +129,17 @@ ProtobufBase { validate: { HelperFunctions.validateCompiler(compilerName, compilerPath); - if (!HelperFunctions.checkPath(includePath)) + if (_linkLibraries && !HelperFunctions.checkPath(includePath)) throw "Can't find cpp protobuf include files. Please set the includePath property."; - if (!HelperFunctions.checkPath(libraryPath)) + if (_linkLibraries && !HelperFunctions.checkPath(libraryPath)) throw "Can't find cpp protobuf library. Please set the libraryPath property."; if (useGrpc) { if (!File.exists(grpcPluginPath)) throw "Can't find grpc_cpp_plugin plugin. Please set the grpcPluginPath property."; - if (!HelperFunctions.checkPath(grpcIncludePath)) + if (_linkLibraries && !HelperFunctions.checkPath(grpcIncludePath)) throw "Can't find grpc++ include files. Please set the grpcIncludePath property."; - if (!HelperFunctions.checkPath(grpcLibraryPath)) + if (_linkLibraries && !HelperFunctions.checkPath(grpcLibraryPath)) throw "Can't find grpc++ library. Please set the grpcLibraryPath property."; } } diff --git a/share/qbs/modules/xcode/xcode.js b/share/qbs/modules/xcode/xcode.js index 9c87e09dc..1060894d4 100644 --- a/share/qbs/modules/xcode/xcode.js +++ b/share/qbs/modules/xcode/xcode.js @@ -93,6 +93,16 @@ var XcodeArchSpecsReader = (function () { return XcodeArchSpecsReader; }()); +function platformInfo(platformInfoPlist) { + var propertyList = new PropertyList(); + try { + propertyList.readFromFile(platformInfoPlist); + return propertyList.toObject(); + } finally { + propertyList.clear(); + } +} + function sdkInfoList(sdksPath) { var sdkInfo = []; var sdks = File.directoryEntries(sdksPath, File.Dirs | File.NoDotAndDotDot); @@ -181,6 +191,17 @@ function provisioningProfilePlistContents(filePath) { } } +function boolFromSdkOrPlatform(varName, sdkProps, platformProps, defaultValue) { + var values = [(sdkProps || {})[varName], (platformProps || {})[varName]]; + for (var i = 0; i < values.length; ++i) { + if (values[i] === "YES") + return true; + if (values[i] === "NO") + return false; + } + return defaultValue; +} + function archsSpecsPath(version, targetOS, platformType, platformPath, devicePlatformPath) { var _specsPluginBaseName; if (Utilities.versionCompare(version, "12") >= 0) { diff --git a/share/qbs/modules/xcode/xcode.qbs b/share/qbs/modules/xcode/xcode.qbs index aeb0760ac..6c0584c81 100644 --- a/share/qbs/modules/xcode/xcode.qbs +++ b/share/qbs/modules/xcode/xcode.qbs @@ -7,7 +7,6 @@ import qbs.ModUtils import qbs.Probes import qbs.PropertyList import qbs.Utilities -import 'xcode.js' as Xcode Module { id: xcodeModule @@ -87,31 +86,6 @@ Module { } } - property string signingIdentity - readonly property string actualSigningIdentity: { - if (_actualSigningIdentity && _actualSigningIdentity.length === 2) - return _actualSigningIdentity[0]; - } - - readonly property string actualSigningIdentityDisplayName: { - if (_actualSigningIdentity && _actualSigningIdentity.length === 2) - return _actualSigningIdentity[1]; - } - - property string signingTimestamp: "none" - - property string provisioningProfile - - property string xcodebuildName: "xcodebuild" - property string xcodebuildPath: FileInfo.joinPaths(developerPath, "usr", "bin", xcodebuildName) - - property string securityName: "security" - property string securityPath: securityName - - property string codesignName: "codesign" - property string codesignPath: codesignName - property stringList codesignFlags - readonly property path toolchainPath: FileInfo.joinPaths(toolchainsPath, "XcodeDefault" + ".xctoolchain") readonly property path platformPath: FileInfo.joinPaths(platformsPath, @@ -143,35 +117,11 @@ Module { readonly property path toolchainInfoPlist: FileInfo.joinPaths(toolchainPath, "ToolchainInfo.plist") - readonly property stringList _actualSigningIdentity: { - if (/^[A-Fa-f0-9]{40}$/.test(signingIdentity)) { - return [signingIdentity, signingIdentity]; - } - - var result = []; + readonly property var _platformSettings: xcodeProbe.platformSettings - if (signingIdentity) { - var identities = Utilities.signingIdentities(); - for (var key in identities) { - if (identities[key].subjectInfo.CN === signingIdentity) { - result.push([key, signingIdentity]); - } - } - - if (result.length == 0) { - throw "Unable to find signingIdentity '" + signingIdentity + "'"; - } - - if (result.length > 1) { - throw "Signing identity '" + signingIdentity + "' is ambiguous"; - } - } - - return result[0]; - } - - property path provisioningProfilesPath: { - return FileInfo.joinPaths(Environment.getEnv("HOME"), "Library/MobileDevice/Provisioning Profiles"); + readonly property var _platformProps: { + if (_platformSettings) + return _platformSettings["DefaultProperties"]; } readonly property stringList standardArchitectures: _architectureSettings["ARCHS_STANDARD"] @@ -197,6 +147,12 @@ Module { } } + readonly property var _sdkProps: { + if (_sdkSettings) { + return _sdkSettings["DefaultProperties"]; + } + } + qbs.sysroot: sdkPath validate: { @@ -231,23 +187,10 @@ Module { validator.validate(); } - property var buildEnv: { - var env = { - "DEVELOPER_DIR": developerPath, - "SDKROOT": sdkPath - }; - - var prefixes = [platformPath + "/Developer", toolchainPath, developerPath]; - for (var i = 0; i < prefixes.length; ++i) { - var codesign_allocate = prefixes[i] + "/usr/bin/codesign_allocate"; - if (File.exists(codesign_allocate)) { - env["CODESIGN_ALLOCATE"] = codesign_allocate; - break; - } - } - - return env; - } + property var buildEnv: ({ + "DEVELOPER_DIR": developerPath, + "SDKROOT": sdkPath + }) setupBuildEnvironment: { var v = new ModUtils.EnvironmentVariable("PATH", product.qbs.pathListSeparator, false); @@ -261,191 +204,4 @@ Module { v.set(); } } - - Group { - name: "Provisioning Profiles" - prefix: xcode.provisioningProfilesPath + "/" - files: ["*.mobileprovision", "*.provisionprofile"] - fileTags: ["xcode.provisioningprofile"] - } - - FileTagger { - fileTags: ["xcode.entitlements"] - patterns: ["*.entitlements"] - } - - FileTagger { - fileTags: ["xcode.provisioningprofile"] - patterns: ["*.mobileprovision", "*.provisionprofile"] - } - - Rule { - inputs: ["xcode.provisioningprofile"] - - Artifact { - filePath: FileInfo.joinPaths("provisioning-profiles", input.fileName + ".xml") - fileTags: ["xcode.provisioningprofile.data"] - } - - prepare: { - var cmds = []; - - var cmd = new Command("openssl", ["smime", "-verify", "-noverify", "-inform", "DER", - "-in", input.filePath, "-out", output.filePath]); - cmd.silent = true; - cmd.stderrFilterFunction = function (output) { - return output.replace("Verification successful\n", ""); - }; - cmds.push(cmd); - - cmd = new JavaScriptCommand(); - cmd.silent = true; - cmd.inputFilePath = input.filePath; - cmd.outputFilePath = output.filePath; - cmd.sourceCode = function() { - var propertyList = new PropertyList(); - try { - propertyList.readFromFile(outputFilePath); - propertyList.readFromObject({ - data: propertyList.toObject(), - fileName: FileInfo.fileName(inputFilePath), - filePath: inputFilePath - }); - propertyList.writeToFile(outputFilePath, "xml1"); - } finally { - propertyList.clear(); - } - }; - cmds.push(cmd); - - return cmds; - } - } - - Rule { - multiplex: true - inputs: ["xcode.provisioningprofile.data"] - outputFileTags: ["xcode.provisioningprofile.main", "xcode.provisioningprofile.data.main"] - - outputArtifacts: { - var artifacts = []; - for (var i = 0; i < inputs["xcode.provisioningprofile.data"].length; ++i) { - var dataFile = inputs["xcode.provisioningprofile.data"][i].filePath; - var query = product.moduleProperty("xcode", "provisioningProfile"); - var obj = Xcode.provisioningProfilePlistContents(dataFile); - if (obj && obj.data && (obj.data.UUID === query || obj.data.Name === query)) { - console.log("Using provisioning profile: " + obj.filePath); - artifacts.push({ - filePath: obj.fileName, - fileTags: ["xcode.provisioningprofile.main"], - qbs: { _inputFilePath: obj.filePath } - }); - - artifacts.push({ - filePath: obj.fileName + ".xml", - fileTags: ["xcode.provisioningprofile.data.main"], - qbs: { _inputFilePath: dataFile } - }); - } - } - return artifacts; - } - - prepare: { - var cmds = []; - for (var tag in outputs) { - for (var i = 0; i < outputs[tag].length; ++i) { - var output = outputs[tag][i]; - var cmd = new JavaScriptCommand(); - cmd.silent = true; - cmd.inputFilePath = output.qbs._inputFilePath; // there's no such prop in qbs, see QBS-754 - cmd.outputFilePath = output.filePath; - cmd.sourceCode = function() { - File.copy(inputFilePath, outputFilePath); - }; - cmds.push(cmd); - } - } - return cmds; - } - } - - Rule { - inputs: ["xcode.entitlements", "xcode.provisioningprofile.data.main"] - - Artifact { - filePath: FileInfo.joinPaths(product.destinationDirectory, - product.targetName + ".xcent") - fileTags: ["xcent"] - } - - prepare: { - var cmd = new JavaScriptCommand(); - cmd.description = "generating entitlements"; - cmd.highlight = "codegen"; - cmd.bundleIdentifier = product.moduleProperty("bundle", "identifier"); - cmd.signingEntitlements = inputs["xcode.entitlements"] - ? inputs["xcode.entitlements"].map(function (a) { return a.filePath; }) - : []; - cmd.platformPath = ModUtils.moduleProperty(product, "platformPath"); - cmd.sdkPath = ModUtils.moduleProperty(product, "sdkPath"); - cmd.sourceCode = function() { - var i; - var provData = Xcode.provisioningProfilePlistContents(input.filePath); - if (provData) - provData = provData.data; - - var aggregateEntitlements = {}; - - // Start building up an aggregate entitlements plist from the files in the SDKs, - // which contain placeholders in the same manner as Info.plist - function entitlementsFileContents(path) { - return File.exists(path) ? BundleTools.infoPlistContents(path) : undefined; - } - var entitlementsSources = [ - entitlementsFileContents(FileInfo.joinPaths(platformPath, "Entitlements.plist")), - entitlementsFileContents(FileInfo.joinPaths(sdkPath, "Entitlements.plist")) - ]; - - for (i = 0; i < signingEntitlements.length; ++i) { - entitlementsSources.push(entitlementsFileContents(signingEntitlements[i])); - } - - for (i = 0; i < entitlementsSources.length; ++i) { - var contents = entitlementsSources[i]; - for (var key in contents) { - if (contents.hasOwnProperty(key)) - aggregateEntitlements[key] = contents[key]; - } - } - - contents = provData["Entitlements"]; - for (key in contents) { - if (contents.hasOwnProperty(key) && !aggregateEntitlements.hasOwnProperty(key)) - aggregateEntitlements[key] = contents[key]; - } - - // Expand entitlements variables with data from the provisioning profile - var env = { - "AppIdentifierPrefix": provData["ApplicationIdentifierPrefix"] + ".", - "CFBundleIdentifier": bundleIdentifier - }; - DarwinTools.expandPlistEnvironmentVariables(aggregateEntitlements, env, true); - - // Anything with an undefined or otherwise empty value should be removed - // Only JSON-formatted plists can have null values, other formats error out - // This also follows Xcode behavior - DarwinTools.cleanPropertyList(aggregateEntitlements); - - var plist = new PropertyList(); - try { - plist.readFromObject(aggregateEntitlements); - plist.writeToFile(outputs.xcent[0].filePath, "xml1"); - } finally { - plist.clear(); - } - }; - return [cmd]; - } - } } |