diff options
125 files changed, 3542 insertions, 487 deletions
diff --git a/.gitignore b/.gitignore index 636212ee5..af37f8f0f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.qmake.cache +.qmake.stash .qbs build *.dll @@ -10,6 +12,8 @@ build *.pdb *.pro.user* *.qbs.user* +*.xcodeproj/ +target_wrapper.sh *~ *.o *.lib diff --git a/dist/dist.qbs b/dist/dist.qbs index a43f5820e..3278cd2c3 100644 --- a/dist/dist.qbs +++ b/dist/dist.qbs @@ -49,7 +49,7 @@ Product { cmd.binaryFilePaths = inputs.installable.filter(function (artifact) { return artifact.fileTags.contains("application") || artifact.fileTags.contains("dynamiclibrary"); - }).map(ModUtils.artifactInstalledFilePath); + }).map(function(a) { return ModUtils.artifactInstalledFilePath(a); }); cmd.sourceCode = function () { var out; var process; @@ -90,7 +90,9 @@ Product { prepare: { var cmd = new JavaScriptCommand(); cmd.silent = true; - cmd.inputFilePaths = inputs.installable.map(ModUtils.artifactInstalledFilePath); + cmd.inputFilePaths = inputs.installable.map(function(a) { + return ModUtils.artifactInstalledFilePath(a); + }); cmd.outputFilePath = output.filePath; cmd.installRoot = product.moduleProperty("qbs", "installRoot"); cmd.sourceCode = function() { diff --git a/doc/reference/items/artifact.qdoc b/doc/reference/items/artifact.qdoc index 4c5e6b3ef..e9a6330a7 100644 --- a/doc/reference/items/artifact.qdoc +++ b/doc/reference/items/artifact.qdoc @@ -37,7 +37,8 @@ \title Artifact Item \brief Describes a file produced by a \c Rule or \c Transformer. - An \c Artifact represents a single file produced by a \c Rule or \c Transformer. + An \c Artifact represents a single file produced by a \l{Rule Item}{Rule} or + \l{Transformer Item}{Transformer}. For example, if a rule produces three files, it needs to contain three Artifact items. diff --git a/doc/reference/items/rule.qdoc b/doc/reference/items/rule.qdoc index 37be27954..e74b6fd3d 100644 --- a/doc/reference/items/rule.qdoc +++ b/doc/reference/items/rule.qdoc @@ -149,8 +149,8 @@ \code outputArtifacts: [{filePath: "myfile.txt", fileTags: ["foo", "bar"]}] \endcode - For a description of the possible properties, see the documentation of the Artifact - item. + For a description of the possible properties, see the documentation of the + \l{Artifact item}. Output artifacts can be specified either by \c{Rule.outputArtifacts} or by \c{Artifact} items. Use \c{Rule.outputArtifacts} if the set of outputs is not fixed but dependent on the input's content. If no file tags are provided, \QBS will apply all diff --git a/doc/reference/jsextensions/jsextensions-general.qdoc b/doc/reference/jsextensions/jsextensions-general.qdoc index 1e63ce574..61c95231b 100644 --- a/doc/reference/jsextensions/jsextensions-general.qdoc +++ b/doc/reference/jsextensions/jsextensions-general.qdoc @@ -75,6 +75,20 @@ \endcode Returns \c{true} if the array contains the element \c{e}. Returns \c{false} otherwise. + \section2 Array.containsAll + \code + Array.containsAll(other: any[]): boolean + \endcode + Returns \c{true} if the array contains every element in the \c{other} array. + Returns \c{false} otherwise. + + \section2 Array.containsAny + \code + Array.containsAny(other: any[]): boolean + \endcode + Returns \c{true} if the array contains some element(s) in the \c{other} array. + Returns \c{false} otherwise. + \section2 Array.uniqueConcat \code Array.uniqueConcat(other: any[]): any[] diff --git a/doc/reference/modules/android-ndk-module.qdoc b/doc/reference/modules/android-ndk-module.qdoc index 0d9e10e52..dc95ec10a 100644 --- a/doc/reference/modules/android-ndk-module.qdoc +++ b/doc/reference/modules/android-ndk-module.qdoc @@ -97,18 +97,6 @@ \li undefined \li Whether to use the hard floating point variant of the armeabi-v7a ABI. \row - \li enableExceptions - \li bool - \li 1.4 - \li \c{appStl !== "system"} - \li Whether to enable exceptions in C++ code. - \row - \li enableRtti - \li bool - \li 1.4 - \li \c{appStl !== "system"} - \li Whether to enable runtime type information in C++ code. - \row \li ndkDir \li path \li 1.4 diff --git a/doc/reference/modules/bundle-module.qdoc b/doc/reference/modules/bundle-module.qdoc index daa444c3f..471d44a8b 100644 --- a/doc/reference/modules/bundle-module.qdoc +++ b/doc/reference/modules/bundle-module.qdoc @@ -69,12 +69,11 @@ whether it should actually be built as a bundle. \row \li isShallow - \li \c{bool} + \li \c{bool} (read only) \li 1.4 - \li \c{true} for iOS applications + \li \c{false} on OS X, otherwise \c{true} \li Whether the bundle directory tree is "shallow", i.e. whether it lacks a Contents - subdirectory. This is the default for iOS applications and should normally never be - changed. + subdirectory. This is the default on all platforms other than OS X. \row \li identifierPrefix \li \c{string} @@ -112,6 +111,14 @@ This property should almost never need to be changed, though specifying an alternative package type for custom bundles is allowed. \row + \li generatePackageInfo + \li \c{bool} + \li 1.5 + \li \c{true} for applications, otherwise \c{false} + \li Whether to generate a PkgInfo file for the bundle. + This property should almost never need to be changed, though enabling it when specifying + an alternative package type for custom bundles using \c{packageType} is allowed. + \row \li signature \li \c{string} \li 1.4 @@ -207,10 +214,13 @@ \row \li infoPlistPath \li 1.4 - \li Path that the Info.plist file will be written to. If \c{embedInfoPlist} is \c{true}, - this will point to a file in a temporary directory. + \li Path that the Info.plist file will be written to. \row - \li infoPlistPath + \li infoStringsPath + \li 1.5 + \li Path that the InfoPlist.strings file will be written to. + \row + \li pkgInfoPath \li 1.4 \li Path that the PkgInfo file will be written to. \row @@ -222,6 +232,14 @@ \li 1.4 \li Path that the main executable file will be written to. \row + \li contentsFolderPath + \li 1.4 + \li Path of the bundle's Contents subdirectory. + \row + \li documentationFolderPath + \li 1.5 + \li Path of the directory where documentation will be written. + \row \li executableFolderPath \li 1.4 \li Path of the directory where the main exectuable will be written. @@ -236,6 +254,14 @@ \li 1.4 \li Path of the directory where internal frameworks will be copied. \row + \li javaFolderPath + \li 1.5 + \li Path of the directory where Java content will be written. + \row + \li localizedResourcesFolderPath + \li 1.5 + \li Path of the directory where localized resource files will be copied. + \row \li pluginsFolderPath \li 1.4 \li Path of the directory where plugins will be copied. @@ -265,8 +291,9 @@ \li Path of the directory where non-localized resource files will be copied. This is the same as the base resources path. \row - \li contentsFolderPath - \li 1.4 - \li Path of the bundle's Contents subdirectory. + \li versionsFolderPath + \li 1.5 + \li Path of the bundle's Versions subdirectory. + This is only relevant for (non-shallow) framework bundles. \endtable */ diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc index 49d681260..0980f3d9e 100644 --- a/doc/reference/modules/cpp-module.qdoc +++ b/doc/reference/modules/cpp-module.qdoc @@ -329,7 +329,26 @@ toolchain is used. \note For MSVC the default value is \c{"dynamic"}. \note At the moment this property is only functional for MSVC. - + \row + \li enableExceptions + \li \c{bool} + \li 1.5 + \li \c{undefined} + \li Whether to enable exceptions in C++ code. + \row + \li exceptionHandlingModel + \li \c{string} + \li 1.5 + \li \c{"default"} + \li The exception handling model to use. For MSVC, this can be \c{"default"}, \c{"seh"} or + \c{"externc"}. For all other compilers, \c{"default"} indicates the default or only + exception handling model. + \row + \li enableRtti + \li \c{bool} + \li 1.5 + \li \c{undefined} + \li Whether to enable runtime type information in C++ code. \row \li enableReproducibleBuilds \li \c{bool} diff --git a/doc/reference/modules/xcode-module.qdoc b/doc/reference/modules/xcode-module.qdoc index 4e772a573..b3f05c335 100644 --- a/doc/reference/modules/xcode-module.qdoc +++ b/doc/reference/modules/xcode-module.qdoc @@ -59,12 +59,6 @@ directory of the Xcode installation at its default location in /Applications. Corresponds to the \c DEVELOPER_DIR environment variable. \row - \li provisioningProfile - \li string - \li 1.5 - \li \c undefined - \li Name or UUID of the provisioning profile to embed in the product. - \row \li sdk \li string \li 1.5 @@ -75,26 +69,6 @@ available for that platform will be used. The default is the latest SDK available in the Xcode installation for the current platform. \row - \li signingIdentity - \li string - \li 1.5 - \li \c undefined - \li Search string used to find the certificate to sign the product. This does not have to be - a full certificate name like "Mac Developer: John Doe (XXXXXXXXXX)", and can instead be - a partial string like "Mac Developer". - The search string should generally be one of the following: - \list - \li 3rd Party Mac Developer Application - \li 3rd Party Mac Developer Installer - \li Developer ID Application - \li Developer ID Installer - \li iPhone Developer - \li iPhone Distribution - \li Mac Developer - \endlist - See \l{https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html#//apple_ref/doc/uid/TP40012582-CH31-SW41}{Maintaining Your Signing Identities and Certificates} - for complete documentation on the existing certificate types. - \row \li targetDevices \li stringList \li 1.5 @@ -105,32 +79,6 @@ the current platform. \endtable - \section1 Advanced Properties - - \table - \header - \li Property - \li Type - \li Since - \li Default - \li Description - \row - \li provisioningProfilesPath - \li path - \li 1.5 - \li \c{"~/Library/MobileDevice/Provisioning Profiles"} - \li Path to directory containing provisioning profiles installed on the system. - \row - \li signingTimestamp - \li string - \li 1.5 - \li \c{"none"} - \li URL of the timestamp authority server to be contacted to authenticate code signing. - \c{undefined} indicates that a system-specific default should be used, and the empty - string indicates the default server provided by Apple. \c{"none"} explicitly disables - the use of timestamp services and this should not usually need to be changed. - \endtable - \section1 Read-only Properties \table diff --git a/share/qbs/imports/qbs/DarwinTools/darwin-tools.js b/share/qbs/imports/qbs/DarwinTools/darwin-tools.js index 670ca8181..ad67dc16b 100644 --- a/share/qbs/imports/qbs/DarwinTools/darwin-tools.js +++ b/share/qbs/imports/qbs/DarwinTools/darwin-tools.js @@ -31,38 +31,45 @@ var FileInfo = loadExtension("qbs.FileInfo"); var Utilities = loadExtension("qbs.Utilities"); +var _deviceMap = { + "mac": undefined, // only devices have an ID + "iphone": 1, + "ipad": 2, + "tv": 3, + "watch": 4, + "car": 5 +}; + +var _platformMap = { + "ios": "iPhone", + "osx": "MacOSX", + "tvos": "AppleTV", + "watchos": "Watch" +}; + +var _platformDeviceMap = { + "ios": ["iphone", "ipad"], + "osx": ["mac"], + "tvos": ["tv"], + "watchos": ["watch"] +} + /** * Returns the numeric identifier corresponding to an Apple device name * (i.e. for use by TARGETED_DEVICE_FAMILY). */ function appleDeviceNumber(deviceName) { - if (deviceName === "mac") { - return undefined; // only iOS devices have an ID - } else if (deviceName === "iphone") { - return 1; - } else if (deviceName === "ipad") { - return 2; - } else if (deviceName === "tv") { - return 3; - } else if (deviceName === "watch") { - return 4; - } else if (deviceName === "car") { - return 5; - } + return _deviceMap[deviceName]; } /** * Returns the list of target devices available for the given qbs target OS list. */ function targetDevices(targetOS) { - if (targetOS.contains("osx")) - return ["mac"]; - if (targetOS.contains("ios")) - return ["iphone", "ipad"]; - if (targetOS.contains("tvos")) - return ["tv"]; - if (targetOS.contains("watchos")) - return ["watch"]; + for (var key in _platformDeviceMap) { + if (targetOS.contains(key)) + return _platformDeviceMap[key]; + } } /** @@ -77,22 +84,26 @@ function targetedDeviceFamily(deviceNames) { /** * Returns the most appropriate Apple platform name given a targetOS list. */ -function applePlatformName(targetOSList) { - if (targetOSList.contains("ios-simulator")) - return "iphonesimulator"; - else if (targetOSList.contains("ios")) - return "iphoneos"; - else if (targetOSList.contains("osx")) - return "macosx"; - else if (targetOSList.contains("tvos-simulator")) - return "appletvsimulator"; - else if (targetOSList.contains("tvos")) - return "appletvos"; - else if (targetOSList.contains("watchos-simulator")) - return "watchsimulator"; - else if (targetOSList.contains("watchos")) - return "watchos"; - throw("No Apple platform corresponds to target OS list: " + targetOSList); +function applePlatformName(targetOSList, platformType) { + return applePlatformDirectoryName(targetOSList, platformType).toLowerCase(); +} + +/** + * Returns the most appropriate Apple platform directory name given a targetOS list and version. + */ +function applePlatformDirectoryName(targetOSList, platformType, version, throwOnError) { + var suffixMap = { + "device": "OS", + "simulator": "Simulator" + }; + + for (var key in _platformMap) { + if (targetOSList.contains(key)) + return _platformMap[key] + (suffixMap[platformType] || "") + (version || ""); + } + + if (throwOnError || throwOnError === undefined) + throw("No Apple platform corresponds to target OS list: " + targetOSList); } /** diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js index 262704da9..493316850 100644 --- a/share/qbs/imports/qbs/ModUtils/utils.js +++ b/share/qbs/imports/qbs/ModUtils/utils.js @@ -452,7 +452,8 @@ var BlackboxOutputArtifactTracker = (function () { "/B", "/S", "/A:-D"], true); else proc.exec("find", [dir, "-type", "f"], true); - return proc.readStdOut().trim().split(/\r?\n/).map(FileInfo.fromWindowsSeparators); + return proc.readStdOut().trim().split(/\r?\n/).map( + function(p) { return FileInfo.fromWindowsSeparators(p); }); } finally { if (proc) diff --git a/share/qbs/imports/qbs/PathTools/path-tools.js b/share/qbs/imports/qbs/PathTools/path-tools.js index 5333127d8..02de91b4a 100644 --- a/share/qbs/imports/qbs/PathTools/path-tools.js +++ b/share/qbs/imports/qbs/PathTools/path-tools.js @@ -126,22 +126,21 @@ function debugInfoIsBundle(product) { function debugInfoFileName(product) { var suffix = ""; - // For bundled dSYMs, the suffix appears on the bundle name, not the actual debug info file + // For dSYM bundles, the DWARF debug info file has no suffix if (!product.moduleProperty("qbs", "targetOS").contains("darwin") || !debugInfoIsBundle(product)) suffix = product.moduleProperty("cpp", "debugInfoSuffix"); - if (product.moduleProperty("bundle", "isBundle")) { - if (!debugInfoIsBundle(product)) - return product.moduleProperty("bundle", "bundleName") + suffix; - } else if (product.type.contains("application")) - return applicationFileName(product) + suffix; - else if (product.type.contains("dynamiclibrary")) - return dynamicLibraryFileName(product) + suffix; - else if (product.type.contains("loadablemodule")) - return loadableModuleFileName(product) + suffix; - else if (product.type.contains("staticlibrary")) - return staticLibraryFileName(product) + suffix; + if (!product.moduleProperty("bundle", "isBundle")) { + if (product.type.contains("application")) + return applicationFileName(product) + suffix; + else if (product.type.contains("dynamiclibrary")) + return dynamicLibraryFileName(product) + suffix; + else if (product.type.contains("loadablemodule")) + return loadableModuleFileName(product) + suffix; + else if (product.type.contains("staticlibrary")) + return staticLibraryFileName(product) + suffix; + } return product.targetName + suffix; } @@ -149,7 +148,7 @@ function debugInfoFileName(product) { function debugInfoBundlePath(product) { if (!debugInfoIsBundle(product)) return undefined; - var suffix = product.moduleProperty("cpp", "debugInfoSuffix"); + var suffix = product.moduleProperty("cpp", "debugInfoBundleSuffix"); if (product.moduleProperty("qbs", "targetOS").contains("darwin") && product.moduleProperty("bundle", "isBundle")) return product.moduleProperty("bundle", "bundleName") + suffix; @@ -161,6 +160,8 @@ function debugInfoFilePath(product) { if (product.moduleProperty("qbs", "targetOS").contains("darwin") && debugInfoIsBundle(product)) { return FileInfo.joinPaths(debugInfoBundlePath(product), "Contents", "Resources", "DWARF", name); + } else if (product.moduleProperty("bundle", "isBundle")) { + return FileInfo.joinPaths(product.moduleProperty("bundle", "executableFolderPath"), name); } return name; diff --git a/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs b/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs index ecaf91180..2f648d19e 100644 --- a/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs +++ b/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs @@ -33,7 +33,7 @@ import qbs.Environment import qbs.FileInfo BinaryProbe { - names: ["nodejs", "node"] + names: ["node", "nodejs"] platformPaths: { var paths = base; if (qbs.hostOS.contains("windows")) { diff --git a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs index cc7782a73..b0b4ecf14 100644 --- a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs +++ b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs @@ -41,6 +41,7 @@ BinaryProbe { pathPrefixes: [packageManagerBinPath] // Inputs + property path interpreterPath property path packageManagerBinPath property path packageManagerRootPath @@ -50,6 +51,8 @@ BinaryProbe { configure: { if (!condition) return; + if (!interpreterPath) + throw '"interpreterPath" must be specified'; if (!packageManagerBinPath) throw '"packageManagerBinPath" must be specified'; if (!packageManagerRootPath) @@ -59,7 +62,7 @@ BinaryProbe { pathSuffixes, platformPaths, environmentPaths, platformEnvironmentPaths, qbs.pathListSeparator); result.version = result.found - ? TypeScript.findTscVersion(result.filePath, packageManagerBinPath) + ? TypeScript.findTscVersion(result.filePath, interpreterPath) : undefined; if (FileInfo.fromNativeSeparators(packageManagerBinPath) !== result.path || !File.exists(FileInfo.fromNativeSeparators(packageManagerRootPath, "typescript"))) { diff --git a/share/qbs/imports/qbs/Probes/path-probe.js b/share/qbs/imports/qbs/Probes/path-probe.js index 4f634876a..53e04fa39 100644 --- a/share/qbs/imports/qbs/Probes/path-probe.js +++ b/share/qbs/imports/qbs/Probes/path-probe.js @@ -39,7 +39,7 @@ function configure(names, nameSuffixes, nameFilter, pathPrefixes, pathSuffixes, throw '"names" must be specified'; var _names = ModUtils.concatAll(names); if (nameFilter) - _names = _names.map(nameFilter); + _names = _names.map(function(n) { return nameFilter(n); }); _names = ModUtils.concatAll.apply(undefined, _names.map(function(name) { return (nameSuffixes || [""]).map(function(suffix) { return name + suffix; }); })); @@ -53,8 +53,8 @@ function configure(names, nameSuffixes, nameFilter, pathPrefixes, pathSuffixes, _paths = _paths.concat(value.split(pathListSeparator)); } var _suffixes = ModUtils.concatAll('', pathSuffixes); - _paths = _paths.map(FileInfo.fromNativeSeparators); - _suffixes = _suffixes.map(FileInfo.fromNativeSeparators); + _paths = _paths.map(function(p) { return FileInfo.fromNativeSeparators(p); }); + _suffixes = _suffixes.map(function(p) { return FileInfo.fromNativeSeparators(p); }); for (i = 0; i < _names.length; ++i) { for (var j = 0; j < _paths.length; ++j) { for (var k = 0; k < _suffixes.length; ++k) { @@ -63,8 +63,15 @@ function configure(names, nameSuffixes, nameFilter, pathPrefixes, pathSuffixes, return { found: true, filePath: _filePath, - fileName: FileInfo.fileName(_filePath), - path: FileInfo.path(_filePath) + + // Manually specify the path components that constitute _filePath rather + // than using the FileInfo.path and FileInfo.fileName functions because we + // want to break _filePath into its constituent parts based on the input + // originally given by the user. For example, the FileInfo functions would + // produce a different result if any of the items in the names property + // contained more than a single path component. + fileName: _names[i], + path: FileInfo.joinPaths(_paths[j], _suffixes[k]), } } } diff --git a/share/qbs/imports/qbs/base/ApplicationExtension.qbs b/share/qbs/imports/qbs/base/ApplicationExtension.qbs index 656007567..0e534de38 100644 --- a/share/qbs/imports/qbs/base/ApplicationExtension.qbs +++ b/share/qbs/imports/qbs/base/ApplicationExtension.qbs @@ -31,10 +31,20 @@ import qbs XPCService { + Depends { name: "xcode" } + type: base.concat(["applicationextension"]) cpp.entryPoint: "_NSExtensionMain" - cpp.frameworks: base.concat(["/System/Library/PrivateFrameworks/PlugInKit.framework"]) + cpp.frameworks: { + var frameworks = base.concat(["Foundation"]); + if (qbs.targetOS.contains("osx") && parseInt(xcode.sdkVersion.split(".")[1], 10) < 11 || + qbs.targetOS.contains("ios") && parseInt(xcode.sdkVersion.split(".")[0], 10) < 9) { + frameworks = base.concat(["/System/Library/PrivateFrameworks/PlugInKit.framework"]); + } + return frameworks; + } + cpp.requireAppExtensionSafeApi: true xpcServiceType: undefined diff --git a/share/qbs/modules/Android/ndk/ndk.qbs b/share/qbs/modules/Android/ndk/ndk.qbs index d9ea534d5..ea7d48352 100644 --- a/share/qbs/modules/Android/ndk/ndk.qbs +++ b/share/qbs/modules/Android/ndk/ndk.qbs @@ -77,8 +77,6 @@ Module { return cpp.toolchainPrefix + toolchainVersionNumber; } - property bool enableExceptions: appStl !== "system" - property bool enableRtti: appStl !== "system" property bool hardFloat property string ndkDir: ndkProbe.path property string platform: "android-9" @@ -206,23 +204,13 @@ Module { qbs.optimization: cpp.targetAbi === "androideabi" ? "small" : base + cpp.enableExceptions: appStl !== "system" + cpp.enableRtti: appStl !== "system" + cpp.commonCompilerFlags: NdkUtils.commonCompilerFlags(qbs.buildVariant, abi, hardFloat, armMode) cpp.linkerFlags: NdkUtils.commonLinkerFlags(abi, hardFloat) - cpp.cxxFlags: { - var flags = []; - if (enableExceptions) - flags.push("-fexceptions"); - else - flags.push("-fno-exceptions"); - if (enableRtti) - flags.push("-frtti"); - else - flags.push("-fno-rtti"); - return flags; - } - cpp.libraryPaths: { var prefix = FileInfo.joinPaths(cpp.sysroot, "usr"); var paths = []; diff --git a/share/qbs/modules/bundle/BundleModule.qbs b/share/qbs/modules/bundle/BundleModule.qbs index 8ec0e8458..88fb6ecd6 100644 --- a/share/qbs/modules/bundle/BundleModule.qbs +++ b/share/qbs/modules/bundle/BundleModule.qbs @@ -31,43 +31,80 @@ 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.TextFile import qbs.Utilities +import "bundle.js" as Bundle Module { + Depends { name: "xcode"; required: false; } + + Probe { + id: bundleSettingsProbe + condition: qbs.targetOS.contains("darwin") + + property string xcodeDeveloperPath: xcode.developerPath + + // Note that we include several settings pointing to properties which reference the output + // of this probe (WRAPPER_NAME, WRAPPER_EXTENSION, etc.). This is to ensure that derived + // properties take into account the value of these settings if the user customized them. + property var additionalSettings: ({ + "DEVELOPMENT_LANGUAGE": "English", + "EXECUTABLE_VARIANT_SUFFIX": "", // e.g. _debug, _profile + "FRAMEWORK_VERSION": frameworkVersion, + "GENERATE_PKGINFO_FILE": generatePackageInfo !== undefined + ? (generatePackageInfo ? "YES" : "NO") + : undefined, + "PRODUCT_NAME": product.targetName, + "LOCAL_APPS_DIR": Environment.getEnv("HOME") + "/Applications", + "LOCAL_LIBRARY_DIR": Environment.getEnv("HOME") + "/Library", + "TARGET_BUILD_DIR": product.buildDirectory, + "WRAPPER_NAME": bundleName, + "WRAPPER_EXTENSION": extension + }) + + // Outputs + property var xcodeSettings: ({}) + + configure: { + var specsPath = path; + var specsSeparator = "-"; + if (xcodeDeveloperPath && _useXcodeBuildSpecs) { + specsPath = xcodeDeveloperPath + + "/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications"; + specsSeparator = " "; + } + + var reader = new Bundle.XcodeBuildSpecsReader(specsPath, + specsSeparator, + additionalSettings, + !qbs.targetOS.contains("osx")); + var settings = reader.expandedSettings(_productTypeIdentifier); + if (settings) { + xcodeSettings = settings; + found = true; + } else { + xcodeSettings = {}; + found = false; + } + } + } + additionalProductTypes: ["bundle"] - property bool isBundle: qbs.targetOS.contains("darwin") - && (product.type.contains("application") - || product.type.contains("dynamiclibrary") - || product.type.contains("loadablemodule")) - && !product.consoleApplication - property bool isShallow: !qbs.targetOS.contains("osx") && product.type.contains("application") + property bool isBundle: !product.consoleApplication && qbs.targetOS.contains("darwin") && + product.type.containsAny(["application", "dynamiclibrary", "loadablemodule"]) + + readonly property bool isShallow: bundleSettingsProbe.xcodeSettings["SHALLOW_BUNDLE"] === "YES" property string identifierPrefix: "org.example" property string identifier: [identifierPrefix, Utilities.rfc1034Identifier(product.targetName)].join(".") - property string extension: { - if (packageType === undefined) { - return ""; - } else if (packageType === "APPL") { - return "app"; - } else if (packageType === "XPC!") { - if (product.type.contains("applicationextension")) - return "appex"; - return "xpc"; - } else if (packageType === "FMWK") { - return "framework"; - } else{ - return "bundle"; - } - - // Also: kext, prefPane, qlgenerator, saver, mdimporter, or a custom extension - } + property string extension: bundleSettingsProbe.xcodeSettings["WRAPPER_EXTENSION"] property string packageType: { if (product.type.contains("inapppurchase")) @@ -76,20 +113,27 @@ Module { return "XPC!"; if (product.type.contains("application")) return "APPL"; - if (product.type.contains("dynamiclibrary") || product.type.contains("staticlibrary")) + if (product.type.containsAny(["dynamiclibrary", "staticlibrary"])) return "FMWK"; + if (product.type.contains("kernelmodule")) + return "KEXT"; return "BNDL"; } property string signature: "????" // legacy creator code in Mac OS Classic (CFBundleSignature), can be ignored - property string bundleName: product.targetName + (extension ? ("." + extension) : "") + property string bundleName: bundleSettingsProbe.xcodeSettings["WRAPPER_NAME"] property string frameworkVersion: { - if (packageType === "FMWK") { - var n = parseInt(product.version, 10); - return isNaN(n) ? 'A' : String(n); - } + var n = parseInt(product.version, 10); + return isNaN(n) ? bundleSettingsProbe.xcodeSettings["FRAMEWORK_VERSION"] : String(n); + } + + property bool generatePackageInfo: { + // Make sure to return undefined as default to indicate "not set" + var genPkgInfo = bundleSettingsProbe.xcodeSettings["GENERATE_PKGINFO_FILE"]; + if (genPkgInfo) + return genPkgInfo === "YES"; } property pathList publicHeaders @@ -110,46 +154,34 @@ Module { "/Versions/A/Support", lsregisterName); // all paths are relative to the directory containing the bundle - readonly property string infoPlistPath: { - var path; - if (!isBundle) - path = FileInfo.joinPaths(".tmp", product.name); - else if (packageType === "FMWK") - path = unlocalizedResourcesFolderPath; - else if (product.type.contains("inapppurchase")) - path = bundleName; - else - path = contentsFolderPath; - - return FileInfo.joinPaths(path, product.type.contains("inapppurchase") ? "ContentInfo.plist" : "Info.plist"); - } - - readonly property string pkgInfoPath: FileInfo.joinPaths(packageType === "FMWK" ? bundleName : contentsFolderPath, "PkgInfo") - readonly property string versionPlistPath: FileInfo.joinPaths(packageType === "FMWK" ? unlocalizedResourcesFolderPath : contentsFolderPath, "version.plist") - - readonly property string executablePath: FileInfo.joinPaths(executableFolderPath, product.targetName) - - readonly property string executableFolderPath: (!isShallow && packageType !== "FMWK" && !isShallowContents) ? FileInfo.joinPaths(contentsFolderPath, "MacOS") : contentsFolderPath - readonly property string executablesFolderPath: packageType === "FMWK" ? unlocalizedResourcesFolderPath : FileInfo.joinPaths(contentsFolderPath, !isShallowContents ? "Executables" : "") - readonly property string frameworksFolderPath: FileInfo.joinPaths(contentsFolderPath, !isShallowContents ? "Frameworks" : "") - readonly property string pluginsFolderPath: packageType === "FMWK" ? unlocalizedResourcesFolderPath : FileInfo.joinPaths(contentsFolderPath, !isShallowContents ? "PlugIns" : "") - readonly property string privateHeadersFolderPath: FileInfo.joinPaths(contentsFolderPath, !isShallowContents ? "PrivateHeaders" : "") - readonly property string publicHeadersFolderPath: FileInfo.joinPaths(contentsFolderPath, !isShallowContents ? "Headers" : "") - readonly property string scriptsFolderPath: FileInfo.joinPaths(unlocalizedResourcesFolderPath, "Scripts") - readonly property string sharedFrameworksFolderPath: FileInfo.joinPaths(contentsFolderPath, !isShallowContents ? "SharedFrameworks" : "") - readonly property string sharedSupportFolderPath: packageType === "FMWK" ? unlocalizedResourcesFolderPath : FileInfo.joinPaths(contentsFolderPath, !isShallowContents ? "SharedSupport" : "") - readonly property string unlocalizedResourcesFolderPath: isShallow ? contentsFolderPath : FileInfo.joinPaths(contentsFolderPath, !isShallowContents ? "Resources" : "") - - readonly property string contentsFolderPath: { - if (packageType === "FMWK") - return FileInfo.joinPaths(bundleName, "Versions", frameworkVersion); - else if (!isShallow) - return FileInfo.joinPaths(bundleName, "Contents"); - return bundleName; - } + readonly property string infoPlistPath: bundleSettingsProbe.xcodeSettings["INFOPLIST_PATH"] + readonly property string infoStringsPath: bundleSettingsProbe.xcodeSettings["INFOSTRINGS_PATH"] + readonly property string pbdevelopmentPlistPath: bundleSettingsProbe.xcodeSettings["PBDEVELOPMENTPLIST_PATH"] + readonly property string pkgInfoPath: bundleSettingsProbe.xcodeSettings["PKGINFO_PATH"] + readonly property string versionPlistPath: bundleSettingsProbe.xcodeSettings["VERSIONPLIST_PATH"] + + readonly property string executablePath: bundleSettingsProbe.xcodeSettings["EXECUTABLE_PATH"] + + readonly property string contentsFolderPath: bundleSettingsProbe.xcodeSettings["CONTENTS_FOLDER_PATH"] + readonly property string documentationFolderPath: bundleSettingsProbe.xcodeSettings["DOCUMENTATION_FOLDER_PATH"] + readonly property string executableFolderPath: bundleSettingsProbe.xcodeSettings["EXECUTABLE_FOLDER_PATH"] + readonly property string executablesFolderPath: bundleSettingsProbe.xcodeSettings["EXECUTABLES_FOLDER_PATH"] + readonly property string frameworksFolderPath: bundleSettingsProbe.xcodeSettings["FRAMEWORKS_FOLDER_PATH"] + readonly property string javaFolderPath: bundleSettingsProbe.xcodeSettings["JAVA_FOLDER_PATH"] + readonly property string localizedResourcesFolderPath: bundleSettingsProbe.xcodeSettings["LOCALIZED_RESOURCES_FOLDER_PATH"] + readonly property string pluginsFolderPath: bundleSettingsProbe.xcodeSettings["PLUGINS_FOLDER_PATH"] + readonly property string privateHeadersFolderPath: bundleSettingsProbe.xcodeSettings["PRIVATE_HEADERS_FOLDER_PATH"] + readonly property string publicHeadersFolderPath: bundleSettingsProbe.xcodeSettings["PUBLIC_HEADERS_FOLDER_PATH"] + readonly property string scriptsFolderPath: bundleSettingsProbe.xcodeSettings["SCRIPTS_FOLDER_PATH"] + readonly property string sharedFrameworksFolderPath: bundleSettingsProbe.xcodeSettings["SHARED_FRAMEWORKS_FOLDER_PATH"] + readonly property string sharedSupportFolderPath: bundleSettingsProbe.xcodeSettings["SHARED_SUPPORT_FOLDER_PATH"] + readonly property string unlocalizedResourcesFolderPath: bundleSettingsProbe.xcodeSettings["UNLOCALIZED_RESOURCES_FOLDER_PATH"] + readonly property string versionsFolderPath: bundleSettingsProbe.xcodeSettings["VERSIONS_FOLDER_PATH"] // private properties - readonly property bool isShallowContents: product.type.contains("inapppurchase") + property string _productTypeIdentifier: Bundle.productTypeIdentifier(product.type) + + property bool _useXcodeBuildSpecs: true // false to use ONLY the qbs build specs readonly property var extraEnv: ({ "PRODUCT_BUNDLE_IDENTIFIER": identifier @@ -182,6 +214,47 @@ Module { }; } + validate: { + if (!qbs.targetOS.contains("darwin")) + return; + if (!bundleSettingsProbe.found) { + var error = "Bundle product type " + _productTypeIdentifier + " is not supported."; + if ((_productTypeIdentifier || "").startsWith("com.apple.product-type.")) + error += " You may need to upgrade Xcode."; + throw error; + } + + var validator = new ModUtils.PropertyValidator("bundle"); + validator.setRequiredProperty("bundleName", bundleName); + validator.setRequiredProperty("infoPlistPath", infoPlistPath); + validator.setRequiredProperty("pbdevelopmentPlistPath", pbdevelopmentPlistPath); + validator.setRequiredProperty("pkgInfoPath", pkgInfoPath); + validator.setRequiredProperty("versionPlistPath", versionPlistPath); + validator.setRequiredProperty("executablePath", executablePath); + validator.setRequiredProperty("contentsFolderPath", contentsFolderPath); + validator.setRequiredProperty("documentationFolderPath", documentationFolderPath); + validator.setRequiredProperty("executableFolderPath", executableFolderPath); + validator.setRequiredProperty("executablesFolderPath", executablesFolderPath); + validator.setRequiredProperty("frameworksFolderPath", frameworksFolderPath); + validator.setRequiredProperty("javaFolderPath", javaFolderPath); + validator.setRequiredProperty("localizedResourcesFolderPath", localizedResourcesFolderPath); + validator.setRequiredProperty("pluginsFolderPath", pluginsFolderPath); + validator.setRequiredProperty("privateHeadersFolderPath", privateHeadersFolderPath); + validator.setRequiredProperty("publicHeadersFolderPath", publicHeadersFolderPath); + validator.setRequiredProperty("scriptsFolderPath", scriptsFolderPath); + validator.setRequiredProperty("sharedFrameworksFolderPath", sharedFrameworksFolderPath); + validator.setRequiredProperty("sharedSupportFolderPath", sharedSupportFolderPath); + validator.setRequiredProperty("unlocalizedResourcesFolderPath", unlocalizedResourcesFolderPath); + + if (packageType === "FMWK") { + validator.setRequiredProperty("frameworkVersion", frameworkVersion); + validator.setRequiredProperty("versionsFolderPath", versionsFolderPath); + } + + // extension and infoStringsPath might not be set + return validator.validate(); + } + FileTagger { fileTags: ["infoplist"] patterns: ["Info.plist", "*-Info.plist"] @@ -199,9 +272,13 @@ Module { outputFileTags: ["aggregate_infoplist"] outputArtifacts: { var artifacts = []; - if (ModUtils.moduleProperty(product, "isBundle") || ModUtils.moduleProperty(product, "embedInfoPlist")) { + var embed = ModUtils.moduleProperty(product, "embedInfoPlist"); + if (ModUtils.moduleProperty(product, "isBundle") || embed) { artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, ModUtils.moduleProperty(product, "infoPlistPath")), + filePath: FileInfo.joinPaths( + product.destinationDirectory, embed + ? product.name + "-Info.plist" + : ModUtils.moduleProperty(product, "infoPlistPath")), fileTags: ["aggregate_infoplist"] }); } @@ -378,7 +455,7 @@ Module { outputFileTags: ["pkginfo"] outputArtifacts: { var artifacts = []; - if (ModUtils.moduleProperty(product, "isBundle")) { + if (ModUtils.moduleProperty(product, "isBundle") && ModUtils.moduleProperty(product, "generatePackageInfo")) { artifacts.push({ filePath: FileInfo.joinPaths(product.destinationDirectory, ModUtils.moduleProperty(product, "pkgInfoPath")), fileTags: ["pkginfo"] @@ -443,7 +520,8 @@ Module { } var packageType = ModUtils.moduleProperty(product, "packageType"); - if (packageType === "FMWK") { + var isShallow = ModUtils.moduleProperty(product, "isShallow"); + if (packageType === "FMWK" && !isShallow) { var publicHeaders = ModUtils.moduleProperties(product, "publicHeaders"); if (publicHeaders && publicHeaders.length) { artifacts.push({ @@ -471,7 +549,7 @@ Module { }); artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, ModUtils.moduleProperty(product, "bundleName"), "Versions", "Current"), + filePath: FileInfo.joinPaths(product.destinationDirectory, ModUtils.moduleProperty(product, "versionsFolderPath"), "Current"), fileTags: ["bundle.symlink.version"] }); } diff --git a/share/qbs/modules/bundle/MacOSX-Package-Types.xcspec b/share/qbs/modules/bundle/MacOSX-Package-Types.xcspec new file mode 100644 index 000000000..b36353fc7 --- /dev/null +++ b/share/qbs/modules/bundle/MacOSX-Package-Types.xcspec @@ -0,0 +1,462 @@ +[ + { + "DefaultBuildSettings" : { + "EXECUTABLE_PATH" : "$(EXECUTABLE_NAME)", + "EXECUTABLE_PREFIX" : "", + "EXECUTABLE_SUFFIX" : "", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)" + }, + "Identifier" : "com.apple.package-type.mach-o-executable", + "Type" : "PackageType", + "Name" : "Mach-O Executable", + "Description" : "Mach-O executable", + "ProductReference" : { + "FileType" : "compiled.mach-o.executable", + "Name" : "$(EXECUTABLE_NAME)", + "IsLaunchable" : "YES" + } + }, + { + "DefaultBuildSettings" : { + "EXECUTABLE_PATH" : "$(EXECUTABLE_NAME)", + "EXECUTABLE_PREFIX" : "", + "EXECUTABLE_SUFFIX" : "", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)" + }, + "Identifier" : "com.apple.package-type.mach-o-objfile", + "Type" : "PackageType", + "Name" : "Mach-O Object File", + "Description" : "Mach-O Object File", + "ProductReference" : { + "FileType" : "compiled.mach-o.objfile", + "Name" : "$(EXECUTABLE_NAME)", + "IsLaunchable" : "NO" + } + }, + { + "DefaultBuildSettings" : { + "EXECUTABLE_PATH" : "$(EXECUTABLE_NAME)", + "EXECUTABLE_PREFIX" : "", + "EXECUTABLE_SUFFIX" : "", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)" + }, + "Identifier" : "com.apple.package-type.mach-o-dylib", + "Type" : "PackageType", + "Name" : "Mach-O Dynamic Library", + "Description" : "Mach-O dynamic library", + "ProductReference" : { + "FileType" : "compiled.mach-o.dylib", + "Name" : "$(EXECUTABLE_NAME)", + "IsLaunchable" : "NO" + } + }, + { + "DefaultBuildSettings" : { + "EXECUTABLE_PATH" : "$(EXECUTABLE_NAME)", + "EXECUTABLE_PREFIX" : "lib", + "EXECUTABLE_SUFFIX" : ".a", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)" + }, + "Identifier" : "com.apple.package-type.static-library", + "Type" : "PackageType", + "Name" : "Mach-O Static Library", + "Description" : "Mach-O static library", + "ProductReference" : { + "FileType" : "archive.ar", + "Name" : "$(EXECUTABLE_NAME)", + "IsLaunchable" : "NO" + } + }, + { + "DefaultBuildSettings" : { + "EXECUTABLE_PATH" : "$(EXECUTABLE_NAME)", + "EXECUTABLE_PREFIX" : "", + "EXECUTABLE_SUFFIX" : ".dylib", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)" + }, + "Identifier" : "com.apple.package-type.mach-o-bundle", + "Type" : "PackageType", + "Name" : "Mach-O Loadable", + "Description" : "Mach-O loadable", + "ProductReference" : { + "FileType" : "compiled.mach-o.bundle", + "Name" : "$(EXECUTABLE_NAME)", + "IsLaunchable" : "NO" + } + }, + { + "DefaultBuildSettings" : { + "PUBLIC_HEADERS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/Headers", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)", + "EXECUTABLE_PREFIX" : "", + "PLUGINS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/PlugIns", + "DOCUMENTATION_FOLDER_PATH" : "$(LOCALIZED_RESOURCES_FOLDER_PATH)\/Documentation", + "EXECUTABLES_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/Executables", + "INFOSTRINGS_PATH" : "$(LOCALIZED_RESOURCES_FOLDER_PATH)\/InfoPlist.strings", + "INFOPLIST_PATH" : "$(CONTENTS_FOLDER_PATH)\/Info.plist", + "EXECUTABLE_SUFFIX" : "", + "VERSIONPLIST_PATH" : "$(CONTENTS_FOLDER_PATH)\/version.plist", + "SHARED_SUPPORT_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/SharedSupport", + "EXECUTABLE_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/MacOS", + "PBDEVELOPMENTPLIST_PATH" : "$(CONTENTS_FOLDER_PATH)\/pbdevelopment.plist", + "FRAMEWORKS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/Frameworks", + "LOCALIZED_RESOURCES_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/$(DEVELOPMENT_LANGUAGE).lproj", + "SCRIPTS_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/Scripts", + "WRAPPER_PREFIX" : "", + "PRIVATE_HEADERS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/PrivateHeaders", + "CONTENTS_FOLDER_PATH" : "$(WRAPPER_NAME)\/Contents", + "WRAPPER_NAME" : "$(WRAPPER_PREFIX)$(PRODUCT_NAME)$(WRAPPER_SUFFIX)", + "PKGINFO_PATH" : "$(CONTENTS_FOLDER_PATH)\/PkgInfo", + "EXECUTABLE_PATH" : "$(EXECUTABLE_FOLDER_PATH)\/$(EXECUTABLE_NAME)", + "UNLOCALIZED_RESOURCES_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/Resources", + "JAVA_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/Java", + "SHARED_FRAMEWORKS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/SharedFrameworks", + "WRAPPER_SUFFIX" : ".bundle" + }, + "Identifier" : "com.apple.package-type.wrapper", + "Type" : "PackageType", + "Name" : "Wrapper", + "Description" : "Wrapper", + "ProductReference" : { + "FileType" : "wrapper.cfbundle", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + } + }, + { + "ProductReference" : { + "FileType" : "wrapper.cfbundle", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "CONTENTS_FOLDER_PATH" : "$(WRAPPER_NAME)", + "UNLOCALIZED_RESOURCES_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "SHALLOW_BUNDLE" : "YES", + "EXECUTABLE_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper", + "Name" : "Wrapper (Shallow)", + "Identifier" : "com.apple.package-type.wrapper.shallow", + "Description" : "Shallow Wrapper" + }, + { + "ProductReference" : { + "FileType" : "wrapper.application", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "YES" + }, + "DefaultBuildSettings" : { + "GENERATE_PKGINFO_FILE" : "YES" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper", + "Name" : "Application Wrapper", + "Identifier" : "com.apple.package-type.wrapper.application", + "Description" : "Application Wrapper" + }, + { + "ProductReference" : { + "FileType" : "wrapper.application", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "YES" + }, + "DefaultBuildSettings" : { + "UNLOCALIZED_RESOURCES_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "SHALLOW_BUNDLE" : "YES", + "GENERATE_PKGINFO_FILE" : "YES" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper.shallow", + "Name" : "Application Wrapper (Shallow)", + "Identifier" : "com.apple.package-type.wrapper.application.shallow", + "Description" : "Shallow Application Wrapper" + }, + { + "ProductReference" : { + "FileType" : "wrapper.cfbundle", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "PRIVATE_HEADERS_FOLDER_PATH" : "$(KEXT_FRAMEWORK)\/Contents\/PrivateHeaders\/$(KEXT_FAMILY_NAME)", + "PUBLIC_HEADERS_FOLDER_PATH" : "$(KEXT_FRAMEWORK)\/Contents\/Headers\/$(KEXT_FAMILY_NAME)" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper", + "Name" : "Kernel Extension Wrapper", + "Identifier" : "com.apple.package-type.wrapper.kernel-extension", + "Description" : "Kernel Extension Wrapper" + }, + { + "ProductReference" : { + "FileType" : "wrapper.cfbundle", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "PRIVATE_HEADERS_FOLDER_PATH" : "$(KEXT_FRAMEWORK)\/Contents\/PrivateHeaders\/$(KEXT_FAMILY_NAME)", + "PUBLIC_HEADERS_FOLDER_PATH" : "$(KEXT_FRAMEWORK)\/Contents\/Headers\/$(KEXT_FAMILY_NAME)", + "SHALLOW_BUNDLE" : "YES" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper.shallow", + "Name" : "Kernel Extension Wrapper (Shallow)", + "Identifier" : "com.apple.package-type.wrapper.kernel-extension.shallow", + "Description" : "Shallow Kernel Extension Wrapper" + }, + { + "DefaultBuildSettings" : { + "PUBLIC_HEADERS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/Headers", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)", + "EXECUTABLE_PREFIX" : "", + "PLUGINS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/PlugIns", + "DOCUMENTATION_FOLDER_PATH" : "$(LOCALIZED_RESOURCES_FOLDER_PATH)\/Documentation", + "EXECUTABLES_FOLDER_PATH" : "$(LOCALIZED_RESOURCES_FOLDER_PATH)", + "INFOPLIST_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/Info.plist", + "EXECUTABLE_SUFFIX" : "", + "INFOPLISTSTRINGS_PATH" : "$(LOCALIZED_RESOURCES_FOLDER_PATH)\/InfoPlist.strings", + "VERSIONPLIST_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/version.plist", + "SHARED_SUPPORT_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)", + "EXECUTABLE_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "PBDEVELOPMENTPLIST_PATH" : "$(CONTENTS_FOLDER_PATH)\/pbdevelopment.plist", + "VERSIONS_FOLDER_PATH" : "$(WRAPPER_NAME)\/Versions", + "FRAMEWORKS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/Frameworks", + "CODESIGNING_FOLDER_PATH" : "$(TARGET_BUILD_DIR)\/$(CONTENTS_FOLDER_PATH)", + "LOCALIZED_RESOURCES_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/$(DEVELOPMENT_LANGUAGE).lproj", + "SCRIPTS_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/Scripts", + "WRAPPER_PREFIX" : "", + "PRIVATE_HEADERS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/PrivateHeaders", + "CURRENT_VERSION" : "Current", + "PKGINFO_PATH" : "$(WRAPPER_NAME)\/PkgInfo", + "WRAPPER_NAME" : "$(WRAPPER_PREFIX)$(PRODUCT_NAME)$(WRAPPER_SUFFIX)", + "CONTENTS_FOLDER_PATH" : "$(VERSIONS_FOLDER_PATH)\/$(FRAMEWORK_VERSION)", + "EXECUTABLE_PATH" : "$(EXECUTABLE_FOLDER_PATH)\/$(EXECUTABLE_NAME)", + "UNLOCALIZED_RESOURCES_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/Resources", + "JAVA_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/Java", + "SHARED_FRAMEWORKS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)\/SharedFrameworks", + "WRAPPER_SUFFIX" : ".framework" + }, + "Identifier" : "com.apple.package-type.wrapper.framework", + "Type" : "PackageType", + "Name" : "Framework Wrapper", + "Description" : "Framework wrapper", + "ProductReference" : { + "FileType" : "wrapper.framework", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + } + }, + { + "ProductReference" : { + "FileType" : "wrapper.framework.static", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "EXECUTABLE_SUFFIX" : "", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_VARIANT_SUFFIX)$(EXECUTABLE_SUFFIX)", + "EXECUTABLE_PREFIX" : "" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper.framework", + "Name" : "Mach-O Static Framework", + "Identifier" : "com.apple.package-type.wrapper.framework.static", + "Description" : "Mach-O static framework" + }, + { + "ProductReference" : { + "FileType" : "wrapper.framework", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "UNLOCALIZED_RESOURCES_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "CONTENTS_FOLDER_PATH" : "$(WRAPPER_NAME)", + "SHALLOW_BUNDLE" : "YES", + "VERSIONS_FOLDER_PATH" : "$(WRAPPER_NAME)" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper.framework", + "Name" : "Shallow Framework Wrapper", + "Identifier" : "com.apple.package-type.wrapper.framework.shallow", + "Description" : "Shallow framework wrapper" + }, + { + "ProductReference" : { + "FileType" : "wrapper.cfbundle", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "WRAPPER_SUFFIX" : "xctest" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper", + "Name" : "Unit Test Bundle", + "Identifier" : "com.apple.package-type.bundle.unit-test", + "Description" : "Unit Test Bundle" + }, + { + "ProductReference" : { + "FileType" : "wrapper.cfbundle", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "WRAPPER_SUFFIX" : "octest" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper", + "Name" : "OCUnit Test Bundle", + "Identifier" : "com.apple.package-type.bundle.ocunit-test", + "Description" : "OCUnit Test Bundle" + }, + { + "ProductReference" : { + "FileType" : "folder", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "EXECUTABLE_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "JAVA_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)", + "INFOSTRINGS_PATH" : "$(LOCALIZED_RESOURCES_FOLDER_PATH)\/ContentInfo.strings", + "INFOPLIST_PATH" : "$(WRAPPER_NAME)\/ContentInfo.plist", + "WRAPPER_SUFFIX" : "", + "UNLOCALIZED_RESOURCES_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "DOCUMENTATION_FOLDER_PATH" : "$(LOCALIZED_RESOURCES_FOLDER_PATH)", + "EXECUTABLES_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "LOCALIZED_RESOURCES_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)\/$(DEVELOPMENT_LANGUAGE).lproj", + "PLUGINS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "PUBLIC_HEADERS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "SHARED_SUPPORT_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "SHARED_FRAMEWORKS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "PRIVATE_HEADERS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)", + "SCRIPTS_FOLDER_PATH" : "$(UNLOCALIZED_RESOURCES_FOLDER_PATH)", + "FRAMEWORKS_FOLDER_PATH" : "$(CONTENTS_FOLDER_PATH)" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper", + "Name" : "In-App Purchase Content", + "Identifier" : "com.apple.package-type.in-app-purchase-content", + "Description" : "In-App Purchase Content" + }, + { + "ProductReference" : { + "FileType" : "wrapper.xpc-service", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "WRAPPER_SUFFIX" : ".xpc" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper", + "Name" : "XPC Service", + "Identifier" : "com.apple.package-type.xpc-service", + "Description" : "XPC Service" + }, + { + "ProductReference" : { + "FileType" : "wrapper.app-extension", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "WRAPPER_SUFFIX" : ".pluginkit" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.xpc-service", + "Name" : "PlugInKit PlugIn", + "Identifier" : "com.apple.package-type.pluginkit-plugin", + "Description" : "PlugInKit PlugIn" + }, + { + "ProductReference" : { + "FileType" : "wrapper.app-extension", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + "WRAPPER_SUFFIX" : ".appex" + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.pluginkit-plugin", + "Name" : "App Extension", + "Identifier" : "com.apple.package-type.app-extension", + "Description" : "App Extension" + }, + { + "ProductReference" : { + "FileType" : "wrapper.spotlight-importer", + "Name" : "$(WRAPPER_NAME)", + "IsLaunchable" : "NO" + }, + "DefaultBuildSettings" : { + + }, + "Type" : "PackageType", + "BasedOn" : "com.apple.package-type.wrapper", + "Name" : "Spotlight Importer", + "Identifier" : "com.apple.package-type.spotlight-importer", + "Description" : "Spotlight Importer" + }, + { + "DefaultBuildSettings" : { + "EXECUTABLE_PATH" : "$(EXECUTABLE_NAME)", + "JAVA_MAKE_ZIPFILE" : "NO", + "JAVA_ARCHIVE_CLASSES" : "YES", + "EXECUTABLE_PREFIX" : "", + "EXECUTABLE_SUFFIX" : ".jar", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_SUFFIX)" + }, + "Identifier" : "com.apple.package-type.jarfile", + "Type" : "PackageType", + "Name" : "Jar File", + "Description" : "Jar file", + "ProductReference" : { + "FileType" : "archive.jar", + "Name" : "$(EXECUTABLE_NAME)", + "IsLaunchable" : "NO" + } + }, + { + "DefaultBuildSettings" : { + "EXECUTABLE_PATH" : "$(EXECUTABLE_NAME)", + "JAVA_MAKE_ZIPFILE" : "YES", + "JAVA_ARCHIVE_CLASSES" : "YES", + "EXECUTABLE_PREFIX" : "", + "EXECUTABLE_SUFFIX" : ".zip", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_SUFFIX)" + }, + "Identifier" : "com.apple.package-type.zipfile", + "Type" : "PackageType", + "Name" : "Zip File", + "Description" : "Zip file", + "ProductReference" : { + "FileType" : "archive.zip", + "Name" : "$(EXECUTABLE_NAME)", + "IsLaunchable" : "NO" + } + }, + { + "DefaultBuildSettings" : { + "EXECUTABLE_PATH" : "$(EXECUTABLE_NAME)", + "JAVA_ARCHIVE_CLASSES" : "NO", + "EXECUTABLE_PREFIX" : "", + "EXECUTABLE_SUFFIX" : "", + "EXECUTABLE_NAME" : "$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)$(EXECUTABLE_SUFFIX)" + }, + "Identifier" : "com.apple.package-type.javaclassfolder", + "Type" : "PackageType", + "Name" : "Class Folder", + "Description" : "Class folder", + "ProductReference" : { + "FileType" : "wrapper.java-classfolder", + "Name" : "$(EXECUTABLE_NAME)", + "IsLaunchable" : "NO" + } + } +] diff --git a/share/qbs/modules/bundle/MacOSX-Product-Types.xcspec b/share/qbs/modules/bundle/MacOSX-Product-Types.xcspec new file mode 100644 index 000000000..f7766be24 --- /dev/null +++ b/share/qbs/modules/bundle/MacOSX-Product-Types.xcspec @@ -0,0 +1,545 @@ +[ + { + "IconNamePrefix" : "TargetExecutable", + "DefaultBuildProperties" : { + "REZ_EXECUTABLE" : "YES", + "FULL_PRODUCT_NAME" : "$(EXECUTABLE_NAME)", + "LIBRARY_FLAG_NOSPACE" : "YES", + "INSTALL_PATH" : "\/usr\/local\/bin", + "GCC_INLINES_ARE_PRIVATE_EXTERN" : "YES", + "FRAMEWORK_FLAG_PREFIX" : "-framework", + "GCC_DYNAMIC_NO_PIC" : "NO", + "GCC_SYMBOLS_PRIVATE_EXTERN" : "YES", + "CODE_SIGNING_ALLOWED" : "YES", + "STRIP_STYLE" : "all", + "EXECUTABLE_PREFIX" : "", + "EXECUTABLE_SUFFIX" : "", + "LIBRARY_FLAG_PREFIX" : "-l" + }, + "PackageTypes" : [ + "com.apple.package-type.mach-o-executable" + ], + "Type" : "ProductType", + "DefaultTargetName" : "Command-line Tool", + "Name" : "Command-line Tool", + "Identifier" : "com.apple.product-type.tool", + "Description" : "Standalone command-line tool", + "Class" : "PBXToolProductType" + }, + { + "IconNamePrefix" : "TargetExecutable", + "IsJava" : "YES", + "PackageTypes" : [ + "com.apple.package-type.jarfile", + "com.apple.package-type.zipfile", + "com.apple.package-type.javaclassfolder" + ], + "Type" : "ProductType", + "DefaultTargetName" : "Java Command-line Tool", + "Name" : "Java Command-line Tool", + "Identifier" : "com.apple.product-type.tool.java", + "Description" : "Java Command-line tool", + "DefaultBuildProperties" : { + "REZ_EXECUTABLE" : "YES", + "INSTALL_PATH" : "\/usr\/local\/bin", + "FULL_PRODUCT_NAME" : "$(EXECUTABLE_NAME)" + } + }, + { + "IconNamePrefix" : "TargetPlugin", + "DefaultBuildProperties" : { + "DEAD_CODE_STRIPPING" : "NO", + "REZ_EXECUTABLE" : "YES", + "LINK_WITH_STANDARD_LIBRARIES" : "NO", + "FULL_PRODUCT_NAME" : "$(EXECUTABLE_NAME)", + "LIBRARY_FLAG_NOSPACE" : "YES", + "FRAMEWORK_FLAG_PREFIX" : "-framework", + "INSTALL_PATH" : "$(HOME)\/Objects", + "SKIP_INSTALL" : "YES", + "GCC_INLINES_ARE_PRIVATE_EXTERN" : "YES", + "KEEP_PRIVATE_EXTERNS" : "YES", + "EXECUTABLE_EXTENSION" : "o", + "PUBLIC_HEADERS_FOLDER_PATH" : "\/usr\/local\/include", + "MACH_O_TYPE" : "mh_object", + "EXECUTABLE_SUFFIX" : ".$(EXECUTABLE_EXTENSION)", + "LIBRARY_FLAG_PREFIX" : "-l", + "PRIVATE_HEADERS_FOLDER_PATH" : "\/usr\/local\/include", + "STRIP_STYLE" : "debugging" + }, + "PackageTypes" : [ + "com.apple.package-type.mach-o-objfile" + ], + "Type" : "ProductType", + "DefaultTargetName" : "Object File", + "Name" : "Object File", + "Identifier" : "com.apple.product-type.objfile", + "Description" : "Object File", + "Class" : "XCStandaloneExecutableProductType" + }, + { + "IconNamePrefix" : "TargetLibrary", + "DefaultBuildProperties" : { + "LIBRARY_FLAG_PREFIX" : "-l", + "STRIP_STYLE" : "debugging", + "REZ_EXECUTABLE" : "YES", + "FULL_PRODUCT_NAME" : "$(EXECUTABLE_NAME)", + "LD_DYLIB_INSTALL_NAME" : "$(DYLIB_INSTALL_NAME_BASE:standardizepath)\/$(EXECUTABLE_PATH)", + "DYLIB_COMPATIBILITY_VERSION" : "1", + "INSTALL_PATH" : "\/usr\/local\/lib", + "FRAMEWORK_FLAG_PREFIX" : "-framework", + "LIBRARY_FLAG_NOSPACE" : "YES", + "GCC_INLINES_ARE_PRIVATE_EXTERN" : "YES", + "CODE_SIGNING_ALLOWED" : "YES", + "EXECUTABLE_EXTENSION" : "dylib", + "PUBLIC_HEADERS_FOLDER_PATH" : "\/usr\/local\/include", + "DYLIB_INSTALL_NAME_BASE" : "$(INSTALL_PATH)", + "EXECUTABLE_SUFFIX" : ".$(EXECUTABLE_EXTENSION)", + "PRIVATE_HEADERS_FOLDER_PATH" : "\/usr\/local\/include", + "MACH_O_TYPE" : "mh_dylib", + "DYLIB_CURRENT_VERSION" : "1" + }, + "PackageTypes" : [ + "com.apple.package-type.mach-o-dylib" + ], + "Type" : "ProductType", + "DefaultTargetName" : "Dynamic Library", + "Name" : "Dynamic Library", + "Identifier" : "com.apple.product-type.library.dynamic", + "Description" : "Dynamic library", + "Class" : "PBXDynamicLibraryProductType" + }, + { + "IconNamePrefix" : "TargetLibrary", + "DefaultBuildProperties" : { + "STRIP_STYLE" : "debugging", + "REZ_EXECUTABLE" : "YES", + "FULL_PRODUCT_NAME" : "$(EXECUTABLE_NAME)", + "LIBRARY_FLAG_NOSPACE" : "YES", + "FRAMEWORK_FLAG_PREFIX" : "-framework", + "INSTALL_PATH" : "\/usr\/local\/lib", + "SEPARATE_STRIP" : "YES", + "EXECUTABLE_EXTENSION" : "a", + "EXECUTABLE_PREFIX" : "lib", + "PUBLIC_HEADERS_FOLDER_PATH" : "\/usr\/local\/include", + "EXECUTABLE_SUFFIX" : ".$(EXECUTABLE_EXTENSION)", + "LIBRARY_FLAG_PREFIX" : "-l", + "PRIVATE_HEADERS_FOLDER_PATH" : "\/usr\/local\/include", + "MACH_O_TYPE" : "staticlib" + }, + "AlwaysPerformSeparateStrip" : "YES", + "PackageTypes" : [ + "com.apple.package-type.static-library" + ], + "Type" : "ProductType", + "DefaultTargetName" : "Static Library", + "Name" : "Static Library", + "Identifier" : "com.apple.product-type.library.static", + "Description" : "Static library", + "Class" : "PBXStaticLibraryProductType" + }, + { + "IconNamePrefix" : "TargetPlugin", + "IsJava" : "YES", + "PackageTypes" : [ + "com.apple.package-type.jarfile", + "com.apple.package-type.zipfile", + "com.apple.package-type.javaclassfolder" + ], + "Type" : "ProductType", + "DefaultTargetName" : "Java Library", + "Name" : "Java Library", + "Identifier" : "com.apple.product-type.library.java.archive", + "Description" : "Java library packaged as a Jar file, Zip file, or class folder", + "DefaultBuildProperties" : { + "INSTALL_PATH" : "\/usr\/local\/lib", + "FULL_PRODUCT_NAME" : "$(PRODUCT_NAME)" + } + }, + { + "HasInfoPlistStrings" : "YES", + "Description" : "Generic bundle", + "HasInfoPlist" : "YES", + "Name" : "Bundle", + "Class" : "PBXBundleProductType", + "DefaultTargetName" : "Bundle", + "DefaultBuildProperties" : { + "LIBRARY_FLAG_NOSPACE" : "YES", + "WRAPPER_NAME" : "$(WRAPPER_PREFIX)$(PRODUCT_NAME)$(WRAPPER_SUFFIX)", + "FRAMEWORK_FLAG_PREFIX" : "-framework", + "GCC_INLINES_ARE_PRIVATE_EXTERN" : "YES", + "WRAPPER_SUFFIX" : ".$(WRAPPER_EXTENSION)", + "FULL_PRODUCT_NAME" : "$(WRAPPER_NAME)", + "WRAPPER_EXTENSION" : "bundle", + "CODE_SIGNING_ALLOWED" : "YES", + "WRAPPER_PREFIX" : "", + "STRIP_STYLE" : "non-global", + "MACH_O_TYPE" : "mh_bundle", + "LIBRARY_FLAG_PREFIX" : "-l" + }, + "PackageTypes" : [ + "com.apple.package-type.wrapper", + "com.apple.package-type.wrapper.shallow" + ], + "IsWrapper" : "YES", + "Type" : "ProductType", + "Identifier" : "com.apple.product-type.bundle", + "IconNamePrefix" : "TargetPlugin" + }, + { + "PackageTypes" : [ + "com.apple.package-type.wrapper.shallow" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.bundle", + "Name" : "Bundle (Shallow)", + "Identifier" : "com.apple.product-type.bundle.shallow", + "Description" : "Bundle (Shallow)", + "Class" : "PBXBundleProductType" + }, + { + "Description" : "Application", + "Class" : "PBXApplicationProductType", + "Name" : "Application", + "RunpathSearchPathForEmbeddedFrameworks" : "@executable_path\/..\/Frameworks", + "CanEmbedAddressSanitizerLibraries" : "YES", + "ValidateEmbeddedBinaries" : "YES", + "DefaultTargetName" : "Application", + "DefaultBuildProperties" : { + "INSTALL_PATH" : "$(LOCAL_APPS_DIR)", + "WRAPPER_EXTENSION" : "app", + "GCC_DYNAMIC_NO_PIC" : "NO", + "STRIP_STYLE" : "all", + "CODE_SIGNING_ALLOWED" : "YES", + "GCC_INLINES_ARE_PRIVATE_EXTERN" : "YES", + "WRAPPER_SUFFIX" : ".$(WRAPPER_EXTENSION)", + "GCC_SYMBOLS_PRIVATE_EXTERN" : "YES", + "MACH_O_TYPE" : "mh_execute" + }, + "BasedOn" : "com.apple.product-type.bundle", + "PackageTypes" : [ + "com.apple.package-type.wrapper.application" + ], + "Type" : "ProductType", + "Identifier" : "com.apple.product-type.application", + "IconNamePrefix" : "TargetApp" + }, + { + "PackageTypes" : [ + "com.apple.package-type.wrapper.application.shallow" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.application", + "Name" : "Application (Shallow Bundle)", + "Identifier" : "com.apple.product-type.application.shallow", + "Description" : "Application (Shallow Bundle)", + "Class" : "PBXApplicationProductType" + }, + { + "DefaultBuildProperties" : { + "PKGINFO_PATH" : "", + "INFOPLIST_PATH" : "" + }, + "IsJava" : "YES", + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.application", + "Name" : "Java Application", + "Identifier" : "com.apple.product-type.application.java", + "Description" : "Java Application", + "DefaultTargetName" : "Java Application" + }, + { + "IconNamePrefix" : "TargetFramework", + "DefaultTargetName" : "Framework", + "DefaultBuildProperties" : { + "WRAPPER_EXTENSION" : "framework", + "DYLIB_INSTALL_NAME_BASE" : "$(INSTALL_PATH)", + "STRIP_STYLE" : "debugging", + "FRAMEWORK_VERSION" : "A", + "CODE_SIGNING_ALLOWED" : "YES", + "LD_DYLIB_INSTALL_NAME" : "$(DYLIB_INSTALL_NAME_BASE:standardizepath)\/$(EXECUTABLE_PATH)", + "INSTALL_PATH" : "$(LOCAL_LIBRARY_DIR)\/Frameworks", + "WRAPPER_SUFFIX" : ".$(WRAPPER_EXTENSION)", + "MACH_O_TYPE" : "mh_dylib" + }, + "PackageTypes" : [ + "com.apple.package-type.wrapper.framework" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.bundle", + "Name" : "Framework", + "Identifier" : "com.apple.product-type.framework", + "Description" : "Framework", + "Class" : "PBXFrameworkProductType" + }, + { + "PackageTypes" : [ + "com.apple.package-type.wrapper.framework.shallow" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.framework", + "Name" : "Framework (Shallow Bundle)", + "Identifier" : "com.apple.product-type.framework.shallow", + "Description" : "Framework (Shallow Bundle)", + "Class" : "PBXFrameworkProductType" + }, + { + "IconNamePrefix" : "TargetFramework", + "DefaultTargetName" : "Static Framework", + "DefaultBuildProperties" : { + "SEPARATE_STRIP" : "YES", + "WRAPPER_EXTENSION" : "framework", + "DYLIB_INSTALL_NAME_BASE" : "", + "CODE_SIGNING_ALLOWED" : "NO", + "FRAMEWORK_VERSION" : "A", + "LD_DYLIB_INSTALL_NAME" : "", + "GCC_INLINES_ARE_PRIVATE_EXTERN" : "NO", + "INSTALL_PATH" : "$(LOCAL_LIBRARY_DIR)\/Frameworks", + "WRAPPER_SUFFIX" : ".$(WRAPPER_EXTENSION)", + "MACH_O_TYPE" : "staticlib" + }, + "AlwaysPerformSeparateStrip" : "YES", + "PackageTypes" : [ + "com.apple.package-type.wrapper.framework.static" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.framework", + "Name" : "Static Framework", + "Identifier" : "com.apple.product-type.framework.static", + "Description" : "Static Framework", + "Class" : "XCStaticFrameworkProductType" + }, + { + "DefaultTargetName" : "Kernel Extension", + "DefaultBuildProperties" : { + "GCC_ENABLE_BUILTIN_FUNCTIONS" : "NO", + "MODULE_START" : "0", + "PRIVATE_HEADERS_FOLDER_PATH" : "$(KEXT_FRAMEWORK)\/Contents\/PrivateHeaders\/$(KEXT_FAMILY_NAME)", + "WRAPPER_SUFFIX" : ".$(WRAPPER_EXTENSION)", + "MACH_O_TYPE" : "mh_execute", + "GCC_ENABLE_KERNEL_DEVELOPMENT" : "YES", + "MODULE_STOP" : "0", + "GCC_ENABLE_FLOATING_POINT_LIBRARY_CALLS" : "YES", + "GCC_PRODUCT_TYPE_PREPROCESSOR_DEFINITIONS" : "$(inherited) KERNEL KERNEL_PRIVATE DRIVER_PRIVATE APPLE NeXT", + "GCC_DISABLE_STATIC_FUNCTION_INLINING" : "YES", + "ENABLE_APPLE_KEXT_CODE_GENERATION" : "YES", + "CODE_SIGNING_ALLOWED" : "YES", + "GCC_FORCE_CPU_SUBTYPE_ALL" : "YES", + "WRAPPER_EXTENSION" : "kext", + "KERNEL_EXTENSION_HEADER_SEARCH_PATHS" : "$(KERNEL_FRAMEWORK)\/PrivateHeaders $(KERNEL_FRAMEWORK_HEADERS)", + "GCC_INLINES_ARE_PRIVATE_EXTERN" : "NO", + "KEXT_FRAMEWORK_NAME" : "Kernel", + "GCC_NO_COMMON_BLOCKS" : "YES", + "GCC_ENABLE_PASCAL_STRINGS" : "NO", + "PUBLIC_HEADERS_FOLDER_PATH" : "$(KEXT_FRAMEWORK)\/Contents\/Headers\/$(KEXT_FAMILY_NAME)", + "GCC_ENABLE_FUNCTION_INLINING" : "YES", + "KERNEL_FRAMEWORK_HEADERS" : "$(KERNEL_FRAMEWORK)\/Headers", + "KEXT_FAMILY_NAME" : "family", + "KEXT_FRAMEWORK" : "$(SYSTEM_LIBRARY_DIR)\/Frameworks\/$(KEXT_FRAMEWORK_NAME).framework", + "GCC_ENABLE_CPP_EXCEPTIONS" : "NO", + "GCC_ENABLE_CPP_RTTI" : "NO", + "MODULE_NAME" : "com.company.driver.modulename", + "GCC_USE_STANDARD_INCLUDE_SEARCHING" : "NO", + "KERNEL_FRAMEWORK" : "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)\/Frameworks\/Kernel.framework", + "MODULE_VERSION" : "1.0", + "INSTALL_PATH" : "$(DEFAULT_KEXT_INSTALL_PATH)", + "PRODUCT_TYPE_HEADER_SEARCH_PATHS" : "$(inherited) $(KERNEL_EXTENSION_HEADER_SEARCH_PATHS)", + "GCC_CHECK_RETURN_VALUE_OF_OPERATOR_NEW" : "YES", + "STRIP_STYLE" : "debugging" + }, + "PackageTypes" : [ + "com.apple.package-type.wrapper.kernel-extension", + "com.apple.package-type.wrapper.kernel-extension.shallow" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.bundle", + "Name" : "Kernel Extension", + "Identifier" : "com.apple.product-type.kernel-extension", + "Description" : "Kernel extension", + "Class" : "XCKernelExtensionProductType" + }, + { + "DefaultBuildProperties" : { + + }, + "PackageTypes" : [ + "com.apple.package-type.wrapper.kernel-extension.shallow" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.kernel-extension", + "Name" : "Kernel Extension (Shallow)", + "Identifier" : "com.apple.product-type.kernel-extension.shallow", + "Description" : "Kernel extension (shallow)", + "Class" : "XCKernelExtensionProductType" + }, + { + "DefaultTargetName" : "IOKit Kernel Extension", + "DefaultBuildProperties" : { + "CODE_SIGNING_ALLOWED" : "YES" + }, + "PackageTypes" : [ + "com.apple.package-type.wrapper.kernel-extension", + "com.apple.package-type.wrapper.kernel-extension.shallow" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.kernel-extension", + "Name" : "IOKit Kernel Extension", + "Identifier" : "com.apple.product-type.kernel-extension.iokit", + "Description" : "IOKit Kernel extension", + "Class" : "XCKernelExtensionProductType" + }, + { + "DefaultTargetName" : "IOKit Kernel Extension (Shallow)", + "DefaultBuildProperties" : { + + }, + "PackageTypes" : [ + "com.apple.package-type.wrapper.kernel-extension.shallow" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.kernel-extension", + "Name" : "IOKit Kernel Extension (Shallow)", + "Identifier" : "com.apple.product-type.kernel-extension.iokit.shallow", + "Description" : "IOKit Kernel extension (Shallow)", + "Class" : "XCKernelExtensionProductType" + }, + { + "DefaultBuildProperties" : { + "TEST_FRAMEWORK_SEARCH_PATHS" : [ + "$(inherited)", + "$(PLATFORM_DIR)\/Developer\/Library\/Frameworks" + ], + "PRODUCT_SPECIFIC_LDFLAGS" : "-framework XCTest", + "WRAPPER_EXTENSION" : "xctest", + "PRODUCT_TYPE_FRAMEWORK_SEARCH_PATHS" : "$(TEST_FRAMEWORK_SEARCH_PATHS)" + }, + "PackageTypes" : [ + "com.apple.package-type.bundle.unit-test" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.bundle", + "Name" : "Unit Test Bundle", + "Identifier" : "com.apple.product-type.bundle.unit-test", + "Description" : "Unit Test Bundle", + "Class" : "PBXXCTestBundleProductType" + }, + { + "DefaultBuildProperties" : { + "TEST_FRAMEWORK_SEARCH_PATHS" : [ + "$(inherited)", + "$(PLATFORM_DIR)\/Developer\/Library\/Frameworks" + ], + "PRODUCT_SPECIFIC_LDFLAGS" : "-framework XCTest", + "WRAPPER_EXTENSION" : "xctest", + "USES_XCTRUNNER" : "YES", + "PRODUCT_TYPE_FRAMEWORK_SEARCH_PATHS" : "$(TEST_FRAMEWORK_SEARCH_PATHS)" + }, + "PackageTypes" : [ + "com.apple.package-type.bundle.unit-test" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.bundle.unit-test", + "Name" : "UI Testing Bundle", + "Identifier" : "com.apple.product-type.bundle.ui-testing", + "Description" : "UI Testing Bundle", + "Class" : "PBXXCTestBundleProductType" + }, + { + "DefaultBuildProperties" : { + "WRAPPER_EXTENSION" : "octest" + }, + "PackageTypes" : [ + "com.apple.package-type.bundle.ocunit-test" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.bundle", + "Name" : "OCUnit Test Bundle", + "Identifier" : "com.apple.product-type.bundle.ocunit-test", + "Description" : "OCUnit Test Bundle", + "Class" : "PBXBundleProductType" + }, + { + "HasInfoPlistStrings" : "NO", + "PackageTypes" : [ + "com.apple.package-type.in-app-purchase-content" + ], + "HasInfoPlist" : "YES", + "IsWrapper" : "YES", + "Type" : "ProductType", + "DefaultBuildProperties" : { + "FULL_PRODUCT_NAME" : "$(WRAPPER_NAME)" + }, + "Name" : "In-App Purchase Content", + "Identifier" : "com.apple.product-type.in-app-purchase-content", + "Description" : "In-App Purchase Content", + "Class" : "PBXBundleProductType" + }, + { + "IconNamePrefix" : "XPCService", + "DefaultTargetName" : "XPC Service", + "CanEmbedAddressSanitizerLibraries" : "YES", + "DefaultBuildProperties" : { + "MACH_O_TYPE" : "mh_execute", + "WRAPPER_EXTENSION" : "xpc" + }, + "PackageTypes" : [ + "com.apple.package-type.xpc-service" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.bundle", + "Name" : "XPC Service", + "Identifier" : "com.apple.product-type.xpc-service", + "Description" : "XPC Service", + "Class" : "PBXBundleProductType" + }, + { + "IconNamePrefix" : "XPCService", + "DefaultTargetName" : "PlugInKit PlugIn", + "DefaultBuildProperties" : { + "WRAPPER_EXTENSION" : "pluginkit", + "PRODUCT_SPECIFIC_LDFLAGS" : "$(SDKROOT)\/System\/Library\/PrivateFrameworks\/PlugInKit.framework\/PlugInKit" + }, + "PackageTypes" : [ + "com.apple.package-type.pluginkit-plugin" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.xpc-service", + "Name" : "PlugInKit PlugIn", + "Identifier" : "com.apple.product-type.pluginkit-plugin", + "Description" : "PlugInKit PlugIn", + "Class" : "PBXBundleProductType" + }, + { + "IconNamePrefix" : "AppExtension", + "DefaultTargetName" : "App Extension", + "DefaultBuildProperties" : { + "APPLICATION_EXTENSION_API_ONLY" : "YES", + "PRODUCT_SPECIFIC_LDFLAGS" : "-e _NSExtensionMain", + "WRAPPER_EXTENSION" : "appex", + "CODE_SIGNING_ALLOWED" : "YES" + }, + "PackageTypes" : [ + "com.apple.package-type.app-extension" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.pluginkit-plugin", + "Name" : "App Extension", + "Identifier" : "com.apple.product-type.app-extension", + "Description" : "App Extension", + "Class" : "PBXBundleProductType" + }, + { + "DefaultTargetName" : "Spotlight", + "DefaultBuildProperties" : { + "CODE_SIGNING_ALLOWED" : "YES" + }, + "PackageTypes" : [ + "com.apple.package-type.spotlight-importer" + ], + "Type" : "ProductType", + "BasedOn" : "com.apple.product-type.bundle", + "Name" : "Spotlight Importer", + "Identifier" : "com.apple.product-type.spotlight-importer", + "Description" : "Spotlight Importer", + "Class" : "PBXBundleProductType" + } +] diff --git a/share/qbs/modules/bundle/bundle.js b/share/qbs/modules/bundle/bundle.js new file mode 100644 index 000000000..d6ab4b56a --- /dev/null +++ b/share/qbs/modules/bundle/bundle.js @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of the Qt Build Suite. +** +** 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 DarwinTools = loadExtension("qbs.DarwinTools"); +var Process = loadExtension("qbs.Process"); + +// HACK: Workaround until the PropertyList extension is supported cross-platform +var PropertyList2 = (function () { + function PropertyList2() { + } + PropertyList2.prototype.readFromFile = function (filePath) { + var str; + var process = new Process(); + try { + if (process.exec("plutil", ["-convert", "json", "-o", "-", filePath], false) === 0) { + str = process.readStdOut(); + } else { + var tf = new TextFile(filePath); + try { + str = tf.readAll(); + } finally { + tf.close(); + } + } + } finally { + process.close(); + } + + if (str) + this.obj = JSON.parse(str); + }; + PropertyList2.prototype.toObject = function () { + return this.obj; + }; + PropertyList2.prototype.clear = function () { + }; + return PropertyList2; +}()); + +// Order is significant due to productTypeIdentifier() search path +var _productTypeIdentifiers = { + "inapppurchase": "com.apple.product-type.in-app-purchase-content", + "applicationextension": "com.apple.product-type.app-extension", + "xpcservice": "com.apple.product-type.xpc-service", + "application": "com.apple.product-type.application", + "dynamiclibrary": "com.apple.product-type.framework", + "loadablemodule": "com.apple.product-type.bundle", + "staticlibrary": "com.apple.product-type.framework.static", + "kernelmodule": "com.apple.product-type.kernel-extension" +}; + +function productTypeIdentifier(productType) { + for (var k in _productTypeIdentifiers) { + if (productType.contains(k)) + return _productTypeIdentifiers[k]; + } + return "com.apple.package-type.wrapper"; +} + +var XcodeBuildSpecsReader = (function () { + function XcodeBuildSpecsReader(specsPath, separator, additionalSettings, useShallowBundles) { + this._additionalSettings = additionalSettings; + this._useShallowBundles = useShallowBundles; + var i; + var plist = new PropertyList2(); + var plist2 = new PropertyList2(); + try { + plist.readFromFile(specsPath + ["/MacOSX", "Package", "Types.xcspec"].join(separator)); + plist2.readFromFile(specsPath + ["/MacOSX", "Product", "Types.xcspec"].join(separator)); + this._packageTypes = plist.toObject(); + this._productTypes = plist2.toObject(); + this._types = {}; + for (i = 0; i < this._packageTypes.length; ++i) + this._types[this._packageTypes[i]["Identifier"]] = this._packageTypes[i]; + for (i = 0; i < this._productTypes.length; ++i) + this._types[this._productTypes[i]["Identifier"]] = this._productTypes[i]; + } finally { + plist.clear(); + plist2.clear(); + } + } + XcodeBuildSpecsReader.prototype.settings = function (typeIdentifier, recursive, skipPackageTypes) { + // Silently use shallow bundles when preferred since it seems to be some sort of automatic + // shadowing mechanism. For example, this matches Xcode behavior where static frameworks + // are shallow even though no such product specification exists, and also seems to match + // other behavior i.e. where productType in pbxproj files is never explicitly shallow. + if (this._useShallowBundles && this._types[typeIdentifier + ".shallow"] && !skipPackageTypes) + typeIdentifier += ".shallow"; + + var typesObject = this._types[typeIdentifier]; + if (typesObject) { + var buildProperties = {}; + + if (recursive) { + // Get all the settings for the product's package type + if (!skipPackageTypes && typesObject["PackageTypes"]) { + for (var k = 0; k < typesObject["PackageTypes"].length; ++k) { + var props = this.settings(typesObject["PackageTypes"][k], recursive, true); + for (var y in props) { + if (props.hasOwnProperty(y)) + buildProperties[y] = props[y]; + } + break; + } + } + + // Get all the settings for the product's inherited product type + if (typesObject["BasedOn"]) { + // We'll only do the auto shallow substitution for wrapper package types... + // this ensures that in-app purchase content bundles are non-shallow on both + // OS X and iOS, for example (which matches Xcode behavior) + var isWrapper = false; + if (typesObject["ProductReference"]) { + var fileType = typesObject["ProductReference"]["FileType"]; + if (fileType) + isWrapper = fileType.startsWith("wrapper."); + } + + // Prevent recursion loop if this spec's base plus .shallow would be the same + // as the current spec's identifier + var baseIdentifier = typesObject["BasedOn"]; + if (this._useShallowBundles && isWrapper + && this._types[baseIdentifier + ".shallow"] + && typeIdentifier !== baseIdentifier + ".shallow") + baseIdentifier += ".shallow"; + + props = this.settings(baseIdentifier, recursive, true); + for (y in props) { + if (props.hasOwnProperty(y)) + buildProperties[y] = props[y]; + } + } + } + + + if (typesObject["Type"] === "PackageType") { + props = typesObject["DefaultBuildSettings"]; + for (y in props) { + if (props.hasOwnProperty(y)) + buildProperties[y] = props[y]; + } + } + + if (typesObject["Type"] === "ProductType") { + props = typesObject["DefaultBuildProperties"]; + for (y in props) { + if (props.hasOwnProperty(y)) + buildProperties[y] = props[y]; + } + } + + return buildProperties; + } + }; + XcodeBuildSpecsReader.prototype.setting = function (typeIdentifier, settingName) { + var obj = this.settings(typeIdentifier, false); + if (obj) { + return obj[settingName]; + } + }; + XcodeBuildSpecsReader.prototype.expandedSettings = function (typeIdentifier) { + var obj = this.settings(typeIdentifier, true); + if (obj) { + for (var k in obj) + obj[k] = this.expandedSetting(typeIdentifier, k); + return obj; + } + }; + XcodeBuildSpecsReader.prototype.expandedSetting = function (typeIdentifier, settingName) { + var obj = this.settings(typeIdentifier, true); + if (obj) { + for (var x in this._additionalSettings) { + var additionalSetting = this._additionalSettings[x]; + if (additionalSetting !== undefined) + obj[x] = additionalSetting; + } + var setting = obj[settingName]; + var original; + while (original !== setting) { + original = setting; + setting = DarwinTools.expandPlistEnvironmentVariables({ key: setting }, obj, true)["key"]; + } + return setting; + } + }; + return XcodeBuildSpecsReader; +}()); diff --git a/share/qbs/modules/bundle/update-specs.sh b/share/qbs/modules/bundle/update-specs.sh new file mode 100755 index 000000000..869fb011f --- /dev/null +++ b/share/qbs/modules/bundle/update-specs.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# Update build specs from Xcode - this script should be run when new Xcode releases are made. +specs_dir="$(xcrun --sdk macosx --show-sdk-platform-path)/Developer/Library/Xcode/Specifications" +spec_files=("MacOSX Package Types.xcspec" "MacOSX Product Types.xcspec") +for spec_file in "${spec_files[@]}" ; do + printf "%s\n" "$(plutil -convert json -r -o - "$specs_dir/$spec_file")" > "${spec_file// /-}" +done +xcode_version="$(/usr/libexec/PlistBuddy -c 'Print CFBundleShortVersionString' \ + "$(xcode-select --print-path)/../Info.plist")" +echo "Updated build specs from Xcode $xcode_version" diff --git a/share/qbs/modules/cli/mono.qbs b/share/qbs/modules/cli/mono.qbs index 9f19f3a0a..6ce1ea3e6 100644 --- a/share/qbs/modules/cli/mono.qbs +++ b/share/qbs/modules/cli/mono.qbs @@ -1,7 +1,7 @@ import qbs CLIModule { - condition: qbs.toolchain.contains("mono") + condition: qbs.toolchain && qbs.toolchain.contains("mono") debugInfoSuffix: ".mdb" csharpCompilerName: "mcs" diff --git a/share/qbs/modules/cli/windows-dotnet.qbs b/share/qbs/modules/cli/windows-dotnet.qbs index a51eb4c40..0ec457bdf 100755 --- a/share/qbs/modules/cli/windows-dotnet.qbs +++ b/share/qbs/modules/cli/windows-dotnet.qbs @@ -2,7 +2,7 @@ import qbs import qbs.Utilities CLIModule { - condition: qbs.toolchain.contains("dotnet") + condition: qbs.toolchain && qbs.toolchain.contains("dotnet") debugInfoSuffix: ".pdb" csharpCompilerName: "csc" diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs index df10fd1dc..18ae4df1d 100644 --- a/share/qbs/modules/cpp/CppModule.qbs +++ b/share/qbs/modules/cpp/CppModule.qbs @@ -168,6 +168,7 @@ Module { property string loadableModuleSuffix property string executableSuffix property string debugInfoSuffix + property string debugInfoBundleSuffix property bool createSymlinks: true property stringList dynamicLibraries // list of names, will be linked with -lname property stringList staticLibraries // list of static library files @@ -271,6 +272,10 @@ Module { description: "version of the C++ standard library to use" } + property bool enableExceptions + property string exceptionHandlingModel: "default" + property bool enableRtti + // Platform properties. Those are intended to be set by the toolchain setup // and are prepended to the corresponding user properties. property stringList platformAssemblerFlags diff --git a/share/qbs/modules/cpp/DarwinGCC.qbs b/share/qbs/modules/cpp/DarwinGCC.qbs index 906da4bfe..a147de935 100644 --- a/share/qbs/modules/cpp/DarwinGCC.qbs +++ b/share/qbs/modules/cpp/DarwinGCC.qbs @@ -47,7 +47,8 @@ UnixGCC { loadableModuleSuffix: ".bundle" dynamicLibrarySuffix: ".dylib" separateDebugInformation: true - debugInfoSuffix: ".dSYM" + debugInfoBundleSuffix: ".dSYM" + debugInfoSuffix: ".dwarf" toolchainInstallPath: xcode.present ? FileInfo.joinPaths(xcode.toolchainPath, "usr", "bin") : base @@ -73,14 +74,16 @@ UnixGCC { dict["LSMinimumSystemVersion"] = minimumOsxVersion; } - if (qbs.targetOS.contains("ios") || qbs.targetOS.contains("tvos")) { + if (qbs.targetOS.containsAny(["ios", "tvos"])) { dict["LSRequiresIPhoneOS"] = true; - if (qbs.targetOS.contains("ios") && !qbs.targetOS.contains("ios-simulator")) - dict["UIRequiredDeviceCapabilities"] = ["armv7"]; + if (xcode.platformType === "device") { + if (qbs.targetOS.contains("ios")) + dict["UIRequiredDeviceCapabilities"] = ["armv7"]; - if (qbs.targetOS.contains("tvos") && !qbs.targetOS.contains("tvos-simulator")) - dict["UIRequiredDeviceCapabilities"] = ["arm64"]; + if (qbs.targetOS.contains("tvos")) + dict["UIRequiredDeviceCapabilities"] = ["arm64"]; + } } if (xcode.present) { @@ -88,7 +91,7 @@ UnixGCC { if (qbs.targetOS.contains("ios")) dict["UIDeviceFamily"] = targetDevices; - if (qbs.targetOS.contains("ios") || qbs.targetOS.contains("watchos")) { + if (qbs.targetOS.containsAny(["ios", "watchos"])) { var orientations = [ "UIInterfaceOrientationPortrait", "UIInterfaceOrientationPortraitUpsideDown", diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs index 9ffe1505c..6f54fe924 100644 --- a/share/qbs/modules/cpp/GenericGCC.qbs +++ b/share/qbs/modules/cpp/GenericGCC.qbs @@ -107,8 +107,8 @@ CppModule { assemblerPath: toolchainPathPrefix + assemblerName compilerPath: toolchainPathPrefix + compilerName linkerPath: toolchainPathPrefix + linkerName - property path archiverPath: { return toolchainPathPrefix + archiverName } - property path nmPath: { return toolchainPathPrefix + nmName } + property string archiverPath: toolchainPathPrefix + archiverName + property string nmPath: toolchainPathPrefix + nmName property string objcopyPath: toolchainPathPrefix + objcopyName property string stripPath: toolchainPathPrefix + stripName property string dsymutilPath: toolchainPathPrefix + dsymutilName @@ -122,10 +122,15 @@ CppModule { if (product.version === undefined) return undefined; - if (typeof product.version !== "string" - || !product.version.match(/^([0-9]+\.){0,3}[0-9]+$/)) + if (!Gcc.isNumericProductVersion(product.version)) { + // Dynamic library version numbers like "A" or "B" are common on Apple platforms, so + // don't restrict the product version to a componentized version number here. + if (qbs.targetOS.contains("darwin")) + return product.version; + throw("product.version must be a string in the format x[.y[.z[.w]] " - + "where each component is an integer"); + + "where each component is an integer"); + } var maxVersionParts = 3; var versionParts = product.version.split('.').slice(0, maxVersionParts); @@ -137,6 +142,26 @@ CppModule { return versionParts.join('.'); } + exceptionHandlingModel: { + if (qbs.toolchain.contains("mingw")) { + // https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html claims + // __USING_SJLJ_EXCEPTIONS__ is defined as 1 when using SJLJ exceptions, but there don't + // seem to be defines for the other models, so use the presence of the DLLs for now. + var prefix = toolchainInstallPath; + if (!qbs.hostOS.contains("windows")) + prefix = FileInfo.joinPaths(toolchainInstallPath, "..", "lib", "gcc", + toolchainPrefix, + [compilerVersionMajor, compilerVersionMinor].join(".")); + var models = ["seh", "sjlj", "dw2"]; + for (var i = 0; i < models.length; ++i) { + if (File.exists(FileInfo.joinPaths(prefix, "libgcc_s_" + models[i] + "-1.dll"))) { + return models[i]; + } + } + } + return base; + } + validate: { var validator = new ModUtils.PropertyValidator("cpp"); validator.setRequiredProperty("architecture", architecture, @@ -175,7 +200,8 @@ CppModule { var artifacts = [lib, libCopy]; if (ModUtils.moduleProperty(product, "shouldCreateSymlinks") && !product.moduleProperty("bundle", "isBundle")) { - for (var i = 0; i < 3; ++i) { + var maxVersionParts = Gcc.isNumericProductVersion(product.version) ? 3 : 1; + for (var i = 0; i < maxVersionParts; ++i) { var symlink = { filePath: product.destinationDirectory + "/" + PathTools.dynamicLibraryFileName(product, undefined, i), @@ -186,23 +212,7 @@ CppModule { artifacts.push(symlink); } } - if (ModUtils.moduleProperty(product, "separateDebugInformation")) { - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoFilePath(product)), - fileTags: ["debuginfo"] - }); - if (PathTools.debugInfoIsBundle(product)) { - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoBundlePath(product)), - fileTags: ["debuginfo_bundle"] - }); - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoPlistFilePath(product)), - fileTags: ["debuginfo_plist"] - }); - } - } - return artifacts; + return artifacts.concat(Gcc.debugInfoArtifacts(product)); } prepare: { @@ -271,24 +281,7 @@ CppModule { PathTools.loadableModuleFilePath(product)), fileTags: ["loadablemodule"] } - var artifacts = [app]; - if (ModUtils.moduleProperty(product, "separateDebugInformation")) { - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoFilePath(product)), - fileTags: ["debuginfo"] - }); - if (PathTools.debugInfoIsBundle(product)) { - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoBundlePath(product)), - fileTags: ["debuginfo_bundle"] - }); - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoPlistFilePath(product)), - fileTags: ["debuginfo_plist"] - }); - } - } - return artifacts; + return [app].concat(Gcc.debugInfoArtifacts(product)); } prepare: { @@ -316,24 +309,7 @@ CppModule { PathTools.applicationFilePath(product)), fileTags: ["application"] } - var artifacts = [app]; - if (ModUtils.moduleProperty(product, "separateDebugInformation")) { - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoFilePath(product)), - fileTags: ["debuginfo"] - }); - if (PathTools.debugInfoIsBundle(product)) { - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoBundlePath(product)), - fileTags: ["debuginfo_bundle"] - }); - artifacts.push({ - filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoPlistFilePath(product)), - fileTags: ["debuginfo_plist"] - }); - } - } - return artifacts; + return [app].concat(Gcc.debugInfoArtifacts(product)); } prepare: { diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js index 0c65dc060..d7842c4e0 100644 --- a/share/qbs/modules/cpp/gcc.js +++ b/share/qbs/modules/cpp/gcc.js @@ -82,7 +82,7 @@ function linkerFlags(product, inputs, output) { if (isDarwin) { var internalVersion = product.moduleProperty("cpp", "internalVersion"); - if (internalVersion) + if (internalVersion && isNumericProductVersion(internalVersion)) args.push("-current_version", internalVersion); args = args.concat(escapeLinkerFlags(product, [ @@ -98,7 +98,7 @@ function linkerFlags(product, inputs, output) { if (output.fileTags.contains("loadablemodule")) args.push(isDarwin ? "-bundle" : "-shared"); - if (output.fileTags.contains("dynamiclibrary") || output.fileTags.contains("loadablemodule")) { + if (output.fileTags.containsAny(["dynamiclibrary", "loadablemodule"])) { if (isDarwin) args = args.concat(escapeLinkerFlags(product, ["-headerpad_max_install_names"])); else @@ -420,6 +420,23 @@ function compilerFlags(product, input, output) { args.push(useArc ? "-fobjc-arc" : "-fno-objc-arc"); } + var enableExceptions = ModUtils.moduleProperty(input, "enableExceptions"); + if (enableExceptions !== undefined) { + if (tag === "cpp" || tag === "objcpp") + args.push(enableExceptions ? "-fexceptions" : "-fno-exceptions"); + + if (tag === "objc" || tag === "objcpp") { + args.push(enableExceptions ? "-fobjc-exceptions" : "-fno-objc-exceptions"); + if (useArc !== undefined) + args.push(useArc ? "-fobjc-arc-exceptions" : "-fno-objc-arc-exceptions"); + } + } + + var enableRtti = ModUtils.moduleProperty(input, "enableRtti"); + if (enableRtti !== undefined && (tag === "cpp" || tag === "objcpp")) { + args.push(enableRtti ? "-frtti" : "-fno-rtti"); + } + var visibility = ModUtils.moduleProperty(input, 'visibility'); if (!product.type.contains('staticlibrary') && !product.moduleProperty("qbs", "toolchain").contains("mingw")) { @@ -704,24 +721,25 @@ function prepareLinker(project, product, inputs, outputs, input, output) { ])); cmd.description = "generating dSYM for " + product.name; commands.push(cmd); + + cmd = new Command(ModUtils.moduleProperty(product, "stripPath"), + ["-S", primaryOutput.filePath]); + cmd.silent = true; + commands.push(cmd); } else { - cmd = new Command(ModUtils.moduleProperty(product, "objcopyPath"), [ - "--only-keep-debug", primaryOutput.filePath, - outputs.debuginfo[0].filePath - ]); + var objcopy = ModUtils.moduleProperty(product, "objcopyPath"); + + cmd = new Command(objcopy, ["--only-keep-debug", primaryOutput.filePath, + outputs.debuginfo[0].filePath]); cmd.silent = true; commands.push(cmd); - cmd = new Command(ModUtils.moduleProperty(product, "stripPath"), [ - "--strip-debug", primaryOutput.filePath - ]); + cmd = new Command(objcopy, ["--strip-debug", primaryOutput.filePath]); cmd.silent = true; commands.push(cmd); - cmd = new Command(ModUtils.moduleProperty(product, "objcopyPath"), [ - "--add-gnu-debuglink=" + outputs.debuginfo[0].filePath, - primaryOutput.filePath - ]); + cmd = new Command(objcopy, ["--add-gnu-debuglink=" + outputs.debuginfo[0].filePath, + primaryOutput.filePath]); cmd.silent = true; commands.push(cmd); } @@ -856,3 +874,28 @@ function concatLibsFromArtifacts(libs, artifacts) deps.reverse(); return concatLibs(deps, libs); } + +function debugInfoArtifacts(product) { + var artifacts = []; + if (product.moduleProperty("cpp", "separateDebugInformation")) { + artifacts.push({ + filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoFilePath(product)), + fileTags: ["debuginfo"] + }); + if (PathTools.debugInfoIsBundle(product)) { + artifacts.push({ + filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoBundlePath(product)), + fileTags: ["debuginfo_bundle"] + }); + artifacts.push({ + filePath: FileInfo.joinPaths(product.destinationDirectory, PathTools.debugInfoPlistFilePath(product)), + fileTags: ["debuginfo_plist"] + }); + } + } + return artifacts; +} + +function isNumericProductVersion(version) { + return version && version.match(/^([0-9]+\.){0,3}[0-9]+$/); +} diff --git a/share/qbs/modules/cpp/genericunix-gcc.qbs b/share/qbs/modules/cpp/genericunix-gcc.qbs index fa330abed..7c8869d63 100644 --- a/share/qbs/modules/cpp/genericunix-gcc.qbs +++ b/share/qbs/modules/cpp/genericunix-gcc.qbs @@ -31,6 +31,6 @@ import qbs 1.0 UnixGCC { - condition: !qbs.targetOS.contains('darwin') && !qbs.targetOS.contains('linux') && + condition: qbs.targetOS && !qbs.targetOS.containsAny(['darwin', 'linux']) && qbs.toolchain && qbs.toolchain.contains('gcc') && !qbs.toolchain.contains('mingw') } diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js index aff810c27..c671f8abe 100644 --- a/share/qbs/modules/cpp/msvc.js +++ b/share/qbs/modules/cpp/msvc.js @@ -47,8 +47,27 @@ function prepareCompiler(project, product, inputs, outputs, input, output) { // Whether we're compiling a precompiled header or normal source file var pchOutput = outputs[tag + "_pch"] ? outputs[tag + "_pch"][0] : undefined; - // enable unwind semantics - args.push("/EHsc") + var enableExceptions = ModUtils.moduleProperty(input, "enableExceptions"); + if (enableExceptions) { + var ehModel = ModUtils.moduleProperty(input, "exceptionHandlingModel"); + switch (ehModel) { + case "default": + args.push("/EHsc"); // "Yes" in VS + break; + case "seh": + args.push("/EHa"); // "Yes with SEH exceptions" in VS + break; + case "externc": + args.push("/EHs"); // "Yes with Extern C functions" in VS + break; + } + } + + var enableRtti = ModUtils.moduleProperty(input, "enableRtti"); + if (enableRtti !== undefined) { + args.push(enableRtti ? "/GR" : "/GR-"); + } + // optimization: if (optimization === 'small') args.push('/Os') diff --git a/share/qbs/modules/ib/ib.js b/share/qbs/modules/ib/ib.js index 198f8fe88..91048752b 100644 --- a/share/qbs/modules/ib/ib.js +++ b/share/qbs/modules/ib/ib.js @@ -67,7 +67,9 @@ function ibtooldArguments(product, inputs, outputs, overrideOutput) { } if (inputs.assetcatalog) { - args.push("--platform", DarwinTools.applePlatformName(product.moduleProperty("qbs", "targetOS"))); + args.push("--platform", DarwinTools.applePlatformName( + product.moduleProperty("qbs", "targetOS"), + product.moduleProperty("xcode", "platformType"))); var appIconName = ModUtils.modulePropertyFromArtifacts(product, inputs.assetcatalog, product.moduleName, "appIconName"); if (appIconName) diff --git a/share/qbs/modules/java/utils.js b/share/qbs/modules/java/utils.js index c1104a138..9477125f0 100644 --- a/share/qbs/modules/java/utils.js +++ b/share/qbs/modules/java/utils.js @@ -119,7 +119,8 @@ function findJdkPath(hostOS, arch, environmentPaths, searchPaths) { return FileInfo.joinPaths(searchPaths[i], "bin", tool); } - if (requiredTools.map(fullToolPath).every(File.exists)) { + if (requiredTools.map(function(p) { return fullToolPath(p); }) + .every(function(p) { return File.exists(p); })) { return searchPaths[i]; } } diff --git a/share/qbs/modules/nodejs/NodeJS.qbs b/share/qbs/modules/nodejs/NodeJS.qbs index f411e06da..1c04b09c2 100644 --- a/share/qbs/modules/nodejs/NodeJS.qbs +++ b/share/qbs/modules/nodejs/NodeJS.qbs @@ -56,6 +56,8 @@ Module { description: "file whose corresponding output will be executed when running the Node.js app" } + Group { name: "Application file"; files: nodejs.applicationFile ? [nodejs.applicationFile] : [] } + property path toolchainInstallPath: { if (nodejs.path && npm.path && nodejs.path !== npm.path) throw("node and npm binaries do not belong to the same installation (" diff --git a/share/qbs/modules/typescript/TypeScriptModule.qbs b/share/qbs/modules/typescript/TypeScriptModule.qbs index 5173fb916..fbcd4fcf0 100644 --- a/share/qbs/modules/typescript/TypeScriptModule.qbs +++ b/share/qbs/modules/typescript/TypeScriptModule.qbs @@ -47,6 +47,7 @@ Module { Probes.TypeScriptProbe { id: tsc + interpreterPath: FileInfo.path(nodejs.interpreterFilePath) packageManagerBinPath: nodejs.packageManagerBinPath packageManagerRootPath: nodejs.packageManagerRootPath } @@ -78,7 +79,7 @@ Module { PropertyOptions { name: "targetVersion" description: "ECMAScript target version" - allowedValues: ["ES3", "ES5"] + allowedValues: ["ES3", "ES5", "ES2015"] } property string moduleLoader @@ -120,6 +121,22 @@ Module { } validate: { + var interpreterMessage = "TypeScript requires the Node.js interpreter to be called 'node'."; + if (File.exists("/etc/debian_version")) { + interpreterMessage += " Did you forget to install the nodejs-legacy package? " + + "See https://lists.debian.org/debian-devel-announce/2012/07/msg00002.html " + + "for more information."; + } + + var preValidator = new ModUtils.PropertyValidator("nodejs"); + preValidator.addCustomValidator("interpreterFileName", nodejs.interpreterFileName, function (value) { + return value === "node" + (qbs.hostOS.contains("windows") ? ".exe" : ""); + }, interpreterMessage); + preValidator.addCustomValidator("interpreterFilePath", nodejs.interpreterFilePath, function (value) { + return value.endsWith(nodejs.interpreterFileName); + }, interpreterMessage); + preValidator.validate(); + var validator = new ModUtils.PropertyValidator("typescript"); validator.setRequiredProperty("toolchainInstallPath", toolchainInstallPath); validator.setRequiredProperty("compilerName", compilerName); @@ -158,7 +175,8 @@ Module { name: "io.qt.qbs.internal.typescript-helper" files: [ FileInfo.joinPaths(path, "qbs-tsc-scan", "qbs-tsc-scan.ts"), - FileInfo.joinPaths(typescript.toolchainLibInstallPath, "typescript.d.ts") + FileInfo.joinPaths(typescript.toolchainLibInstallPath, "typescript.d.ts"), + FileInfo.joinPaths(typescript.toolchainLibInstallPath, "..", "package.json") ] fileTags: ["typescript.typescript-internal"] } @@ -173,6 +191,23 @@ Module { return []; return [{ filePath: FileInfo.joinPaths(product.buildDirectory, + ".io.qt.qbs.internal.typescript", "qbs-tsc-scan.ts"), + fileTags: ["typescript.typescript-internal.copy"] + }, + { + filePath: FileInfo.joinPaths(product.buildDirectory, + ".io.qt.qbs.internal.typescript", + "node_modules", "typescript", "lib", "typescript.d.ts"), + fileTags: ["typescript.typescript-internal.copy"] + }, + { + filePath: FileInfo.joinPaths(product.buildDirectory, + ".io.qt.qbs.internal.typescript", + "node_modules", "typescript", "package.json"), + fileTags: ["typescript.typescript-internal.copy"] + }, + { + filePath: FileInfo.joinPaths(product.buildDirectory, ".io.qt.qbs.internal.typescript", "qbs-tsc-scan.js"), fileTags: ["typescript.compiled_typescript-internal"] }]; @@ -183,11 +218,30 @@ Module { return input.filePath; }); + var outputPaths = outputs["typescript.typescript-internal.copy"].map(function (output) { + return output.filePath; + }); + + var sortFunc = function (a, b) { + return FileInfo.fileName(a).localeCompare(FileInfo.fileName(b)); + }; + + var jcmd = new JavaScriptCommand(); + jcmd.silent = true; + jcmd.inputPaths = inputPaths.sort(sortFunc); + jcmd.outputPaths = outputPaths.sort(sortFunc); + jcmd.sourceCode = function() { + for (var i = 0; i < inputPaths.length; ++i) + File.copy(inputPaths[i], outputPaths[i]); + }; + + var outDir = FileInfo.path( + outputs["typescript.compiled_typescript-internal"][0].filePath); var args = ["--module", "commonjs", - "--outDir", FileInfo.path(output.filePath)].concat(inputPaths); + "--outDir", outDir].concat(outputPaths.filter(function (f) { return !f.endsWith(".json"); })); var cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), args); cmd.silent = true; - return [cmd]; + return [jcmd, cmd]; } } diff --git a/share/qbs/modules/typescript/typescript.js b/share/qbs/modules/typescript/typescript.js index 96bd6ec69..d7b7db9b7 100644 --- a/share/qbs/modules/typescript/typescript.js +++ b/share/qbs/modules/typescript/typescript.js @@ -92,7 +92,7 @@ function tscArguments(product, inputs) { args.push("--outDir", product.buildDirectory); if (ModUtils.moduleProperty(product, "singleFile")) { - args.push("--out", + args.push(outOption(product), FileInfo.joinPaths(product.destinationDirectory, product.targetName) + ".js"); } @@ -129,7 +129,10 @@ function outputArtifacts(product, inputs) { var process; try { process = new Process(); - process.setEnv("NODE_PATH", ModUtils.moduleProperty(product, "toolchainInstallPath")); + process.setEnv("NODE_PATH", [ + ModUtils.moduleProperty(product, "toolchainInstallPath"), + product.moduleProperty("nodejs", "packageManagerRootPath") + ].join(product.moduleProperty("qbs", "pathListSeparator"))); process.exec(product.moduleProperty("nodejs", "interpreterFilePath"), [FileInfo.joinPaths(product.buildDirectory, ".io.qt.qbs.internal.typescript", @@ -247,6 +250,17 @@ function legacyOutputArtifacts(product, inputs) { return artifacts; } +function outOption(product) { + var compilerVersionMajor = ModUtils.moduleProperty(product, "versionMajor"); + if (compilerVersionMajor === 1) { + if (ModUtils.moduleProperty(product, "versionMinor") < 6) { + return "--out"; + } + } + + return "--outFile"; +} + function supportsModernFeatures(product) { var compilerVersionMajor = ModUtils.moduleProperty(product, "versionMajor"); if (compilerVersionMajor === 1) { diff --git a/share/qbs/modules/xcode/xcode.js b/share/qbs/modules/xcode/xcode.js index afe3babfa..e170b154a 100644 --- a/share/qbs/modules/xcode/xcode.js +++ b/share/qbs/modules/xcode/xcode.js @@ -33,27 +33,6 @@ var FileInfo = loadExtension("qbs.FileInfo"); var Process = loadExtension("qbs.Process"); var PropertyList = loadExtension("qbs.PropertyList"); -function applePlatformDirectoryName(targetOSList, version, throwOnError) { - if (!version) - version = ""; - if (targetOSList.contains("ios-simulator")) - return "iPhoneSimulator" + version; - else if (targetOSList.contains("ios")) - return "iPhoneOS" + version; - else if (targetOSList.contains("osx")) - return "MacOSX" + version; - else if (targetOSList.contains("tvos-simulator")) - return "AppleTVSimulator" + version; - else if (targetOSList.contains("tvos")) - return "AppleTVOS" + version; - else if (targetOSList.contains("watchos-simulator")) - return "WatchSimulator" + version; - else if (targetOSList.contains("watchos")) - return "WatchOS" + version; - if (throwOnError || throwOnError === undefined) - throw("No Apple platform corresponds to target OS list: " + targetOSList); -} - function sdkInfoList(sdksPath) { var sdkInfo = []; var sdks = File.directoryEntries(sdksPath, File.Dirs | File.NoDotAndDotDot); diff --git a/share/qbs/modules/xcode/xcode.qbs b/share/qbs/modules/xcode/xcode.qbs index f9b717867..22b39cdb8 100644 --- a/share/qbs/modules/xcode/xcode.qbs +++ b/share/qbs/modules/xcode/xcode.qbs @@ -10,12 +10,19 @@ import 'xcode.js' as Utils Module { condition: qbs.hostOS.contains("darwin") && qbs.targetOS.contains("darwin") && - qbs.toolchain.contains("xcode") + qbs.toolchain && qbs.toolchain.contains("xcode") property path developerPath: "/Applications/Xcode.app/Contents/Developer" property string sdk: DarwinTools.applePlatformName(qbs.targetOS) property stringList targetDevices: DarwinTools.targetDevices(qbs.targetOS) + property string platformType: { + if (qbs.targetOS.containsAny(["ios-simulator", "tvos-simulator", "watchos-simulator"])) + return "simulator"; + if (qbs.targetOS.containsAny(["ios", "tvos", "watchos"])) + return "device"; + } + readonly property string sdkName: { if (_sdkSettings) { return _sdkSettings["CanonicalName"]; @@ -77,12 +84,12 @@ Module { readonly property path toolchainPath: FileInfo.joinPaths(toolchainsPath, "XcodeDefault" + ".xctoolchain") readonly property path platformPath: FileInfo.joinPaths(platformsPath, - Utils.applePlatformDirectoryName( - qbs.targetOS) + DarwinTools.applePlatformDirectoryName( + qbs.targetOS, platformType) + ".platform") readonly property path sdkPath: FileInfo.joinPaths(sdksPath, - Utils.applePlatformDirectoryName( - qbs.targetOS, sdkVersion) + DarwinTools.applePlatformDirectoryName( + qbs.targetOS, platformType, sdkVersion) + ".sdk") // private properties @@ -153,8 +160,8 @@ Module { validator.setRequiredProperty("sdkPath", sdkPath); validator.addVersionValidator("sdkVersion", sdkVersion, 2, 2); validator.addCustomValidator("sdkName", sdkName, function (value) { - return value === Utils.applePlatformDirectoryName( - qbs.targetOS, sdkVersion, false).toLowerCase(); + return value === DarwinTools.applePlatformDirectoryName( + qbs.targetOS, platformType, sdkVersion, false).toLowerCase(); }, " is '" + sdkName + "', but target OS is [" + qbs.targetOS.join(",") + "] and Xcode SDK version is '" + sdkVersion + "'"); validator.validate(); @@ -195,6 +202,7 @@ Module { name: "Provisioning Profiles" prefix: xcode.provisioningProfilesPath + "/" files: ["*.mobileprovision", "*.provisionprofile"] + fileTags: [] // HACK: provisioning profile handling is not yet ready and can break autotests } FileTagger { diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp index aa3a2f3ef..fb245c4eb 100644 --- a/src/app/qbs-setup-toolchains/probe.cpp +++ b/src/app/qbs-setup-toolchains/probe.cpp @@ -66,7 +66,7 @@ static QString findExecutable(const QString &fileName) const QString path = QString::fromLocal8Bit(qgetenv("PATH")); foreach (const QString &ppath, path.split(HostOsInfo::pathListSeparator())) { const QString fullPath = ppath + QLatin1Char('/') + fullFileName; - if (QFileInfo(fullPath).exists()) + if (QFileInfo::exists(fullPath)) return QDir::cleanPath(fullPath); } return QString(); @@ -138,7 +138,7 @@ static void setCommonProperties(Profile &profile, const QString &compilerFilePat const QStringList &toolchainTypes, const QString &architecture) { const QFileInfo cfi(compilerFilePath); - const QString compilerName = QFileInfo(compilerFilePath).fileName(); + const QString compilerName = cfi.fileName(); if (toolchainTypes.contains(QStringLiteral("mingw"))) profile.setValue(QStringLiteral("qbs.targetOS"), QStringList(QStringLiteral("windows"))); @@ -185,8 +185,8 @@ public: private: Profile * const m_profile; - const QString &m_compilerDirPath; - const QString &m_toolchainPrefix; + QString m_compilerDirPath; + QString m_toolchainPrefix; }; static Profile createGccProfile(const QString &compilerFilePath, Settings *settings, @@ -237,11 +237,12 @@ static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString const QString crossCompilePrefix = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE")); const QString compilerFilePath = findExecutable(crossCompilePrefix + compilerName); - if (!QFileInfo(compilerFilePath).exists()) { + QFileInfo cfi(compilerFilePath); + if (!cfi.exists()) { qStderr << Tr::tr("%1 not found.").arg(compilerName) << endl; return; } - const QString profileName = QFileInfo(compilerFilePath).completeBaseName(); + const QString profileName = cfi.completeBaseName(); const QStringList toolchainTypes = toolchainTypeFromCompilerName(compilerName); profiles << createGccProfile(compilerFilePath, settings, toolchainTypes, profileName); } diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp index 36f1522d3..fb26bca83 100644 --- a/src/app/qbs/commandlinefrontend.cpp +++ b/src/app/qbs/commandlinefrontend.cpp @@ -416,7 +416,7 @@ int CommandLineFrontend::runShell() RunEnvironment runEnvironment = m_projects.first().getRunEnvironment(productToRun, m_parser.installOptions(m_projects.first().profile()), QProcessEnvironment::systemEnvironment(), m_settings); - return runEnvironment.runShell(); + return runEnvironment.doRunShell(); } BuildOptions CommandLineFrontend::buildOptions(const Project &project) const @@ -513,7 +513,7 @@ int CommandLineFrontend::runTarget() RunEnvironment runEnvironment = m_projects.first().getRunEnvironment(productToRun, m_parser.installOptions(m_projects.first().profile()), QProcessEnvironment::systemEnvironment(), m_settings); - return runEnvironment.runTarget(executableFilePath, m_parser.runArgs()); + return runEnvironment.doRunTarget(executableFilePath, m_parser.runArgs()); } void CommandLineFrontend::updateTimestamps() diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp index a8707a7b6..12236e00c 100644 --- a/src/lib/corelib/api/project.cpp +++ b/src/lib/corelib/api/project.cpp @@ -72,6 +72,7 @@ #include <QMutexLocker> #include <QRegExp> #include <QSharedData> +#include <QtDebug> namespace qbs { namespace Internal { @@ -1010,16 +1011,20 @@ QList<InstallableFile> Project::installableFilesForProduct(const ProductData &pr foreach (const GroupConstPtr &group, internalProduct->groups) { foreach (const SourceArtifactConstPtr &artifact, group->allFiles()) { InstallableFile f; - const QString &targetFilePath = ProductInstaller::targetFilePath(internalProduct->topLevelProject(), + try { + const QString &targetFilePath = ProductInstaller::targetFilePath(internalProduct->topLevelProject(), internalProduct->sourceDirectory, artifact->absoluteFilePath, artifact->properties, mutableOptions); - if (targetFilePath.isEmpty()) - continue; - f.d->sourceFilePath = artifact->absoluteFilePath; - f.d->fileTags = artifact->fileTags.toStringList(); - f.d->targetFilePath = targetFilePath; - f.d->isValid = true; - installableFiles << f; + if (targetFilePath.isEmpty()) + continue; + f.d->sourceFilePath = artifact->absoluteFilePath; + f.d->fileTags = artifact->fileTags.toStringList(); + f.d->targetFilePath = targetFilePath; + f.d->isValid = true; + installableFiles << f; + } catch (const ErrorInfo &e) { + qDebug() << e.toString(); + } } } if (internalProduct->enabled) { @@ -1028,17 +1033,21 @@ QList<InstallableFile> Project::installableFilesForProduct(const ProductData &pr ArtifactSet::fromNodeSet(internalProduct->buildData->nodes)) { if (artifact->artifactType == Artifact::SourceFile) continue; - InstallableFile f; - const QString &targetFilePath = ProductInstaller::targetFilePath(internalProduct->topLevelProject(), - internalProduct->sourceDirectory, - artifact->filePath(), artifact->properties, mutableOptions); - if (targetFilePath.isEmpty()) - continue; - f.d->sourceFilePath = artifact->filePath(); - f.d->fileTags = artifact->fileTags().toStringList(); - f.d->targetFilePath = targetFilePath; - f.d->isValid = true; - installableFiles << f; + try { + InstallableFile f; + const QString &targetFilePath = ProductInstaller::targetFilePath(internalProduct->topLevelProject(), + internalProduct->sourceDirectory, artifact->filePath(), + artifact->properties, mutableOptions); + if (targetFilePath.isEmpty()) + continue; + f.d->sourceFilePath = artifact->filePath(); + f.d->fileTags = artifact->fileTags().toStringList(); + f.d->targetFilePath = targetFilePath; + f.d->isValid = true; + installableFiles << f; + } catch (const ErrorInfo &e) { + qDebug() << e.toString(); + } } } qSort(installableFiles); diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp index e0f0a0c91..aee7aa31a 100644 --- a/src/lib/corelib/api/runenvironment.cpp +++ b/src/lib/corelib/api/runenvironment.cpp @@ -92,7 +92,52 @@ RunEnvironment::~RunEnvironment() delete d; } -int RunEnvironment::runShell() +int RunEnvironment::runShell(ErrorInfo *error) +{ + try { + return doRunShell(); + } catch (const ErrorInfo &e) { + if (error) + *error = e; + return -1; + } +} + +int RunEnvironment::runTarget(const QString &targetBin, const QStringList &arguments, + ErrorInfo *error) +{ + try { + return doRunTarget(targetBin, arguments); + } catch (const ErrorInfo &e) { + if (error) + *error = e; + return -1; + } +} + +const QProcessEnvironment RunEnvironment::runEnvironment(ErrorInfo *error) const +{ + try { + return getRunEnvironment(); + } catch (const ErrorInfo &e) { + if (error) + *error = e; + return QProcessEnvironment(); + } +} + +const QProcessEnvironment RunEnvironment::buildEnvironment(ErrorInfo *error) const +{ + try { + return getBuildEnvironment(); + } catch (const ErrorInfo &e) { + if (error) + *error = e; + return QProcessEnvironment(); + } +} + +int RunEnvironment::doRunShell() { d->resolvedProduct->setupBuildEnvironment(&d->engine, d->environment); @@ -156,7 +201,7 @@ static QString findExecutable(const QStringList &fileNames) return QString(); } -int RunEnvironment::runTarget(const QString &targetBin, const QStringList &arguments) +int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arguments) { const QStringList targetOS = PropertyFinder().propertyValue( d->resolvedProduct->moduleProperties->value(), @@ -287,13 +332,13 @@ int RunEnvironment::runTarget(const QString &targetBin, const QStringList &argum return process.exitCode(); } -const QProcessEnvironment RunEnvironment::runEnvironment() const +const QProcessEnvironment RunEnvironment::getRunEnvironment() const { d->resolvedProduct->setupRunEnvironment(&d->engine, d->environment); return d->resolvedProduct->runEnvironment; } -const QProcessEnvironment RunEnvironment::buildEnvironment() const +const QProcessEnvironment RunEnvironment::getBuildEnvironment() const { d->resolvedProduct->setupBuildEnvironment(&d->engine, d->environment); return d->resolvedProduct->buildEnvironment; diff --git a/src/lib/corelib/api/runenvironment.h b/src/lib/corelib/api/runenvironment.h index 93f3de7b2..7c276454e 100644 --- a/src/lib/corelib/api/runenvironment.h +++ b/src/lib/corelib/api/runenvironment.h @@ -41,6 +41,7 @@ class QProcessEnvironment; QT_END_NAMESPACE namespace qbs { +class ErrorInfo; class InstallOptions; class Settings; @@ -51,16 +52,17 @@ class ResolvedProduct; class QBS_EXPORT RunEnvironment { + friend class CommandLineFrontend; friend class Project; public: ~RunEnvironment(); - // These can throw an Error - int runShell(); - int runTarget(const QString &targetBin, const QStringList &arguments); + int runShell(ErrorInfo *error = nullptr); + int runTarget(const QString &targetBin, const QStringList &arguments, + ErrorInfo *error = nullptr); - const QProcessEnvironment runEnvironment() const; - const QProcessEnvironment buildEnvironment() const; + const QProcessEnvironment runEnvironment(ErrorInfo *error = nullptr) const; + const QProcessEnvironment buildEnvironment(ErrorInfo *error = nullptr) const; private: RunEnvironment(const Internal::ResolvedProductPtr &product, @@ -68,6 +70,12 @@ private: const QProcessEnvironment &environment, Settings *settings, const Internal::Logger &logger); + int doRunShell(); + int doRunTarget(const QString &targetBin, const QStringList &arguments); + + const QProcessEnvironment getRunEnvironment() const; + const QProcessEnvironment getBuildEnvironment() const; + class RunEnvironmentPrivate; RunEnvironmentPrivate * const d; }; diff --git a/src/lib/corelib/buildgraph/jscommandexecutor.cpp b/src/lib/corelib/buildgraph/jscommandexecutor.cpp index 914d2c9e1..5cf4840fe 100644 --- a/src/lib/corelib/buildgraph/jscommandexecutor.cpp +++ b/src/lib/corelib/buildgraph/jscommandexecutor.cpp @@ -213,8 +213,10 @@ void JsCommandExecutor::onJavaScriptCommandFinished() if (!result.success) { logger().qbsDebug() << "JS context:\n" << jsCommand()->properties(); logger().qbsDebug() << "JS code:\n" << jsCommand()->sourceCode(); - err.append(tr("Error while executing JavaScriptCommand:"), result.errorLocation); err.append(result.errorMessage); + // ### We don't know the line number of the command's sourceCode property assignment. + err.appendBacktrace(QStringLiteral("JavaScriptCommand.sourceCode")); + err.appendBacktrace(QStringLiteral("Rule.prepare"), result.errorLocation); } emit finished(err); } diff --git a/src/lib/corelib/buildgraph/qtmocscanner.cpp b/src/lib/corelib/buildgraph/qtmocscanner.cpp index d74e646d2..b03e06a85 100644 --- a/src/lib/corelib/buildgraph/qtmocscanner.cpp +++ b/src/lib/corelib/buildgraph/qtmocscanner.cpp @@ -67,6 +67,15 @@ QtMocScanner::~QtMocScanner() delete m_scanResultCache; } +ScannerPlugin *QtMocScanner::scannerPluginForFileTags(const FileTags &ft) +{ + if (ft.contains("objcpp")) + return m_objcppScanner; + if (ft.contains("cpp")) + return m_cppScanner; + return m_hppScanner; +} + static ScanResultCache::Result runScanner(ScannerPlugin *scanner, const Artifact *artifact, ScanResultCache *scanResultCache) { @@ -118,9 +127,13 @@ void QtMocScanner::findIncludedMocCppFiles() if (m_logger.traceEnabled()) m_logger.qbsTrace() << "[QtMocScanner] looking for included moc_XXX.cpp files"; - foreach (Artifact *artifact, m_product->lookupArtifactsByFileTag("cpp")) { + static const FileTags mocCppTags = FileTags::fromStringList(QStringList() + << QStringLiteral("cpp") + << QStringLiteral("objcpp")); + foreach (Artifact *artifact, m_product->lookupArtifactsByFileTags(mocCppTags)) { const ScanResultCache::Result scanResult - = runScanner(m_cppScanner, artifact, m_scanResultCache); + = runScanner(scannerPluginForFileTags(artifact->fileTags()), + artifact, m_scanResultCache); foreach (const ScanResultCache::Dependency &dependency, scanResult.deps) { QString includedFileName = dependency.fileName(); if (includedFileName.startsWith(QLatin1String("moc_")) @@ -158,6 +171,10 @@ QScriptValue QtMocScanner::apply(QScriptEngine *engine, const Artifact *artifact if (scanners.count() != 1) return scannerCountError(engine, scanners.count(), QLatin1String("cpp")); m_cppScanner = scanners.first(); + scanners = ScannerPluginManager::scannersForFileTag("objcpp"); + if (scanners.count() != 1) + return scannerCountError(engine, scanners.count(), QLatin1String("objcpp")); + m_objcppScanner = scanners.first(); scanners = ScannerPluginManager::scannersForFileTag("hpp"); if (scanners.count() != 1) return scannerCountError(engine, scanners.count(), QLatin1String("hpp")); @@ -174,7 +191,8 @@ QScriptValue QtMocScanner::apply(QScriptEngine *engine, const Artifact *artifact bool hasPluginMetaDataMacro = false; const bool isHeaderFile = artifact->fileTags().contains("hpp"); - ScannerPlugin * const scanner = isHeaderFile ? m_hppScanner : m_cppScanner; + ScannerPlugin * const scanner = scannerPluginForFileTags(artifact->fileTags()); + const ScanResultCache::Result scanResult = runScanner(scanner, artifact, m_scanResultCache); if (!scanResult.additionalFileTags.isEmpty()) { if (isHeaderFile) { diff --git a/src/lib/corelib/buildgraph/qtmocscanner.h b/src/lib/corelib/buildgraph/qtmocscanner.h index 0d903789f..d53f57f5f 100644 --- a/src/lib/corelib/buildgraph/qtmocscanner.h +++ b/src/lib/corelib/buildgraph/qtmocscanner.h @@ -58,6 +58,7 @@ public: ~QtMocScanner(); private: + ScannerPlugin *scannerPluginForFileTags(const FileTags &ft); void findIncludedMocCppFiles(); static QScriptValue js_apply(QScriptContext *ctx, QScriptEngine *engine, void *data); QScriptValue apply(QScriptEngine *engine, const Artifact *artifact); @@ -68,6 +69,7 @@ private: ScanResultCache *m_scanResultCache; QHash<QString, QString> m_includedMocCppFiles; ScannerPlugin *m_cppScanner; + ScannerPlugin *m_objcppScanner; ScannerPlugin *m_hppScanner; }; diff --git a/src/lib/corelib/buildgraph/rulenode.cpp b/src/lib/corelib/buildgraph/rulenode.cpp index 20238e8e3..dfc12c3ab 100644 --- a/src/lib/corelib/buildgraph/rulenode.cpp +++ b/src/lib/corelib/buildgraph/rulenode.cpp @@ -125,7 +125,7 @@ void RuleNode::apply(const Logger &logger, const ArtifactSet &changedInputs, } if (!inputs.isEmpty()) { RulesApplicator applicator(product, logger); - applicator.applyRuleInEvaluationContext(m_rule, inputs); + applicator.applyRule(m_rule, inputs); result->createdNodes = applicator.createdArtifacts(); result->invalidatedNodes = applicator.invalidatedArtifacts(); m_oldInputArtifacts.unite(inputs); diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp index a265e6564..07b3969d7 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.cpp +++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp @@ -70,20 +70,15 @@ RulesApplicator::~RulesApplicator() delete m_mocScanner; } -void RulesApplicator::applyRuleInEvaluationContext(const RuleConstPtr &rule, - const ArtifactSet &inputArtifacts) -{ - m_createdArtifacts.clear(); - m_invalidatedArtifacts.clear(); - RulesEvaluationContext::Scope s(m_product->topLevelProject()->buildData->evaluationContext.data()); - applyRule(rule, inputArtifacts); -} - void RulesApplicator::applyRule(const RuleConstPtr &rule, const ArtifactSet &inputArtifacts) { if (inputArtifacts.isEmpty()) return; + m_createdArtifacts.clear(); + m_invalidatedArtifacts.clear(); + RulesEvaluationContext::Scope s(evalContext().data()); + m_rule = rule; m_completeInputSet = inputArtifacts; if (rule->name == QLatin1String("QtCoreMocRule")) { @@ -270,11 +265,14 @@ Artifact *RulesApplicator::createOutputArtifactFromRuleArtifact( const RuleArtifactConstPtr &ruleArtifact, const ArtifactSet &inputArtifacts, QSet<QString> *outputFilePaths) { - QScriptValue scriptValue = engine()->evaluate(ruleArtifact->filePath); + QScriptValue scriptValue = engine()->evaluate(ruleArtifact->filePath, + ruleArtifact->filePathLocation.filePath(), + ruleArtifact->filePathLocation.line()); if (Q_UNLIKELY(engine()->hasErrorOrException(scriptValue))) { - throw ErrorInfo(Tr::tr("Error in Rule.Artifact fileName at %1: %2") - .arg(ruleArtifact->location.toString(), - engine()->lastErrorString(scriptValue))); + ErrorInfo errorInfo(engine()->lastErrorString(scriptValue), + engine()->uncaughtExceptionBacktraceOrEmpty()); + errorInfo.append(QStringLiteral("Artifact.filePath"), ruleArtifact->filePathLocation); + throw errorInfo; } QString outputPath = FileInfo::resolvePath(m_product->buildDirectory(), scriptValue.toString()); if (Q_UNLIKELY(outputFilePaths->contains(outputPath))) { @@ -377,14 +375,20 @@ QList<Artifact *> RulesApplicator::runOutputArtifactsScript(const ArtifactSet &i const QScriptValueList &args) { QList<Artifact *> lst; - QScriptValue fun = engine()->evaluate(m_rule->outputArtifactsScript->sourceCode); + QScriptValue fun = engine()->evaluate(m_rule->outputArtifactsScript->sourceCode, + m_rule->outputArtifactsScript->location.filePath(), + m_rule->outputArtifactsScript->location.line()); if (!fun.isFunction()) throw ErrorInfo(QLatin1String("Function expected."), m_rule->outputArtifactsScript->location); QScriptValue res = fun.call(QScriptValue(), args); - if (res.isError() || engine()->hasUncaughtException()) - throw ErrorInfo(Tr::tr("Error while calling Rule.outputArtifacts: %1").arg(res.toString()), - m_rule->outputArtifactsScript->location); + if (engine()->hasErrorOrException(res)) { + ErrorInfo errorInfo(engine()->lastErrorString(res), + engine()->uncaughtExceptionBacktraceOrEmpty()); + errorInfo.append(QStringLiteral("Rule.outputArtifacts"), + m_rule->outputArtifactsScript->location); + throw errorInfo; + } if (!res.isArray()) throw ErrorInfo(Tr::tr("Rule.outputArtifacts must return an array of objects."), m_rule->outputArtifactsScript->location); @@ -525,7 +529,7 @@ QString RulesApplicator::resolveOutPath(const QString &path) const return result; } -RulesEvaluationContextPtr RulesApplicator::evalContext() const +const RulesEvaluationContextPtr &RulesApplicator::evalContext() const { return m_product->topLevelProject()->buildData->evaluationContext; } diff --git a/src/lib/corelib/buildgraph/rulesapplicator.h b/src/lib/corelib/buildgraph/rulesapplicator.h index 9365483d3..f0e530e02 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.h +++ b/src/lib/corelib/buildgraph/rulesapplicator.h @@ -53,8 +53,6 @@ public: RulesApplicator(const ResolvedProductPtr &product, const Logger &logger); ~RulesApplicator(); - void applyRuleInEvaluationContext(const RuleConstPtr &rule, - const ArtifactSet &inputArtifacts); const NodeSet &createdArtifacts() const { return m_createdArtifacts; } const NodeSet &invalidatedArtifacts() const { return m_invalidatedArtifacts; } @@ -74,7 +72,7 @@ private: Artifact *createOutputArtifactFromScriptValue(const QScriptValue &obj, const ArtifactSet &inputArtifacts); QString resolveOutPath(const QString &path) const; - RulesEvaluationContextPtr evalContext() const; + const RulesEvaluationContextPtr &evalContext() const; ScriptEngine *engine() const; QScriptValue scope() const; diff --git a/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp b/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp index eed00cdac..1b7efb33c 100644 --- a/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp +++ b/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp @@ -86,9 +86,6 @@ void RulesEvaluationContext::initScope() if (m_initScopeCalls++ > 0) return; - m_engine->setProperty("lastSetupProject", QVariant()); - m_engine->setProperty("lastSetupProduct", QVariant()); - m_engine->clearImportsCache(); m_engine->pushContext(); m_scope = m_engine->newObject(); diff --git a/src/lib/corelib/buildgraph/transformer.cpp b/src/lib/corelib/buildgraph/transformer.cpp index c0ad6ed07..9278df64d 100644 --- a/src/lib/corelib/buildgraph/transformer.cpp +++ b/src/lib/corelib/buildgraph/transformer.cpp @@ -208,7 +208,9 @@ void Transformer::createCommands(const ScriptFunctionConstPtr &script, { ScriptEngine * const engine = evalContext->engine(); if (!script->scriptFunction.isValid() || script->scriptFunction.engine() != engine) { - script->scriptFunction = engine->evaluate(script->sourceCode); + script->scriptFunction = engine->evaluate(script->sourceCode, + script->location.filePath(), + script->location.line()); if (Q_UNLIKELY(!script->scriptFunction.isFunction())) throw ErrorInfo(Tr::tr("Invalid prepare script."), script->location); } @@ -217,11 +219,15 @@ void Transformer::createCommands(const ScriptFunctionConstPtr &script, propertiesRequestedInPrepareScript = engine->propertiesRequestedInScript(); propertiesRequestedFromArtifactInPrepareScript = engine->propertiesRequestedFromArtifact(); engine->clearRequestedProperties(); - if (Q_UNLIKELY(engine->hasErrorOrException(scriptValue))) - throw ErrorInfo(Tr::tr("evaluating prepare script: ") - + engine->lastErrorString(scriptValue), - CodeLocation(script->location.filePath(), - script->location.line() + engine->uncaughtExceptionLineNumber() - 1)); + if (Q_UNLIKELY(engine->hasErrorOrException(scriptValue))) { + ErrorInfo errorInfo(engine->lastErrorString(scriptValue), + engine->uncaughtExceptionBacktraceOrEmpty()); + if (rule) + errorInfo.append(QStringLiteral("Rule.prepare"), script->location); + else + errorInfo.append(QStringLiteral("Transformer.prepare"), script->location); + throw errorInfo; + } commands.clear(); if (scriptValue.isArray()) { diff --git a/src/lib/corelib/corelib.pro b/src/lib/corelib/corelib.pro index 1c3213c5e..8644f9977 100644 --- a/src/lib/corelib/corelib.pro +++ b/src/lib/corelib/corelib.pro @@ -1,7 +1,7 @@ TARGET = qbscore include(../library.pri) -QT += script +QT += core-private network script qbs_enable_unit_tests:QT += testlib qbs_enable_project_file_updates: QT += gui diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index b57f859ad..d20378764 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -3,7 +3,7 @@ import QbsFunctions QbsLibrary { Depends { name: "cpp" } - Depends { name: "Qt"; submodules: ["script", "xml"] } + Depends { name: "Qt"; submodules: ["core-private", "network", "script", "xml"] } Depends { condition: project.enableProjectFileUpdates; name: "Qt.gui" } Depends { condition: project.enableUnitTests; name: "Qt.test" } name: "qbscore" @@ -31,7 +31,7 @@ QbsLibrary { Properties { condition: qbs.targetOS.contains("darwin") - cpp.frameworks: "Foundation" + cpp.frameworks: ["Foundation", "Security"] } Group { @@ -409,6 +409,15 @@ QbsLibrary { ] } Group { + condition: qbs.targetOS.contains("osx") + name: "tools (OS X)" + prefix: "tools/" + files: [ + "applecodesignutils.cpp", + "applecodesignutils.h" + ] + } + Group { condition: qbs.targetOS.contains("unix") name: "tools (Unix)" prefix: "tools/" diff --git a/src/lib/corelib/jsextensions/propertylist.mm b/src/lib/corelib/jsextensions/propertylist.mm index b236d7225..dae241e5f 100644 --- a/src/lib/corelib/jsextensions/propertylist.mm +++ b/src/lib/corelib/jsextensions/propertylist.mm @@ -128,15 +128,14 @@ void PropertyList::readFromFile(const QString &filePath) QFile file(filePath); if (file.open(QIODevice::ReadOnly)) { - QByteArray data = file.readAll(); - if (!data.isEmpty()) { + const QByteArray data = file.readAll(); + if (file.error() == QFile::NoError) { p->d->readFromData(p->context(), data); - } else { - p->context()->throwError(file.errorString()); + return; } - } else { - p->context()->throwError(file.errorString()); } + + p->context()->throwError(QStringLiteral("%1: %2").arg(filePath).arg(file.errorString())); } void PropertyList::readFromData(const QByteArray &data) @@ -151,17 +150,15 @@ void PropertyList::writeToFile(const QString &filePath, const QString &plistForm Q_ASSERT(thisObject().engine() == engine()); PropertyList *p = qscriptvalue_cast<PropertyList*>(thisObject()); + QFile file(filePath); QByteArray data = p->d->writeToData(p->context(), plistFormat); if (Q_LIKELY(!data.isEmpty())) { - QFile file(filePath); - if (file.open(QIODevice::WriteOnly)) { - if (Q_UNLIKELY(file.write(data) != data.size())) { - p->context()->throwError(file.errorString()); - } - } else { - p->context()->throwError(file.errorString()); + if (file.open(QIODevice::WriteOnly) && file.write(data) == data.size()) { + return; } } + + p->context()->throwError(QStringLiteral("%1: %2").arg(filePath).arg(file.errorString())); } QScriptValue PropertyList::format() const @@ -300,7 +297,7 @@ QByteArray PropertyListPrivate::writeToData(QScriptContext *context, const QStri id obj = QPropertyListUtils::toPropertyList(propertyListObject); if (!obj) { context->throwError(QLatin1String("error converting property list")); - return 0; + return QByteArray(); } if (format == QLatin1String("json") || format == QLatin1String("json-pretty") || diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp index 10ded8bda..6ce37b6bf 100644 --- a/src/lib/corelib/jsextensions/utilitiesextension.cpp +++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp @@ -35,6 +35,10 @@ #include <tools/architectures.h> #include <tools/fileinfo.h> +#ifdef Q_OS_OSX +#include <tools/applecodesignutils.h> +#endif + #include <QCryptographicHash> #include <QDir> #include <QFileInfo> @@ -55,6 +59,10 @@ public: static QScriptValue js_getNativeSetting(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_nativeSettingGroups(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_rfc1034identifier(QScriptContext *context, QScriptEngine *engine); + + static QScriptValue js_smimeMessageContent(QScriptContext *context, QScriptEngine *engine); + static QScriptValue js_certificateInfo(QScriptContext *context, QScriptEngine *engine); + static QScriptValue js_signingIdentities(QScriptContext *context, QScriptEngine *engine); }; void initializeJsExtensionUtilities(QScriptValue extensionObject) @@ -72,6 +80,12 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject) engine->newFunction(UtilitiesExtension::js_nativeSettingGroups, 1)); environmentObj.setProperty(QStringLiteral("rfc1034Identifier"), engine->newFunction(UtilitiesExtension::js_rfc1034identifier, 1)); + environmentObj.setProperty(QStringLiteral("smimeMessageContent"), + engine->newFunction(UtilitiesExtension::js_smimeMessageContent, 1)); + environmentObj.setProperty(QStringLiteral("certificateInfo"), + engine->newFunction(UtilitiesExtension::js_certificateInfo, 1)); + environmentObj.setProperty(QStringLiteral("signingIdentities"), + engine->newFunction(UtilitiesExtension::js_signingIdentities, 0)); extensionObject.setProperty(QStringLiteral("Utilities"), environmentObj); } @@ -147,6 +161,69 @@ QScriptValue UtilitiesExtension::js_rfc1034identifier(QScriptContext *context, return engine->toScriptValue(HostOsInfo::rfc1034Identifier(identifier)); } +/** + * Reads the contents of the S/MIME message located at \p filePath. + * An equivalent command line would be: + * \code security cms -D -i <infile> -o <outfile> \endcode + * or: + * \code openssl smime -verify -noverify -inform DER -in <infile> -out <outfile> \endcode + * + * \note A provisioning profile is an S/MIME message whose contents are an XML property list, + * so this method can be used to read such files. + */ +QScriptValue UtilitiesExtension::js_smimeMessageContent(QScriptContext *context, + QScriptEngine *engine) +{ +#ifndef Q_OS_OSX + Q_UNUSED(engine); + return context->throwError(QScriptContext::UnknownError, + QLatin1String("smimeMessageContent is not available on this platform")); +#else + if (Q_UNLIKELY(context->argumentCount() != 1)) + return context->throwError(QScriptContext::SyntaxError, + QLatin1String("smimeMessageContent expects 1 argument")); + + const QString filePath = context->argument(0).toString(); + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) + return engine->undefinedValue(); + + QByteArray content = smimeMessageContent(file.readAll()); + if (content.isEmpty()) + return engine->undefinedValue(); + return engine->toScriptValue(content); +#endif +} + +QScriptValue UtilitiesExtension::js_certificateInfo(QScriptContext *context, + QScriptEngine *engine) +{ +#ifndef Q_OS_OSX + Q_UNUSED(engine); + return context->throwError(QScriptContext::UnknownError, + QLatin1String("certificateInfo is not available on this platform")); +#else + if (Q_UNLIKELY(context->argumentCount() != 1)) + return context->throwError(QScriptContext::SyntaxError, + QLatin1String("certificateInfo expects 1 argument")); + return engine->toScriptValue(certificateInfo(context->argument(0).toVariant().toByteArray())); +#endif +} + +// Rough command line equivalent: security find-identity -p codesigning -v +QScriptValue UtilitiesExtension::js_signingIdentities(QScriptContext *context, + QScriptEngine *engine) +{ +#ifndef Q_OS_OSX + Q_UNUSED(engine); + return context->throwError(QScriptContext::UnknownError, + QLatin1String("signingIdentities is not available on this platform")); +#else + Q_UNUSED(context); + return engine->toScriptValue(identitiesProperties()); +#endif +} + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/evaluatorscriptclass.cpp b/src/lib/corelib/language/evaluatorscriptclass.cpp index 89c71e2ad..7293f35d7 100644 --- a/src/lib/corelib/language/evaluatorscriptclass.cpp +++ b/src/lib/corelib/language/evaluatorscriptclass.cpp @@ -394,7 +394,7 @@ static QString overriddenSourceDirectory(const Item *item) inline void convertToPropertyType(const Item *item, const PropertyDeclaration::Type t, QScriptValue &v) { - if (v.isUndefined()) + if (v.isUndefined() || v.isError()) return; switch (t) { case PropertyDeclaration::UnknownType: diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp index 6abba8d20..15c9bcc9f 100644 --- a/src/lib/corelib/language/language.cpp +++ b/src/lib/corelib/language/language.cpp @@ -219,6 +219,7 @@ void RuleArtifact::load(PersistentPool &pool) >> fileTags >> alwaysUpdated; location.load(pool); + filePathLocation.load(pool); int i; pool.stream() >> i; @@ -240,6 +241,7 @@ void RuleArtifact::store(PersistentPool &pool) const << fileTags << alwaysUpdated; location.store(pool); + filePathLocation.store(pool); pool.stream() << bindings.count(); for (int i = bindings.count(); --i >= 0;) { @@ -701,6 +703,15 @@ ArtifactSet ResolvedProduct::lookupArtifactsByFileTag(const FileTag &tag) const return buildData->artifactsByFileTag.value(tag); } +ArtifactSet ResolvedProduct::lookupArtifactsByFileTags(const FileTags &tags) const +{ + QBS_CHECK(buildData); + ArtifactSet set; + for (const FileTag &tag : tags) + set = set.unite(buildData->artifactsByFileTag.value(tag)); + return set; +} + ArtifactSet ResolvedProduct::targetArtifacts() const { QBS_CHECK(buildData); diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h index d098d189d..00d0a513b 100644 --- a/src/lib/corelib/language/language.h +++ b/src/lib/corelib/language/language.h @@ -96,6 +96,7 @@ public: FileTags fileTags; bool alwaysUpdated; CodeLocation location; + CodeLocation filePathLocation; class Binding { @@ -388,6 +389,7 @@ public: void unmarkForReapplication(const RuleConstPtr &rule); bool isMarkedForReapplication(const RuleConstPtr &rule) const; ArtifactSet lookupArtifactsByFileTag(const FileTag &tag) const; + ArtifactSet lookupArtifactsByFileTags(const FileTags &tags) const; ArtifactSet targetArtifacts() const; TopLevelProject *topLevelProject() const; diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index 37ecdc79b..2b84e32b4 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -1526,6 +1526,7 @@ void ModuleLoader::resolveProbes(Item *item) void ModuleLoader::resolveProbe(Item *parent, Item *probe) { + m_logger.qbsTrace() << "Resolving Probe at " << probe->location().toString(); const JSSourceValueConstPtr configureScript = probe->sourceProperty(QLatin1String("configure")); if (Q_UNLIKELY(!configureScript)) throw ErrorInfo(Tr::tr("Probe.configure must be set."), probe->location()); @@ -1544,9 +1545,15 @@ void ModuleLoader::resolveProbe(Item *parent, Item *probe) m_engine->currentContext()->pushScope(scope); foreach (const ProbeProperty &b, probeBindings) scope.setProperty(b.first, b.second); - QScriptValue sv = m_engine->evaluate(configureScript->sourceCodeForEvaluation()); - if (Q_UNLIKELY(m_engine->hasErrorOrException(sv))) - throw ErrorInfo(m_engine->lastErrorString(sv), configureScript->location()); + const bool runProbe = m_evaluator->boolValue(probe, QLatin1String("condition")); + ErrorInfo evalError; + if (runProbe) { + QScriptValue sv = m_engine->evaluate(configureScript->sourceCodeForEvaluation()); + if (Q_UNLIKELY(m_engine->hasErrorOrException(sv))) + evalError = ErrorInfo(m_engine->lastErrorString(sv), configureScript->location()); + } else { + m_logger.qbsDebug() << "Probe disabled; skipping"; + } foreach (const ProbeProperty &b, probeBindings) { const QVariant newValue = scope.property(b.first).toVariant(); if (newValue != b.second.toVariant()) @@ -1555,6 +1562,8 @@ void ModuleLoader::resolveProbe(Item *parent, Item *probe) m_engine->currentContext()->popScope(); m_engine->currentContext()->popScope(); m_engine->currentContext()->popScope(); + if (evalError.hasError()) + throw evalError; } void ModuleLoader::checkCancelation() const diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp index 21d393c80..47ad5deca 100644 --- a/src/lib/corelib/language/projectresolver.cpp +++ b/src/lib/corelib/language/projectresolver.cpp @@ -730,6 +730,9 @@ void ProjectResolver::resolveRuleArtifact(const RulePtr &rule, Item *item) rule->artifacts += artifact; artifact->location = item->location(); + if (const auto sourceProperty = item->sourceProperty(QStringLiteral("filePath"))) + artifact->filePathLocation = sourceProperty->location(); + artifact->filePath = verbatimValue(item, QLatin1String("filePath")); artifact->fileTags = m_evaluator->fileTagsValue(item, QLatin1String("fileTags")); artifact->alwaysUpdated = m_evaluator->boolValue(item, QLatin1String("alwaysUpdated")); diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp index c67efbfc9..03b0681d5 100644 --- a/src/lib/corelib/language/scriptengine.cpp +++ b/src/lib/corelib/language/scriptengine.cpp @@ -576,6 +576,12 @@ void ScriptEngine::extendJavaScriptBuiltins() JSTypeExtender arrayExtender(this, QLatin1String("Array")); arrayExtender.addFunction(QLatin1String("contains"), QLatin1String("(function(e){return this.indexOf(e) !== -1;})")); + arrayExtender.addFunction(QLatin1String("containsAll"), + QLatin1String("(function(e){var $this = this;" + "return e.every(function (v) { return $this.contains(v) });})")); + arrayExtender.addFunction(QLatin1String("containsAny"), + QLatin1String("(function(e){var $this = this;" + "return e.some(function (v) { return $this.contains(v) });})")); arrayExtender.addFunction(QLatin1String("uniqueConcat"), QLatin1String("(function(other){" "var r = this.concat();" diff --git a/src/lib/corelib/language/scriptengine.h b/src/lib/corelib/language/scriptengine.h index 0059479ef..481d8fd91 100644 --- a/src/lib/corelib/language/scriptengine.h +++ b/src/lib/corelib/language/scriptengine.h @@ -112,7 +112,9 @@ public: const QScriptValue &context); void registerOwnedVariantMap(QVariantMap *vm) { m_ownedVariantMaps.append(vm); } - + QStringList uncaughtExceptionBacktraceOrEmpty() const { + return hasUncaughtException() ? uncaughtExceptionBacktrace() : QStringList(); + } bool hasErrorOrException(const QScriptValue &v) const { return v.isError() || hasUncaughtException(); } diff --git a/src/lib/corelib/language/testdata/throwing-probe.qbs b/src/lib/corelib/language/testdata/throwing-probe.qbs new file mode 100644 index 000000000..7f4a77a57 --- /dev/null +++ b/src/lib/corelib/language/testdata/throwing-probe.qbs @@ -0,0 +1,12 @@ +import qbs + +Product { + name: "theProduct" + property bool enableProbe + Probe { + condition: enableProbe + configure: { + throw "Error!"; + } + } +} diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp index 81edcdd29..702af884e 100644 --- a/src/lib/corelib/language/tst_language.cpp +++ b/src/lib/corelib/language/tst_language.cpp @@ -1595,6 +1595,31 @@ void TestLanguage::relaxedErrorMode_data() QTest::newRow("relaxed mode") << false; } +void TestLanguage::throwingProbe() +{ + QFETCH(bool, enableProbe); + try { + SetupProjectParameters params = defaultParameters; + params.setProjectFilePath(testProject("throwing-probe.qbs")); + QVariantMap properties; + properties.insert(QLatin1String("theProduct.enableProbe"), enableProbe); + params.setOverriddenValues(properties); + const TopLevelProjectPtr project = loader->loadProject(params); + QVERIFY(project); + QVERIFY(!enableProbe); + } catch (const ErrorInfo &e) { + QVERIFY2(enableProbe, qPrintable(e.toString())); + } +} + +void TestLanguage::throwingProbe_data() +{ + QTest::addColumn<bool>("enableProbe"); + + QTest::newRow("enabled probe") << true; + QTest::newRow("disabled probe") << false; +} + void TestLanguage::qualifiedId() { QString str = "foo.bar.baz"; @@ -1887,7 +1912,7 @@ void TestLanguage::wildcards() QVERIFY(product); GroupPtr group; if (useGroup) { - QCOMPARE(product->groups.count(), 3); + QCOMPARE(product->groups.count(), HostOsInfo::isOsxHost() ? 4 : 3); foreach (const GroupPtr &rg, product->groups) { if (rg->name == groupName) { group = rg; @@ -1895,7 +1920,7 @@ void TestLanguage::wildcards() } } } else { - QCOMPARE(product->groups.count(), 2); + QCOMPARE(product->groups.count(), HostOsInfo::isOsxHost() ? 3 : 2); group = product->groups.first(); } QVERIFY(group); diff --git a/src/lib/corelib/language/tst_language.h b/src/lib/corelib/language/tst_language.h index 93ae173ea..60a1f08f8 100644 --- a/src/lib/corelib/language/tst_language.h +++ b/src/lib/corelib/language/tst_language.h @@ -113,6 +113,8 @@ private slots: void qbsPropertiesInProjectCondition(); void relaxedErrorMode(); void relaxedErrorMode_data(); + void throwingProbe(); + void throwingProbe_data(); void defaultValue(); void defaultValue_data(); void qualifiedId(); diff --git a/src/lib/corelib/tools/applecodesignutils.cpp b/src/lib/corelib/tools/applecodesignutils.cpp new file mode 100644 index 000000000..9ca00c314 --- /dev/null +++ b/src/lib/corelib/tools/applecodesignutils.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "applecodesignutils.h" +#include <QByteArray> +#include <QCryptographicHash> +#include <QDateTime> +#include <QSslCertificate> +#include <QSslCertificateExtension> + +#include <QtCore/private/qcore_mac_p.h> +#include <Security/Security.h> + +#include <QDebug> + +namespace qbs { +namespace Internal { + +QByteArray smimeMessageContent(const QByteArray &data) +{ + QCFType<CMSDecoderRef> decoder = NULL; + if (CMSDecoderCreate(&decoder) != noErr) + return QByteArray(); + + if (CMSDecoderUpdateMessage(decoder, data.constData(), data.size()) != noErr) + return QByteArray(); + + if (CMSDecoderFinalizeMessage(decoder) != noErr) + return QByteArray(); + + QCFType<CFDataRef> content = NULL; + if (CMSDecoderCopyContent(decoder, &content) != noErr) + return QByteArray(); + + return QByteArray::fromCFData(content); +} + +QVariantMap certificateInfo(const QByteArray &data) +{ + const QSslCertificate cert(data, QSsl::Der); + + // Also potentially useful, but these are for signing pkgs which aren't used here + // 1.2.840.113635.100.4.9 - 3rd Party Mac Developer Installer: <name> + // 1.2.840.113635.100.4.13 - Developer ID Installer: <name> + for (const auto &extension : cert.extensions()) { + if (extension.name() == QStringLiteral("extendedKeyUsage")) { + if (!extension.value().toStringList().contains(QStringLiteral("Code Signing"))) + return QVariantMap(); + } + } + + const auto subjectInfo = [](const QSslCertificate &cert) { + QVariantMap map; + for (const auto &attr : cert.subjectInfoAttributes()) + map.insert(QString::fromLatin1(attr), cert.subjectInfo(attr).first()); + return map; + }; + + return { + {QStringLiteral("SHA1"), cert.digest(QCryptographicHash::Sha1).toHex().toUpper()}, + {QStringLiteral("subjectInfo"), subjectInfo(cert)}, + {QStringLiteral("validBefore"), cert.effectiveDate()}, + {QStringLiteral("validAfter"), cert.expiryDate()} + }; +} + +QVariantMap identitiesProperties() +{ + // Apple documentation states that the Sec* family of functions are not thread-safe on OS X + // https://developer.apple.com/library/mac/documentation/Security/Reference/certifkeytrustservices/ + static QMutex securityMutex; + QMutexLocker locker(&securityMutex); + Q_UNUSED(locker); + + const void *keys[] = {kSecClass, kSecMatchLimit, kSecAttrCanSign}; + const void *values[] = {kSecClassIdentity, kSecMatchLimitAll, kCFBooleanTrue}; + QCFType<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, + keys, + values, + sizeof(keys) / sizeof(keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + QCFType<CFTypeRef> result = NULL; + if (SecItemCopyMatching(query, &result) != errSecSuccess) + return QVariantMap(); + + QVariantMap items; + const auto tryAppend = [&](SecIdentityRef identity) { + if (!identity) + return; + + QCFType<SecCertificateRef> certificate = NULL; + if (SecIdentityCopyCertificate(identity, &certificate) != errSecSuccess) + return; + + QCFType<CFDataRef> certificateData = SecCertificateCopyData(certificate); + if (!certificateData) + return; + + auto props = certificateInfo(QByteArray::fromRawCFData(certificateData)); + if (!props.isEmpty()) + items.insert(props[QStringLiteral("SHA1")].toString(), props); + }; + + if (CFGetTypeID(result) == SecIdentityGetTypeID()) { + tryAppend((SecIdentityRef)result.operator const void *()); + } else if (CFGetTypeID(result) == CFArrayGetTypeID()) { + for (CFIndex i = 0; i < CFArrayGetCount((CFArrayRef)result.operator const void *()); ++i) + tryAppend((SecIdentityRef)CFArrayGetValueAtIndex(result.as<CFArrayRef>(), i)); + } + + return items; +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/applecodesignutils.h b/src/lib/corelib/tools/applecodesignutils.h new file mode 100644 index 000000000..4dc456289 --- /dev/null +++ b/src/lib/corelib/tools/applecodesignutils.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_APPLECODESIGNUTILS_H +#define QBS_APPLECODESIGNUTILS_H + +#include "qbs_export.h" +#include <QVariantMap> + +namespace qbs { +namespace Internal { + +QByteArray smimeMessageContent(const QByteArray &data); +QVariantMap certificateInfo(const QByteArray &data); +QVariantMap identitiesProperties(); + +} // namespace Internal +} // namespace qbs + +#endif // QBS_APPLECODESIGNUTILS_H diff --git a/src/lib/corelib/tools/codelocation.h b/src/lib/corelib/tools/codelocation.h index f5b882ead..3550c78ea 100644 --- a/src/lib/corelib/tools/codelocation.h +++ b/src/lib/corelib/tools/codelocation.h @@ -49,7 +49,8 @@ class QBS_EXPORT CodeLocation friend QBS_EXPORT bool operator==(const CodeLocation &cl1, const CodeLocation &cl2); public: CodeLocation(); - CodeLocation(const QString &aFilePath, int aLine = -1, int aColumn = -1, bool checkPath = true); + explicit CodeLocation(const QString &aFilePath, int aLine = -1, int aColumn = -1, + bool checkPath = true); CodeLocation(const CodeLocation &other); CodeLocation &operator=(const CodeLocation &other); ~CodeLocation(); diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp index d114fda7c..78fc5cdcd 100644 --- a/src/lib/corelib/tools/error.cpp +++ b/src/lib/corelib/tools/error.cpp @@ -30,6 +30,7 @@ #include "error.h" +#include <QRegularExpression> #include <QSharedData> #include <QStringList> @@ -40,6 +41,7 @@ class ErrorItem::ErrorItemPrivate : public QSharedData public: QString description; CodeLocation codeLocation; + bool isBacktraceItem = false; }; /*! @@ -53,11 +55,13 @@ ErrorItem::ErrorItem() : d(new ErrorItemPrivate) { } -ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocation) +ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocation, + bool isBacktraceItem) : d(new ErrorItemPrivate) { d->description = description; d->codeLocation = codeLocation; + d->isBacktraceItem = isBacktraceItem; } ErrorItem::ErrorItem(const ErrorItem &rhs) : d(rhs.d) @@ -84,6 +88,11 @@ CodeLocation ErrorItem::codeLocation() const return d->codeLocation; } +bool ErrorItem::isBacktraceItem() const +{ + return d->isBacktraceItem; +} + /*! * \fn const QString &ErrorData::description() const * \brief A general description of the error. @@ -138,6 +147,23 @@ ErrorInfo::ErrorInfo(const QString &description, const CodeLocation &location, b d->internalError = internalError; } +ErrorInfo::ErrorInfo(const QString &description, const QStringList &backtrace) + : d(new ErrorInfoPrivate) +{ + append(description); + for (const QString &traceLine : backtrace) { + QRegularExpression regexp( + QStringLiteral("^(?<message>.+) at (?<file>.+):(?<line>\\-?[0-9]+)$")); + QRegularExpressionMatch match = regexp.match(traceLine); + if (match.hasMatch()) { + const CodeLocation location(match.captured(QStringLiteral("file")), + match.captured(QStringLiteral("line")).toInt()); + appendBacktrace(match.captured(QStringLiteral("message")), location); + } + } +} + + ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other) { d = other.d; @@ -148,6 +174,11 @@ ErrorInfo::~ErrorInfo() { } +void ErrorInfo::appendBacktrace(const QString &description, const CodeLocation &location) +{ + d->items.append(ErrorItem(description, location, true)); +} + void ErrorInfo::append(const QString &description, const CodeLocation &location) { d->items.append(ErrorItem(description, location)); @@ -181,8 +212,19 @@ void ErrorInfo::clear() QString ErrorInfo::toString() const { QStringList lines; - foreach (const ErrorItem &e, d->items) - lines.append(e.toString()); + foreach (const ErrorItem &e, d->items) { + if (e.isBacktraceItem()) { + QString line; + if (!e.description().isEmpty()) + line.append(QStringLiteral(" at %1").arg(e.description())); + if (e.codeLocation().isValid()) + line.append(QStringLiteral(" in %1").arg(e.codeLocation().toString())); + if (!line.isEmpty()) + lines.append(QStringLiteral("\t") + line); + } else { + lines.append(e.toString()); + } + } return lines.join(QLatin1Char('\n')); } diff --git a/src/lib/corelib/tools/error.h b/src/lib/corelib/tools/error.h index 5c0ea0726..1aa83d485 100644 --- a/src/lib/corelib/tools/error.h +++ b/src/lib/corelib/tools/error.h @@ -58,8 +58,11 @@ public: CodeLocation codeLocation() const; QString toString() const; + bool isBacktraceItem() const; + private: - ErrorItem(const QString &description, const CodeLocation &codeLocation); + ErrorItem(const QString &description, const CodeLocation &codeLocation, + bool isBacktraceItem = false); class ErrorItemPrivate; QExplicitlySharedDataPointer<ErrorItemPrivate> d; @@ -72,9 +75,11 @@ public: ErrorInfo(const ErrorInfo &rhs); ErrorInfo(const QString &description, const CodeLocation &location = CodeLocation(), bool internalError = false); + ErrorInfo(const QString &description, const QStringList &backtrace); ErrorInfo &operator=(const ErrorInfo &other); ~ErrorInfo(); + void appendBacktrace(const QString &description, const CodeLocation &location = CodeLocation()); void append(const QString &description, const CodeLocation &location = CodeLocation()); void prepend(const QString &description, const CodeLocation &location = CodeLocation()); QList<ErrorItem> items() const; diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp index 1455f4e16..885cd2b5d 100644 --- a/src/lib/corelib/tools/persistence.cpp +++ b/src/lib/corelib/tools/persistence.cpp @@ -41,7 +41,7 @@ namespace qbs { namespace Internal { -static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-84"; +static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-85"; PersistentPool::PersistentPool(const Logger &logger) : m_logger(logger) { diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri index 4722b7aa1..618b08bb3 100644 --- a/src/lib/corelib/tools/tools.pri +++ b/src/lib/corelib/tools/tools.pri @@ -74,6 +74,12 @@ SOURCES += \ $$PWD/version.cpp \ $$PWD/visualstudioversioninfo.cpp +osx { + HEADERS += $$PWD/applecodesignutils.h + SOURCES += $$PWD/applecodesignutils.cpp + LIBS += -framework Security +} + win32 { SOURCES += $$PWD/filetime_win.cpp } diff --git a/src/lib/qtprofilesetup/qtmoduleinfo.cpp b/src/lib/qtprofilesetup/qtmoduleinfo.cpp index d15e06ac9..03cc042b4 100644 --- a/src/lib/qtprofilesetup/qtmoduleinfo.cpp +++ b/src/lib/qtprofilesetup/qtmoduleinfo.cpp @@ -239,19 +239,20 @@ void QtModuleInfo::setupLibraries(const QtEnvironment &qtEnv, bool debugBuild, if (simplifiedLine.startsWith("QMAKE_PRL_TARGET")) { const bool isMingw = qtEnv.mkspecName.startsWith(QLatin1String("win")) && qtEnv.mkspecName.contains(QLatin1String("g++")); + const bool isQtVersionBefore56 = qtEnv.qtMajorVersion < 5 + || (qtEnv.qtMajorVersion == 5 && qtEnv.qtMinorVersion < 6); libFilePath = libDir; // QMAKE_PRL_TARGET has a "lib" prefix, except for mingw. // Of course, the exception has an exception too: For static libs, mingw *does* // have the "lib" prefix. TODO: Shoot the people responsible for this. - if (isMingw && !isStaticLibrary) + if (isQtVersionBefore56 && isMingw && !isStaticLibrary) libFilePath += QLatin1String("lib"); libFilePath += QString::fromLatin1(simplifiedLine.mid(equalsOffset + 1).trimmed()); if (isNonStaticQt4OnWindows) libFilePath += QString::number(4); // This is *not* part of QMAKE_PRL_TARGET... - if (qtEnv.qtMajorVersion < 5 - || (qtEnv.qtMajorVersion == 5 && qtEnv.qtMinorVersion < 6)) { + if (isQtVersionBefore56) { if (qtEnv.mkspecName.contains(QLatin1String("msvc"))) libFilePath += QLatin1String(".lib"); else if (isMingw) diff --git a/src/plugins/scanner/cpp/cppscanner.cpp b/src/plugins/scanner/cpp/cppscanner.cpp index 1d5f4c156..226e75bcb 100644 --- a/src/plugins/scanner/cpp/cppscanner.cpp +++ b/src/plugins/scanner/cpp/cppscanner.cpp @@ -173,7 +173,9 @@ static void scanCppFile(void *opaq, Lexer &yylex, bool scanForFileTags, bool sca opaque->hasPluginMetaDataMacro = true; } if (!scanForDependencies && opaque->hasQObjectMacro - && (opaque->fileType == Opaq::FT_CPP || opaque->hasPluginMetaDataMacro)) + && (opaque->hasPluginMetaDataMacro + || opaque->fileType == Opaq::FT_CPP + || opaque->fileType == Opaq::FT_OBJCPP)) break; } } @@ -265,6 +267,7 @@ static const char **additionalFileTags(void *opaq, int *size) *size = 1; switch (opaque->fileType) { case Opaq::FT_CPP: + case Opaq::FT_OBJCPP: return thMocCpp; case Opaq::FT_HPP: return opaque->hasPluginMetaDataMacro ? thMocPluginHpp : thMocHpp; diff --git a/tests/auto/api/testdata/error-in-setup-run-environment/error-in-setup-run-environment.qbs b/tests/auto/api/testdata/error-in-setup-run-environment/error-in-setup-run-environment.qbs new file mode 100644 index 000000000..f3247f6f8 --- /dev/null +++ b/tests/auto/api/testdata/error-in-setup-run-environment/error-in-setup-run-environment.qbs @@ -0,0 +1,5 @@ +import qbs + +CppApplication { + Depends { name: "mymodule" } +} diff --git a/tests/auto/api/testdata/error-in-setup-run-environment/modules/mymodule/mymodule.qbs b/tests/auto/api/testdata/error-in-setup-run-environment/modules/mymodule/mymodule.qbs new file mode 100644 index 000000000..e698b45b5 --- /dev/null +++ b/tests/auto/api/testdata/error-in-setup-run-environment/modules/mymodule/mymodule.qbs @@ -0,0 +1,7 @@ +import qbs + +Module { + setupRunEnvironment: { + trallala + } +} diff --git a/tests/auto/api/testdata/moc-hpp-included/object2.h b/tests/auto/api/testdata/moc-hpp-included/object2.h new file mode 100644 index 000000000..14e811124 --- /dev/null +++ b/tests/auto/api/testdata/moc-hpp-included/object2.h @@ -0,0 +1,13 @@ +#ifndef OBJECT2_H +#define OBJECT2_H +#include <QObject> + +class Object2 : public QObject +{ + Q_OBJECT +public: + Object2(QObject *parent = 0); +}; + +#endif + diff --git a/tests/auto/api/testdata/moc-hpp-included/object2.mm b/tests/auto/api/testdata/moc-hpp-included/object2.mm new file mode 100644 index 000000000..6fd95d31f --- /dev/null +++ b/tests/auto/api/testdata/moc-hpp-included/object2.mm @@ -0,0 +1,16 @@ +#include "object2.h" + +Object2::Object2(QObject *parent) + : QObject(parent) +{} + +#include "moc_object2.cpp" +#include <cstdio> + +int main2() +{ + Object2 obj; + printf("Hello World\n"); + return 0; +} + diff --git a/tests/auto/api/testdata/moc-hpp-included/project.qbs b/tests/auto/api/testdata/moc-hpp-included/project.qbs index d78493b2f..554b0a2b3 100644 --- a/tests/auto/api/testdata/moc-hpp-included/project.qbs +++ b/tests/auto/api/testdata/moc-hpp-included/project.qbs @@ -8,11 +8,11 @@ Project { Depends { name: "Qt.core" } - files : [ "object.cpp" ] + files: ["object.cpp", "object.h"] Group { - files : [ "object.h" ] - fileTags: [ "hpp" ] + condition: qbs.targetOS.contains("darwin") + files: ["object2.mm", "object2.h"] } } } diff --git a/tests/auto/api/testdata/simple-probe/project.qbs b/tests/auto/api/testdata/simple-probe/project.qbs index 9a869c3de..34700a99b 100644 --- a/tests/auto/api/testdata/simple-probe/project.qbs +++ b/tests/auto/api/testdata/simple-probe/project.qbs @@ -16,17 +16,17 @@ CppApplication { found = false; } } + type: ["application"] name: "MyApp" - type: { + consoleApplication: { if (!probe1.found) throw "probe1 not found"; if (probe2.found) throw "probe2 unexpectedly found"; if (probe1.someString !== "one") throw "probe1.someString expected to be \"one\"." - return "application" + return true } - consoleApplication: true files: ["main.cpp"] } diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp index de930a13d..e90237f40 100644 --- a/tests/auto/api/tst_api.cpp +++ b/tests/auto/api/tst_api.cpp @@ -32,6 +32,7 @@ #include "../shared.h" +#include <api/runenvironment.h> #include <qbs.h> #include <tools/fileinfo.h> #include <tools/hostosinfo.h> @@ -828,6 +829,35 @@ void TestApi::enableAndDisableProduct() QVERIFY(!bdr.descriptions.contains("compiling")); } +void TestApi::errorInSetupRunEnvironment() +{ + qbs::SetupProjectParameters setupParams + = defaultSetupParameters("error-in-setup-run-environment/" + "error-in-setup-run-environment.qbs"); + QScopedPointer<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams, + m_logSink, 0)); + waitForFinished(job.data()); + QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString())); + const qbs::Project project = job->project(); + QVERIFY(project.isValid()); + QCOMPARE(project.projectData().products().count(), 1); + const qbs::ProductData product = project.projectData().products().first(); + + bool exceptionCaught = false; + try { + qbs::Settings settings((QString())); + qbs::RunEnvironment runEnv = project.getRunEnvironment(product, qbs::InstallOptions(), + QProcessEnvironment(), &settings); + qbs::ErrorInfo error; + const QProcessEnvironment env = runEnv.runEnvironment(&error); + QVERIFY(error.hasError()); + QVERIFY(error.toString().contains("trallala")); + } catch (const qbs::ErrorInfo &e) { + exceptionCaught = true; + } + QVERIFY(!exceptionCaught); +} + static qbs::ErrorInfo forceRuleEvaluation(const qbs::Project project) { qbs::BuildOptions buildOptions; diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h index 57be0d660..92571781b 100644 --- a/tests/auto/api/tst_api.h +++ b/tests/auto/api/tst_api.h @@ -79,6 +79,7 @@ private slots: void emptyFileTagList(); void emptySubmodulesList(); void enableAndDisableProduct(); + void errorInSetupRunEnvironment(); void explicitlyDependsOn(); void exportSimple(); void exportWithRecursiveDepends(); diff --git a/tests/auto/blackbox/testdata/bundle-structure/bundle-structure.qbs b/tests/auto/blackbox/testdata/bundle-structure/bundle-structure.qbs new file mode 100644 index 000000000..19586522c --- /dev/null +++ b/tests/auto/blackbox/testdata/bundle-structure/bundle-structure.qbs @@ -0,0 +1,167 @@ +import qbs + +Project { + property stringList bundleFileTags: [ + "aggregate_infoplist", "pkginfo", "hpp", + "icns", "resourcerules", "xcent", + "compiled_ibdoc", "compiled_assetcatalog", + "bundle.symlink.headers", "bundle.symlink.private-headers", + "bundle.symlink.resources", "bundle.symlink.executable", + "bundle.symlink.version", "bundle.hpp", "bundle.resource", + ] + + property stringList buildableProducts: ["A", "B", "C", "D", "E", "F", "G"] + + Application { + Depends { name: "cpp" } + Depends { name: "B" } + Depends { name: "C" } + Depends { name: "D" } + condition: buildableProducts.contains("A") + name: "A" + bundle.isBundle: true + bundle.publicHeaders: ["dummy.h"] + bundle.privateHeaders: ["dummy_p.h"] + bundle.resources: ["resource.txt"] + files: ["dummy.c"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } + + Application { + Depends { name: "cpp" } + Depends { name: "B" } + Depends { name: "C" } + Depends { name: "D" } + condition: buildableProducts.contains("ABadApple") + name: "ABadApple" + bundle._productTypeIdentifier: "com.apple.product-type.will.never.exist.ever.guaranteed" + bundle.isBundle: true + bundle.publicHeaders: ["dummy.h"] + bundle.privateHeaders: ["dummy_p.h"] + bundle.resources: ["resource.txt"] + files: ["dummy.c"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } + + Application { + Depends { name: "cpp" } + Depends { name: "B" } + Depends { name: "C" } + Depends { name: "D" } + condition: buildableProducts.contains("ABadThirdParty") + name: "ABadThirdParty" + bundle._productTypeIdentifier: "org.special.third.party.non.existent.product.type" + bundle.isBundle: true + bundle.publicHeaders: ["dummy.h"] + bundle.privateHeaders: ["dummy_p.h"] + bundle.resources: ["resource.txt"] + files: ["dummy.c"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } + + DynamicLibrary { + Depends { name: "cpp" } + condition: buildableProducts.containsAny(["A", "B", "ABadApple", "ABadThirdParty"]) + name: "B" + bundle.isBundle: true + bundle.publicHeaders: ["dummy.h"] + bundle.privateHeaders: ["dummy_p.h"] + bundle.resources: ["resource.txt"] + files: ["dummy.c"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } + + StaticLibrary { + Depends { name: "cpp" } + condition: buildableProducts.containsAny(["A", "C", "ABadApple", "ABadThirdParty"]) + name: "C" + bundle.isBundle: true + bundle.publicHeaders: ["dummy.h"] + bundle.privateHeaders: ["dummy_p.h"] + bundle.resources: ["resource.txt"] + files: ["dummy.c"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } + + LoadableModule { + Depends { name: "cpp" } + condition: buildableProducts.containsAny(["A", "D", "ABadApple", "ABadThirdParty"]) + name: "D" + bundle.isBundle: true + bundle.publicHeaders: ["dummy.h"] + bundle.privateHeaders: ["dummy_p.h"] + bundle.resources: ["resource.txt"] + files: ["dummy.c"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } + + ApplicationExtension { + Depends { name: "cpp" } + condition: buildableProducts.contains("E") + name: "E" + bundle.isBundle: true + bundle.publicHeaders: ["dummy.h"] + bundle.privateHeaders: ["dummy_p.h"] + bundle.resources: ["resource.txt"] + files: ["dummy.c"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } + + XPCService { + Depends { name: "cpp" } + condition: buildableProducts.contains("F") + name: "F" + bundle.isBundle: true + bundle.publicHeaders: ["dummy.h"] + bundle.privateHeaders: ["dummy_p.h"] + bundle.resources: ["resource.txt"] + files: ["dummy.c"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } + + Product { + Depends { name: "bundle" } + condition: buildableProducts.contains("G") + type: ["inapppurchase"] + name: "G" + bundle.isBundle: true + bundle.resources: ["resource.txt"] + Group { + fileTagsFilter: product.type.concat(project.bundleFileTags) + qbs.install: true + qbs.installSourceBase: product.buildDirectory + } + } +} diff --git a/tests/auto/blackbox/testdata/bundle-structure/dummy.c b/tests/auto/blackbox/testdata/bundle-structure/dummy.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/bundle-structure/dummy.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/bundle-structure/dummy.h b/tests/auto/blackbox/testdata/bundle-structure/dummy.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/bundle-structure/dummy.h diff --git a/tests/auto/blackbox/testdata/bundle-structure/dummy_p.h b/tests/auto/blackbox/testdata/bundle-structure/dummy_p.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/bundle-structure/dummy_p.h diff --git a/tests/auto/blackbox/testdata/bundle-structure/resource.txt b/tests/auto/blackbox/testdata/bundle-structure/resource.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/bundle-structure/resource.txt diff --git a/tests/auto/blackbox/testdata/change-in-imported-file/prepare.js b/tests/auto/blackbox/testdata/change-in-imported-file/prepare.js index 8d1b44c61..fa73f0ff1 100644 --- a/tests/auto/blackbox/testdata/change-in-imported-file/prepare.js +++ b/tests/auto/blackbox/testdata/change-in-imported-file/prepare.js @@ -1,3 +1,3 @@ function prepare(cmd) { - cmd.sourceCode = function() { print("old output"); }; + cmd.sourceCode = function() { console.info("old output"); }; } diff --git a/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs b/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs index 672576263..9031890bd 100644 --- a/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs +++ b/tests/auto/blackbox/testdata/concurrent-executor/concurrent-executor.qbs @@ -27,7 +27,7 @@ Product { cmd.createFile = i == 9; cmd.sourceCode = function() { if (createFile) { - print("Creating file"); + console.info("Creating file"); var file = new TextFile(output.filePath, TextFile.WriteOnly); file.close(); } diff --git a/tests/auto/blackbox/testdata/deploymentTarget/deployment.qbs b/tests/auto/blackbox/testdata/deploymentTarget/deployment.qbs new file mode 100644 index 000000000..104bbae81 --- /dev/null +++ b/tests/auto/blackbox/testdata/deploymentTarget/deployment.qbs @@ -0,0 +1,9 @@ +import qbs + +CppApplication { + files: ["main.c"] + cpp.minimumOsxVersion: "10.4" + cpp.minimumIosVersion: "5.0" + cpp.cFlags: ["-v"] + cpp.linkerFlags: ["-v"] +} diff --git a/tests/auto/blackbox/testdata/deploymentTarget/main.c b/tests/auto/blackbox/testdata/deploymentTarget/main.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/deploymentTarget/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/enableExceptions/empty.m b/tests/auto/blackbox/testdata/enableExceptions/empty.m new file mode 100644 index 000000000..d3714dc09 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/empty.m @@ -0,0 +1 @@ +int main2() { return 0; } diff --git a/tests/auto/blackbox/testdata/enableExceptions/empty.mm b/tests/auto/blackbox/testdata/enableExceptions/empty.mm new file mode 100644 index 000000000..fe94a49a3 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/empty.mm @@ -0,0 +1 @@ +int main3() { return 0; } diff --git a/tests/auto/blackbox/testdata/enableExceptions/emptymain.cpp b/tests/auto/blackbox/testdata/enableExceptions/emptymain.cpp new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/emptymain.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions-objc.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objc.qbs new file mode 100644 index 000000000..74738ad12 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objc.qbs @@ -0,0 +1,6 @@ +import qbs + +CppApplication { + files: ["main.m"] + cpp.frameworks: ["Foundation"] +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp-cpp.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp-cpp.qbs new file mode 100644 index 000000000..679cdebbe --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp-cpp.qbs @@ -0,0 +1,6 @@ +import qbs + +CppApplication { + files: ["main.cpp"] + fileTags: ["objcpp"] +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp.qbs new file mode 100644 index 000000000..6856f53bb --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp.qbs @@ -0,0 +1,7 @@ +import qbs + +CppApplication { + files: ["main.m"] + fileTags: ["objcpp"] + cpp.frameworks: ["Foundation"] +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs new file mode 100644 index 000000000..da6fdbc2d --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs @@ -0,0 +1,7 @@ +import qbs + +CppApplication { + files: ["main.cpp"] + cpp.treatWarningsAsErrors: true + cpp.defines: qbs.toolchain.contains("msvc") && !cpp.enableExceptions ? ["FORCE_FAIL_VS"] : [] +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/main.cpp b/tests/auto/blackbox/testdata/enableExceptions/main.cpp new file mode 100644 index 000000000..1b99ea96d --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/main.cpp @@ -0,0 +1,8 @@ +#include <stdexcept> + +int main() { +#ifdef FORCE_FAIL_VS +#error "Microsoft Visual C++ cannot disable exceptions at compile-time" +#endif + throw std::runtime_error("failed"); +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/main.m b/tests/auto/blackbox/testdata/enableExceptions/main.m new file mode 100644 index 000000000..86b45fc37 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/main.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> + +int main() { + @throw [NSError new]; +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/none.qbs b/tests/auto/blackbox/testdata/enableExceptions/none.qbs new file mode 100644 index 000000000..332af7614 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/none.qbs @@ -0,0 +1,10 @@ +import qbs + +CppApplication { + files: ["emptymain.cpp"] + + Group { + condition: qbs.targetOS.contains("darwin") + files: ["empty.m", "empty.mm"] + } +} diff --git a/tests/auto/blackbox/testdata/enableRtti/main.cpp b/tests/auto/blackbox/testdata/enableRtti/main.cpp new file mode 100644 index 000000000..630e75170 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableRtti/main.cpp @@ -0,0 +1,23 @@ +#include <typeinfo> + +class I { +public: + virtual ~I() { } + virtual void x() { } +}; + +class A : public I { + void x() override { } +}; + +class B : public I { + void x() override { } +}; + +int main() { + I *a = new A(); + B *b = dynamic_cast<B *>(a); + (void)b; + delete a; + return 0; +} diff --git a/tests/auto/blackbox/testdata/enableRtti/rtti.qbs b/tests/auto/blackbox/testdata/enableRtti/rtti.qbs new file mode 100644 index 000000000..f032bb16b --- /dev/null +++ b/tests/auto/blackbox/testdata/enableRtti/rtti.qbs @@ -0,0 +1,13 @@ +import qbs + +Project { + property bool treatAsObjcpp: false + CppApplication { + cpp.cxxLanguageVersion: "c++11" + cpp.treatWarningsAsErrors: true + Group { + files: ["main.cpp"] + fileTags: [project.treatAsObjcpp ? "objcpp" : "cpp"] + } + } +} diff --git a/tests/auto/blackbox/testdata/error-info/helper.js b/tests/auto/blackbox/testdata/error-info/helper.js new file mode 100644 index 000000000..18323df4a --- /dev/null +++ b/tests/auto/blackbox/testdata/error-info/helper.js @@ -0,0 +1,9 @@ +var x; + +function doSomethingBad() { + nothinghere.works; +} + +function doSomethingEvil() { + throw "OUCH!"; +} diff --git a/tests/auto/blackbox/testdata/error-info/project.qbs b/tests/auto/blackbox/testdata/error-info/project.qbs new file mode 100644 index 000000000..f2c65597f --- /dev/null +++ b/tests/auto/blackbox/testdata/error-info/project.qbs @@ -0,0 +1,71 @@ +import qbs +import "helper.js" as Helper + +Project { + property bool fail1: false + property bool fail2: false + property bool fail3: false + property bool fail4: false + property bool fail5: false + property bool fail6: false + property bool fail7: false + + Product { + type: ["foo", "bar"] + + Rule { + inputs: ["qbs"] + + Artifact { + fileTags: ["foo"] + filePath: { + var path = "foo"; + if (project.fail1) + throw "fail1"; + return path; + } + } + + prepare: { + var cmd = new JavaScriptCommand(); + cmd.sourceCode = function () { + + }; + cmd.silent = true; + if (project.fail2) + generate.an.error; + if (project.fail6) + Helper.doSomethingEvil(); + return cmd; + } + } + + Rule { + inputs: ["qbs"] + + outputFileTags: ["bar"] + outputArtifacts: { + var list = []; + list.push({ fileTags: ["bar"], filePath: "bar" }); + if (project.fail3) + throw "fail3"; + if (project.fail5) + Helper.doSomethingBad(); + return list; + } + + prepare: { + var cmd = new JavaScriptCommand(); + cmd.fail7 = project.fail7; + cmd.sourceCode = function () { + if (fail7) + will.fail; + }; + cmd.silent = true; + if (project.fail4) + generate.an.error; + return cmd; + } + } + } +} diff --git a/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs b/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs index 1f3bf010c..4423d68e0 100644 --- a/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs +++ b/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs @@ -20,7 +20,7 @@ DynamicLibrary { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { - print("---" + product.moduleProperty("cpp", "nmPath") + "---"); + console.info("---" + product.moduleProperty("cpp", "nmPath") + "---"); } return [cmd]; } diff --git a/tests/auto/blackbox/testdata/nodejs/hello.qbs b/tests/auto/blackbox/testdata/nodejs/hello.qbs index e11b1a599..d5e92209a 100644 --- a/tests/auto/blackbox/testdata/nodejs/hello.qbs +++ b/tests/auto/blackbox/testdata/nodejs/hello.qbs @@ -3,5 +3,4 @@ import qbs NodeJSApplication { nodejs.applicationFile: "hello.js" name: "hello" - files: "hello.js" } diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/dependee.qbs b/tests/auto/blackbox/testdata/probe-in-exported-module/dependee.qbs new file mode 100644 index 000000000..94e266499 --- /dev/null +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/dependee.qbs @@ -0,0 +1,15 @@ +import qbs + +Product { + name: "dependee" + Depends { name: "dependency" } + type: ["out", "dep-out"] + Group { + files: "test.in" + fileTags: ["dep-in"] + } + Group { + files: "test2.in" + fileTags: ["in"] + } +} diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/dependency.qbs b/tests/auto/blackbox/testdata/probe-in-exported-module/dependency.qbs new file mode 100644 index 000000000..1413777dc --- /dev/null +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/dependency.qbs @@ -0,0 +1,8 @@ +import qbs + +Product { + name: "dependency" + Export { + Depends { name: "mymodule" } + } +} diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/depmodule.qbs b/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/depmodule.qbs new file mode 100644 index 000000000..b477e2bf7 --- /dev/null +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/modules/depmodule/depmodule.qbs @@ -0,0 +1,21 @@ +import qbs + +Module { + property string prop + + Rule { + inputs: ["dep-in"] + Artifact { + filePath: "dummy.txt" + fileTags: ["dep-out"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "Creating dep-out artifact"; + cmd.sourceCode = function() { + console.info("prop: " + product.moduleProperty("depmodule", "prop")); + }; + return [cmd]; + } + } +} diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/mymodule.qbs b/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/mymodule.qbs new file mode 100644 index 000000000..af1c33049 --- /dev/null +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/modules/mymodule/mymodule.qbs @@ -0,0 +1,27 @@ +import qbs + +Module { + Depends { name: "depmodule" } + Probe { + id: theProbe + configure: { found = true; } + } + property bool found: theProbe.found + depmodule.prop: found ? "yes" : "no" + + Rule { + inputs: ["in"] + Artifact { + filePath: "dummy2.txt" + fileTags: ["out"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "Creating out artifact"; + cmd.sourceCode = function() { + console.info("found: " + product.moduleProperty("mymodule", "found")); + }; + return [cmd]; + } + } +} diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/probe-in-exported-module.qbs b/tests/auto/blackbox/testdata/probe-in-exported-module/probe-in-exported-module.qbs new file mode 100644 index 000000000..4e0f13f60 --- /dev/null +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/probe-in-exported-module.qbs @@ -0,0 +1,5 @@ +import qbs + +Project { + references: [ "dependee.qbs", "dependency.qbs" ] +} diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/test.in b/tests/auto/blackbox/testdata/probe-in-exported-module/test.in new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/test.in diff --git a/tests/auto/blackbox/testdata/probe-in-exported-module/test2.in b/tests/auto/blackbox/testdata/probe-in-exported-module/test2.in new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/probe-in-exported-module/test2.in diff --git a/tests/auto/blackbox/testdata/probeProperties/bin/tool b/tests/auto/blackbox/testdata/probeProperties/bin/tool new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/probeProperties/bin/tool diff --git a/tests/auto/blackbox/testdata/probeProperties/main.c b/tests/auto/blackbox/testdata/probeProperties/main.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/probeProperties/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs b/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs new file mode 100644 index 000000000..36842e40b --- /dev/null +++ b/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs @@ -0,0 +1,30 @@ +import qbs +import qbs.Probes + +CppApplication { + Probes.PathProbe { + id: probe1 + names: ["bin/tool"] + platformPaths: [product.sourceDirectory] + } + + Probes.PathProbe { + id: probe2 + names: ["tool"] + platformPaths: [product.sourceDirectory + "/bin"] + } + + targetName: { + console.info("probe1.fileName=" + probe1.fileName); + console.info("probe1.path=" + probe1.path); + console.info("probe1.filePath=" + probe1.filePath); + + console.info("probe2.fileName=" + probe2.fileName); + console.info("probe2.path=" + probe2.path); + console.info("probe2.filePath=" + probe2.filePath); + + return name; + } + + files: ["main.c"] +} diff --git a/tests/auto/blackbox/testdata/referenceErrorInExport/main.c b/tests/auto/blackbox/testdata/referenceErrorInExport/main.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/referenceErrorInExport/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/referenceErrorInExport/project.qbs b/tests/auto/blackbox/testdata/referenceErrorInExport/project.qbs new file mode 100644 index 000000000..91069f629 --- /dev/null +++ b/tests/auto/blackbox/testdata/referenceErrorInExport/project.qbs @@ -0,0 +1,20 @@ +import qbs + +Project { + CppApplication { + Depends { name: "other" } + files: ["main.c"] + cpp.includePaths: ["."] + } + + DynamicLibrary { + name: "other" + files: ["main.c"] + + property stringList includePaths: [] + Export { + Depends { name: "cpp" } + cpp.includePaths: includePaths + } + } +} diff --git a/tests/auto/blackbox/testdata/separate-debug-info/project.qbs b/tests/auto/blackbox/testdata/separate-debug-info/project.qbs index 0939f7227..c0498df3d 100644 --- a/tests/auto/blackbox/testdata/separate-debug-info/project.qbs +++ b/tests/auto/blackbox/testdata/separate-debug-info/project.qbs @@ -20,6 +20,7 @@ Project { files: ["foo.cpp"] cpp.separateDebugInformation: true } + CppApplication { name: "app2" type: ["application"] @@ -39,4 +40,76 @@ Project { files: ["foo.cpp"] cpp.separateDebugInformation: false } + + CppApplication { + name: "app3" + type: ["application"] + files: ["main.cpp"] + cpp.separateDebugInformation: true + cpp.dsymutilFlags: ["--flat"] + } + DynamicLibrary { + Depends { name: "cpp" } + name: "foo3" + type: ["dynamiclibrary"] + files: ["foo.cpp"] + cpp.separateDebugInformation: true + cpp.dsymutilFlags: ["--flat"] + } + LoadableModule { + Depends { name: "cpp" } + name: "bar3" + files: ["foo.cpp"] + cpp.separateDebugInformation: true + cpp.dsymutilFlags: ["--flat"] + } + + CppApplication { + name: "app4" + type: ["application"] + files: ["main.cpp"] + bundle.isBundle: false + cpp.separateDebugInformation: true + } + DynamicLibrary { + Depends { name: "cpp" } + name: "foo4" + type: ["dynamiclibrary"] + files: ["foo.cpp"] + bundle.isBundle: false + cpp.separateDebugInformation: true + } + LoadableModule { + Depends { name: "cpp" } + name: "bar4" + files: ["foo.cpp"] + bundle.isBundle: false + cpp.separateDebugInformation: true + } + + CppApplication { + name: "app5" + type: ["application"] + files: ["main.cpp"] + bundle.isBundle: false + cpp.separateDebugInformation: true + cpp.dsymutilFlags: ["--flat"] + } + DynamicLibrary { + Depends { name: "cpp" } + name: "foo5" + type: ["dynamiclibrary"] + files: ["foo.cpp"] + bundle.isBundle: false + cpp.separateDebugInformation: true + cpp.dsymutilFlags: ["--flat"] + } + LoadableModule { + Depends { name: "cpp" } + name: "bar5" + files: ["foo.cpp"] + bundle.isBundle: false + cpp.separateDebugInformation: true + cpp.dsymutilFlags: ["--flat"] + } } diff --git a/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js b/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js index c3dfe2b11..159a7d32a 100644 --- a/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js +++ b/tests/auto/blackbox/testdata/trackExternalProductChanges/fileList.js @@ -1,4 +1,4 @@ function fileList() { return []; } -function filesFromFs(qbs) { return File.exists(path + "/fileExists.cpp") ? ["fileExists.cpp"] : []; } +function filesFromFs(path) { return File.exists(path + "/fileExists.cpp") ? ["fileExists.cpp"] : []; } diff --git a/tests/auto/blackbox/testdata/trackExternalProductChanges/project.qbs b/tests/auto/blackbox/testdata/trackExternalProductChanges/project.qbs index 05060acd7..e99d6b350 100644 --- a/tests/auto/blackbox/testdata/trackExternalProductChanges/project.qbs +++ b/tests/auto/blackbox/testdata/trackExternalProductChanges/project.qbs @@ -6,7 +6,7 @@ import "fileList.js" as FileList CppApplication { property stringList filesFromEnv: Environment.getEnv("QBS_TEST_PULL_IN_FILE_VIA_ENV") ? ["environmentChange.cpp"] : [] - files: ["main.cpp"].concat(FileList.fileList()).concat(filesFromEnv).concat(FileList.filesFromFs(qbs)) + files: ["main.cpp"].concat(FileList.fileList()).concat(filesFromEnv).concat(FileList.filesFromFs(path)) Group { condition: Environment.getEnv("INCLUDE_PATH_TEST") diff --git a/tests/auto/blackbox/testdata/typescript/typescript.qbs b/tests/auto/blackbox/testdata/typescript/typescript.qbs index 1b4c675c3..d15e9db50 100644 --- a/tests/auto/blackbox/testdata/typescript/typescript.qbs +++ b/tests/auto/blackbox/testdata/typescript/typescript.qbs @@ -15,8 +15,7 @@ Project { files: [ "animals.ts", "extra.js", - "woosh/extra.ts", - "main.ts" + "woosh/extra.ts" ] } diff --git a/tests/auto/blackbox/testdata/versionscript/versionscript.qbs b/tests/auto/blackbox/testdata/versionscript/versionscript.qbs index f845f2457..56260a022 100644 --- a/tests/auto/blackbox/testdata/versionscript/versionscript.qbs +++ b/tests/auto/blackbox/testdata/versionscript/versionscript.qbs @@ -20,7 +20,7 @@ DynamicLibrary { var cmd = new JavaScriptCommand(); cmd.silent = true; cmd.sourceCode = function() { - print("---" + product.moduleProperty("cpp", "nmPath") + "---"); + console.info("---" + product.moduleProperty("cpp", "nmPath") + "---"); } return [cmd]; } diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index d58d70b00..0c20eb1c9 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -327,14 +327,12 @@ void TestBlackbox::sevenZip() const QString outputFile = relativeProductBuildDir("archivable") + "/archivable.7z"; QVERIFY2(regularFileExists(outputFile), qPrintable(outputFile)); QProcess listContents; - listContents.start(binary, QStringList() << "t" << outputFile); + listContents.start(binary, QStringList() << "l" << outputFile); QVERIFY2(listContents.waitForStarted(), qPrintable(listContents.errorString())); QVERIFY2(listContents.waitForFinished(), qPrintable(listContents.errorString())); QVERIFY2(listContents.exitCode() == 0, listContents.readAllStandardError().constData()); const QByteArray output = listContents.readAllStandardOutput(); - if (output.count("Testing") != 2) - qDebug("%s", output.constData()); - QCOMPARE(output.count("Testing"), 2); + QVERIFY2(output.contains("2 files"), output.constData()); QVERIFY2(output.contains("test.txt"), output.constData()); QVERIFY2(output.contains("archivable.qbs"), output.constData()); } @@ -462,6 +460,12 @@ void TestBlackbox::android() int status; const auto androidPaths = findAndroid(&status); + const auto ndkPath = androidPaths["ndk"]; + static const QStringList ndkSamplesDirs = QStringList() << "teapot" << "no-native"; + if (!ndkPath.isEmpty() && !QFileInfo(ndkPath + "/samples").isDir() + && ndkSamplesDirs.contains(projectDir)) + QSKIP("NDK samples directory not present"); + QDir::setCurrent(testDataDir + "/android/" + projectDir); Settings s((QString())); Profile p("qbs_autotests-android", &s); @@ -520,6 +524,254 @@ void TestBlackbox::buildDirectories() QVERIFY2(outputLines.contains(projectDir), m_qbsStdout.constData()); } +class QFileInfo2 : public QFileInfo { +public: + QFileInfo2(const QString &path) : QFileInfo(path) { } + bool isRegularFile() const { return isFile() && !isSymLink(); } + bool isRegularDir() const { return isDir() && !isSymLink(); } + bool isFileSymLink() const { return isFile() && isSymLink(); } + bool isDirSymLink() const { return isDir() && isSymLink(); } +}; + +void TestBlackbox::bundleStructure() +{ + if (!HostOsInfo::isOsxHost()) + QSKIP("only applies on OS X"); + + QFETCH(QString, productName); + QFETCH(QString, productTypeIdentifier); + QFETCH(bool, isShallow); + + QDir::setCurrent(testDataDir + "/bundle-structure"); + QbsRunParameters params; + params.arguments << "project.buildableProducts:" + productName; + if (isShallow) { + // Coerce shallow bundles - don't set bundle.isShallow directly because we want to test the + // automatic detection + params.arguments + << "qbs.targetOS:ios,darwin,bsd,unix" + << "qbs.architecture:arm64"; + } + + if (productName == "ABadApple" || productName == "ABadThirdParty") + params.expectFailure = true; + + rmDirR(relativeBuildDir()); + const int status = runQbs(params); + if (status != 0) { + QVERIFY2(m_qbsStderr.contains("Bundle product type " + + productTypeIdentifier.toLatin1() + + " is not supported."), + m_qbsStderr.constData()); + return; + } + + QCOMPARE(status, 0); + + if (!isShallow) { + if (productName == "A") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/MacOS").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/MacOS/A").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/PkgInfo").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Resources").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Resources/resource.txt").isRegularFile()); + } + + if (productName == "B") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/B").isFileSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers").isDirSymLink()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules").isDirSymLink()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/B.framework/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders").isDirSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Resources").isDirSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/B").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Headers").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Headers/dummy.h").isRegularFile()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Modules").isRegularDir()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Modules/module.modulemap").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/PrivateHeaders").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/PrivateHeaders/dummy_p.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Resources").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Resources/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/Current").isDirSymLink()); + } + + if (productName == "C") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/C").isFileSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers").isDirSymLink()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules").isDirSymLink()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/C.framework/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders").isDirSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Resources").isDirSymLink()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/C").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Headers").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Headers/dummy.h").isRegularFile()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Modules").isRegularDir()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Modules/module.modulemap").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/PrivateHeaders").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/PrivateHeaders/dummy_p.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Resources").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Resources/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/Current").isDirSymLink()); + } + + if (productName == "D") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/MacOS").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/MacOS/D").isRegularFile()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Resources").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Resources/resource.txt").isRegularFile()); + } + + if (productName == "E") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/MacOS").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/MacOS/E").isRegularFile()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/E.appex/Contents/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Resources").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Resources/resource.txt").isRegularFile()); + } + + if (productName == "F") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/MacOS").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/MacOS/F").isRegularFile()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Resources").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Resources/resource.txt").isRegularFile()); + } + + if (productName == "G") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/G").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile()); + } + } else { + if (productName == "A") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/A").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Info.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/PkgInfo").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/resource.txt").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/ResourceRules.plist").isRegularFile()); + } + + if (productName == "B") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/B").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers/dummy.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Info.plist").isRegularFile()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules").isRegularDir()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules/module.modulemap").isRegularFile()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/B.framework/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders/dummy_p.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/resource.txt").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/ResourceRules.plist").isRegularFile()); + } + + if (productName == "C") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/C").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers/dummy.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Info.plist").isRegularFile()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules").isRegularDir()); + //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules/module.modulemap").isRegularFile()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/C.framework/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders/dummy_p.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/resource.txt").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/ResourceRules.plist").isRegularFile()); + } + + if (productName == "D") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/D").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Headers").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Headers/dummy.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Info.plist").isRegularFile()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/D.bundle/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/PrivateHeaders").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/PrivateHeaders/dummy_p.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/resource.txt").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/ResourceRules.plist").isRegularFile()); + } + + if (productName == "E") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/E").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Headers").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Headers/dummy.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Info.plist").isRegularFile()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/E.appex/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/PrivateHeaders").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/PrivateHeaders/dummy_p.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/resource.txt").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/ResourceRules.plist").isRegularFile()); + } + + if (productName == "F") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/F").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Headers").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Headers/dummy.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Info.plist").isRegularFile()); + QVERIFY(!QFileInfo2(defaultInstallRoot + "/F.xpc/PkgInfo").exists()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/PrivateHeaders").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/PrivateHeaders/dummy_p.h").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/resource.txt").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/ResourceRules.plist").isRegularFile()); + } + + if (productName == "G") { + QVERIFY(QFileInfo2(defaultInstallRoot + "/G").isRegularDir()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile()); + QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile()); + } + } +} + +void TestBlackbox::bundleStructure_data() +{ + QTest::addColumn<QString>("productName"); + QTest::addColumn<QString>("productTypeIdentifier"); + QTest::addColumn<bool>("isShallow"); + + const auto addRows = [](bool isShallow) { + const QString s = (isShallow ? " shallow" : ""); + QTest::newRow(("A" + s).toLatin1()) << "A" << "com.apple.product-type.application" << isShallow; + QTest::newRow(("ABadApple" + s).toLatin1()) << "ABadApple" << "com.apple.product-type.will.never.exist.ever.guaranteed" << isShallow; + QTest::newRow(("ABadThirdParty" + s).toLatin1()) << "ABadThirdParty" << "org.special.third.party.non.existent.product.type" << isShallow; + QTest::newRow(("B" + s).toLatin1()) << "B" << "com.apple.product-type.framework" << isShallow; + QTest::newRow(("C" + s).toLatin1()) << "C" << "com.apple.product-type.framework.static" << isShallow; + QTest::newRow(("D" + s).toLatin1()) << "D" << "com.apple.product-type.bundle" << isShallow; + QTest::newRow(("E" + s).toLatin1()) << "E" << "com.apple.product-type.app-extension" << isShallow; + QTest::newRow(("F" + s).toLatin1()) << "F" << "com.apple.product-type.xpc-service" << isShallow; + QTest::newRow(("G" + s).toLatin1()) << "G" << "com.apple.product-type.in-app-purchase-content" << isShallow; + }; + + addRows(true); + addRows(false); +} + void TestBlackbox::changedFiles_data() { QTest::addColumn<bool>("useChangedFilesForInitialBuild"); @@ -575,7 +827,7 @@ void TestBlackbox::changeInImportedFile() { QDir::setCurrent(testDataDir + "/change-in-imported-file"); QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStderr.contains("old output"), m_qbsStderr.constData()); + QVERIFY2(m_qbsStdout.contains("old output"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); QFile jsFile("prepare.js"); @@ -586,7 +838,7 @@ void TestBlackbox::changeInImportedFile() jsFile.write(content); jsFile.close(); QCOMPARE(runQbs(), 0); - QVERIFY2(m_qbsStderr.contains("new output"), m_qbsStderr.constData()); + QVERIFY2(m_qbsStdout.contains("new output"), m_qbsStdout.constData()); WAIT_FOR_NEW_TIMESTAMP(); QVERIFY2(jsFile.open(QIODevice::ReadWrite), qPrintable(jsFile.errorString())); @@ -594,7 +846,7 @@ void TestBlackbox::changeInImportedFile() jsFile.write(content); jsFile.close(); QCOMPARE(runQbs(), 0); - QVERIFY2(!m_qbsStderr.contains("output"), m_qbsStderr.constData()); + QVERIFY2(!m_qbsStdout.contains("output"), m_qbsStdout.constData()); } void TestBlackbox::dependenciesProperty() @@ -662,6 +914,48 @@ void TestBlackbox::dependencyProfileMismatch() m_qbsStderr.constData()); } +void TestBlackbox::deploymentTarget() +{ + if (!HostOsInfo::isOsxHost()) + QSKIP("only applies on OS X"); + + QFETCH(QString, os); + QFETCH(QString, arch); + QFETCH(QString, cflags); + QFETCH(QString, lflags); + + QDir::setCurrent(testDataDir + "/deploymentTarget"); + + QbsRunParameters params; + params.arguments = QStringList() + << "--command-echo-mode" + << "command-line" + << "qbs.targetOS:" + os + << "qbs.architecture:" + arch; + + rmDirR(relativeBuildDir()); + QCOMPARE(runQbs(params), 0); + QVERIFY2(m_qbsStdout.contains(cflags.toLatin1()), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains(lflags.toLatin1()), m_qbsStdout.constData()); +} + +void TestBlackbox::deploymentTarget_data() +{ + QTest::addColumn<QString>("os"); + QTest::addColumn<QString>("arch"); + QTest::addColumn<QString>("cflags"); + QTest::addColumn<QString>("lflags"); + QTest::newRow("osx") << "osx,darwin,bsd,unix" << "x86_64" + << "-triple x86_64-apple-macosx10.4" + << "-macosx_version_min 10.4"; + QTest::newRow("ios") << "ios,darwin,bsd,unix" << "arm64" + << "-triple arm64-apple-ios5.0" + << "-iphoneos_version_min 5.0"; + QTest::newRow("ios-sim") << "ios-simulator,ios,darwin,bsd,unix" << "x86_64" + << "-triple x86_64-apple-ios5.0" + << "-ios_simulator_version_min 5.0"; +} + void TestBlackbox::symlinkRemoval() { if (HostOsInfo::isWindowsHost()) @@ -699,7 +993,7 @@ void TestBlackbox::versionScript() QDir::setCurrent(testDataDir + "/versionscript"); QCOMPARE(runQbs(QbsRunParameters(QStringList("-qq") << ("qbs.installRoot:" + QDir::currentPath()))), 0); - const QString output = QString::fromLocal8Bit(m_qbsStderr); + const QString output = QString::fromLocal8Bit(m_qbsStdout); QRegExp pattern(".*---(.*)---.*"); QVERIFY2(pattern.exactMatch(output), qPrintable(output)); QCOMPARE(pattern.captureCount(), 1); @@ -861,12 +1155,69 @@ void TestBlackbox::separateDebugInfo() QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList(); QStringList targetOS = buildProfile.value("qbs.targetOS").toStringList(); if (targetOS.contains("darwin") || (targetOS.isEmpty() && HostOsInfo::isOsxHost())) { - QVERIFY(QFile::exists(relativeProductBuildDir("app1") + "/app1.app.dSYM")); + QVERIFY(directoryExists(relativeProductBuildDir("app1") + "/app1.app.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("app1") + + "/app1.app.dSYM/Contents/Info.plist")); + QVERIFY(regularFileExists(relativeProductBuildDir("app1") + + "/app1.app.dSYM/Contents/Resources/DWARF/app1")); + QCOMPARE(QDir(relativeProductBuildDir("app1") + + "/app1.app.dSYM/Contents/Resources/DWARF") + .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); QVERIFY(!QFile::exists(relativeProductBuildDir("app2") + "/app2.app.dSYM")); - QVERIFY(QFile::exists(relativeProductBuildDir("foo1") + "/foo1.framework.dSYM")); + QVERIFY(!QFile::exists(relativeProductBuildDir("app3") + "/app3.app.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("app3") + + "/app3.app/Contents/MacOS/app3.dwarf")); + QVERIFY(directoryExists(relativeProductBuildDir("app4") + "/app4.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("app4") + + "/app4.dSYM/Contents/Info.plist")); + QVERIFY(regularFileExists(relativeProductBuildDir("app4") + + "/app4.dSYM/Contents/Resources/DWARF/app4")); + QCOMPARE(QDir(relativeProductBuildDir("app4") + + "/app4.dSYM/Contents/Resources/DWARF") + .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); + QVERIFY(regularFileExists(relativeProductBuildDir("app5") + "/app5.dwarf")); + QVERIFY(directoryExists(relativeProductBuildDir("foo1") + "/foo1.framework.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("foo1") + + "/foo1.framework.dSYM/Contents/Info.plist")); + QVERIFY(regularFileExists(relativeProductBuildDir("foo1") + + "/foo1.framework.dSYM/Contents/Resources/DWARF/foo1")); + QCOMPARE(QDir(relativeProductBuildDir("foo1") + + "/foo1.framework.dSYM/Contents/Resources/DWARF") + .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); QVERIFY(!QFile::exists(relativeProductBuildDir("foo2") + "/foo2.framework.dSYM")); - QVERIFY(QFile::exists(relativeProductBuildDir("bar1") + "/bar1.bundle.dSYM")); + QVERIFY(!QFile::exists(relativeProductBuildDir("foo3") + "/foo3.framework.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("foo3") + + "/foo3.framework/Versions/A/foo3.dwarf")); + QVERIFY(directoryExists(relativeProductBuildDir("foo4") + "/libfoo4.dylib.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("foo4") + + "/libfoo4.dylib.dSYM/Contents/Info.plist")); + QVERIFY(regularFileExists(relativeProductBuildDir("foo4") + + "/libfoo4.dylib.dSYM/Contents/Resources/DWARF/libfoo4.dylib")); + QCOMPARE(QDir(relativeProductBuildDir("foo4") + + "/libfoo4.dylib.dSYM/Contents/Resources/DWARF") + .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); + QVERIFY(regularFileExists(relativeProductBuildDir("foo5") + "/libfoo5.dylib.dwarf")); + QVERIFY(directoryExists(relativeProductBuildDir("bar1") + "/bar1.bundle.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("bar1") + + "/bar1.bundle.dSYM/Contents/Info.plist")); + QVERIFY(regularFileExists(relativeProductBuildDir("bar1") + + "/bar1.bundle.dSYM/Contents/Resources/DWARF/bar1")); + QCOMPARE(QDir(relativeProductBuildDir("bar1") + + "/bar1.bundle.dSYM/Contents/Resources/DWARF") + .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); QVERIFY(!QFile::exists(relativeProductBuildDir("bar2") + "/bar2.bundle.dSYM")); + QVERIFY(!QFile::exists(relativeProductBuildDir("bar3") + "/bar3.bundle.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("bar3") + + "/bar3.bundle/Contents/MacOS/bar3.dwarf")); + QVERIFY(directoryExists(relativeProductBuildDir("bar4") + "/bar4.bundle.dSYM")); + QVERIFY(regularFileExists(relativeProductBuildDir("bar4") + + "/bar4.bundle.dSYM/Contents/Info.plist")); + QVERIFY(regularFileExists(relativeProductBuildDir("bar4") + + "/bar4.bundle.dSYM/Contents/Resources/DWARF/bar4.bundle")); + QCOMPARE(QDir(relativeProductBuildDir("bar4") + + "/bar4.bundle.dSYM/Contents/Resources/DWARF") + .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).size(), 1); + QVERIFY(regularFileExists(relativeProductBuildDir("bar5") + "/bar5.bundle.dwarf")); } else if (toolchain.contains("gcc")) { QVERIFY(QFile::exists(relativeProductBuildDir("app1") + "/app1.debug")); QVERIFY(!QFile::exists(relativeProductBuildDir("app2") + "/app2.debug")); @@ -1301,6 +1652,17 @@ void TestBlackbox::recursiveWildcards() QVERIFY(QFileInfo(defaultInstallRoot + "/dir/file2.txt").exists()); } +void TestBlackbox::referenceErrorInExport() +{ + QDir::setCurrent(testDataDir + "/referenceErrorInExport"); + QbsRunParameters params; + params.expectFailure = true; + QVERIFY(runQbs(params) != 0); + QEXPECT_FAIL(0, "QBS-946", Abort); + QVERIFY(m_qbsStderr.contains( + "project.qbs:17:31 ReferenceError: Can't find variable: includePaths")); +} + void TestBlackbox::reproducibleBuild() { Settings s((QString())); @@ -1384,6 +1746,29 @@ void TestBlackbox::overrideProjectProperties() QCOMPARE(runQbs(params), 0); } +void TestBlackbox::probeProperties() +{ + QDir::setCurrent(testDataDir + "/probeProperties"); + const QByteArray dir = QDir::cleanPath(testDataDir).toLatin1() + "/probeProperties"; + QCOMPARE(runQbs(), 0); + QVERIFY2(m_qbsStdout.contains("probe1.fileName=bin/tool"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("probe1.path=" + dir), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("probe1.filePath=" + dir + "/bin/tool"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("probe2.fileName=tool"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("probe2.path=" + dir + "/bin"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("probe2.filePath=" + dir + "/bin/tool"), m_qbsStdout.constData()); +} + +void TestBlackbox::probeInExportedModule() +{ + QDir::setCurrent(testDataDir + "/probe-in-exported-module"); + QCOMPARE(runQbs(QbsRunParameters(QStringList() << QLatin1String("-f") + << QLatin1String("probe-in-exported-module.qbs"))), 0); + QVERIFY2(m_qbsStdout.contains("found: true"), m_qbsStdout.constData()); + QEXPECT_FAIL(0, "QBS-955", Abort); + QVERIFY2(m_qbsStdout.contains("prop: yes"), m_qbsStdout.constData()); +} + void TestBlackbox::productProperties() { QDir::setCurrent(testDataDir + "/productproperties"); @@ -1713,6 +2098,44 @@ void TestBlackbox::erroneousFiles() } } +void TestBlackbox::errorInfo() +{ + QDir::setCurrent(testDataDir + "/error-info"); + QCOMPARE(runQbs(), 0); + + QbsRunParameters params; + params.expectFailure = true; + + params.arguments = QStringList() << "project.fail1:true"; + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("project.qbs:24"), m_qbsStderr); + + params.arguments = QStringList() << "project.fail2:true"; + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("project.qbs:36"), m_qbsStderr); + + params.arguments = QStringList() << "project.fail3:true"; + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("project.qbs:51"), m_qbsStderr); + + params.arguments = QStringList() << "project.fail4:true"; + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("project.qbs:66"), m_qbsStderr); + + params.arguments = QStringList() << "project.fail5:true"; + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("helper.js:4"), m_qbsStderr); + + params.arguments = QStringList() << "project.fail6:true"; + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("helper.js:8"), m_qbsStderr); + + params.arguments = QStringList() << "project.fail7:true"; + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("JavaScriptCommand.sourceCode"), m_qbsStderr); + QVERIFY2(m_qbsStderr.contains("project.qbs:57"), m_qbsStderr); +} + void TestBlackbox::exportRule() { QDir::setCurrent(testDataDir + "/export-rule"); @@ -2087,7 +2510,7 @@ void TestBlackbox::linkerScripts() QDir::setCurrent(testDataDir + "/linkerscripts"); QCOMPARE(runQbs(QbsRunParameters(QStringList("-qq") << ("qbs.installRoot:" + QDir::currentPath()))), 0); - const QString output = QString::fromLocal8Bit(m_qbsStderr); + const QString output = QString::fromLocal8Bit(m_qbsStdout); QRegExp pattern(".*---(.*)---.*"); QVERIFY2(pattern.exactMatch(output), qPrintable(output)); QCOMPARE(pattern.captureCount(), 1); @@ -2760,12 +3183,12 @@ void TestBlackbox::assembly() bool haveMSVC = profile.value("qbs.toolchain").toStringList().contains("msvc"); QDir::setCurrent(testDataDir + "/assembly"); QVERIFY(runQbs() == 0); - QCOMPARE((bool)m_qbsStdout.contains("assembling testa.s"), haveGcc); - QCOMPARE((bool)m_qbsStdout.contains("compiling testb.S"), haveGcc); - QCOMPARE((bool)m_qbsStdout.contains("compiling testc.sx"), haveGcc); - QCOMPARE((bool)m_qbsStdout.contains("creating libtesta.a"), haveGcc); - QCOMPARE((bool)m_qbsStdout.contains("creating libtestb.a"), haveGcc); - QCOMPARE((bool)m_qbsStdout.contains("creating libtestc.a"), haveGcc); + QCOMPARE(m_qbsStdout.contains("assembling testa.s"), haveGcc); + QCOMPARE(m_qbsStdout.contains("compiling testb.S"), haveGcc); + QCOMPARE(m_qbsStdout.contains("compiling testc.sx"), haveGcc); + QCOMPARE(m_qbsStdout.contains("creating libtesta.a"), haveGcc); + QCOMPARE(m_qbsStdout.contains("creating libtestb.a"), haveGcc); + QCOMPARE(m_qbsStdout.contains("creating libtestc.a"), haveGcc); QCOMPARE(m_qbsStdout.contains("creating testd.lib"), haveMSVC); } @@ -2841,6 +3264,76 @@ void TestBlackbox::embedInfoPlist() QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/mod.bundle").isEmpty()); } +void TestBlackbox::enableExceptions() +{ + QFETCH(QString, file); + QFETCH(bool, enable); + QFETCH(bool, expectSuccess); + + QDir::setCurrent(testDataDir + QStringLiteral("/enableExceptions")); + + QbsRunParameters params; + params.arguments = QStringList() << "-f" << file << (QStringLiteral("cpp.enableExceptions:") + + (enable ? "true" : "false")); + params.expectFailure = !expectSuccess; + rmDirR(relativeBuildDir()); + if (!params.expectFailure) + QCOMPARE(runQbs(params), 0); + else + QVERIFY(runQbs(params) != 0); +} + +void TestBlackbox::enableExceptions_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<bool>("enable"); + QTest::addColumn<bool>("expectSuccess"); + + QTest::newRow("no exceptions, enabled") << "none.qbs" << true << true; + QTest::newRow("no exceptions, disabled") << "none.qbs" << false << true; + + QTest::newRow("C++ exceptions, enabled") << "exceptions.qbs" << true << true; + QTest::newRow("C++ exceptions, disabled") << "exceptions.qbs" << false << false; + + if (HostOsInfo::isOsxHost()) { + QTest::newRow("Objective-C exceptions, enabled") << "exceptions-objc.qbs" << true << true; + QTest::newRow("Objective-C exceptions in Objective-C++ source, enabled") << "exceptions-objcpp.qbs" << true << true; + QTest::newRow("C++ exceptions in Objective-C++ source, enabled") << "exceptions-objcpp-cpp.qbs" << true << true; + QTest::newRow("Objective-C, disabled") << "exceptions-objc.qbs" << false << false; + QTest::newRow("Objective-C exceptions in Objective-C++ source, disabled") << "exceptions-objcpp.qbs" << false << false; + QTest::newRow("C++ exceptions in Objective-C++ source, disabled") << "exceptions-objcpp-cpp.qbs" << false << false; + } +} + +void TestBlackbox::enableRtti() +{ + QDir::setCurrent(testDataDir + QStringLiteral("/enableRtti")); + + QbsRunParameters params; + + params.arguments = QStringList() << "cpp.enableRtti:true"; + rmDirR(relativeBuildDir()); + QCOMPARE(runQbs(params), 0); + + if (HostOsInfo::isOsxHost()) { + params.arguments = QStringList() << "cpp.enableRtti:true" << "project.treatAsObjcpp:true"; + rmDirR(relativeBuildDir()); + QCOMPARE(runQbs(params), 0); + } + + params.expectFailure = true; + + params.arguments = QStringList() << "cpp.enableRtti:false"; + rmDirR(relativeBuildDir()); + QVERIFY(runQbs(params) != 0); + + if (HostOsInfo::isOsxHost()) { + params.arguments = QStringList() << "cpp.enableRtti:false" << "project.treatAsObjcpp:true"; + rmDirR(relativeBuildDir()); + QVERIFY(runQbs(params) != 0); + } +} + void TestBlackbox::frameworkStructure() { if (!HostOsInfo::isOsxHost()) @@ -2977,9 +3470,11 @@ void TestBlackbox::typescript() QDir::setCurrent(testDataDir + QLatin1String("/typescript")); status = runQbs(); - if (p.value("typescript.toolchainInstallPath").toString().isEmpty() - && status != 0 && m_qbsStderr.contains("toolchainInstallPath")) { - QSKIP("typescript.toolchainInstallPath not set and automatic detection failed"); + if (p.value("typescript.toolchainInstallPath").toString().isEmpty() && status != 0) { + if (m_qbsStderr.contains("typescript.toolchainInstallPath")) + QSKIP("typescript.toolchainInstallPath not set and automatic detection failed"); + if (m_qbsStderr.contains("nodejs.interpreterFilePath")) + QSKIP("nodejs.interpreterFilePath not set and automatic detection failed"); } QCOMPARE(status, 0); diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index 9ac814960..72dff6088 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -103,6 +103,8 @@ private slots: void assetCatalog_data(); void badInterpreter(); void buildDirectories(); + void bundleStructure(); + void bundleStructure_data(); void changedFiles_data(); void changedFiles(); void changeInDisabledProduct(); @@ -113,11 +115,17 @@ private slots: void concurrentExecutor(); void dependenciesProperty(); void dependencyProfileMismatch(); + void deploymentTarget(); + void deploymentTarget_data(); void dynamicMultiplexRule(); void dynamicRuleOutputs(); void embedInfoPlist(); + void enableExceptions(); + void enableExceptions_data(); + void enableRtti(); void erroneousFiles_data(); void erroneousFiles(); + void errorInfo(); void exportRule(); void fileDependencies(); void frameworkStructure(); @@ -156,6 +164,8 @@ private slots: void objcArc(); void outputArtifactAutoTagging(); void overrideProjectProperties(); + void probeProperties(); + void probeInExportedModule(); void probesInNestedModules(); void productDependenciesByType(); void productProperties(); @@ -169,6 +179,7 @@ private slots: void radAfterIncompleteBuild(); void recursiveRenaming(); void recursiveWildcards(); + void referenceErrorInExport(); void reproducibleBuild(); void reproducibleBuild_data(); void ruleConditions(); |